2 * Copyright (C) 2012, 2013 Apple Inc. All Rights Reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "UnlinkedCodeBlock.h"
30 #include "BytecodeGenerator.h"
31 #include "ClassInfo.h"
32 #include "CodeCache.h"
33 #include "Executable.h"
35 #include "JSCInlines.h"
37 #include "SourceProvider.h"
38 #include "Structure.h"
39 #include "SymbolTable.h"
40 #include "UnlinkedInstructionStream.h"
41 #include <wtf/DataLog.h>
45 const ClassInfo
UnlinkedFunctionExecutable::s_info
= { "UnlinkedFunctionExecutable", 0, 0, 0, CREATE_METHOD_TABLE(UnlinkedFunctionExecutable
) };
46 const ClassInfo
UnlinkedCodeBlock::s_info
= { "UnlinkedCodeBlock", 0, 0, 0, CREATE_METHOD_TABLE(UnlinkedCodeBlock
) };
47 const ClassInfo
UnlinkedGlobalCodeBlock::s_info
= { "UnlinkedGlobalCodeBlock", &Base::s_info
, 0, 0, CREATE_METHOD_TABLE(UnlinkedGlobalCodeBlock
) };
48 const ClassInfo
UnlinkedProgramCodeBlock::s_info
= { "UnlinkedProgramCodeBlock", &Base::s_info
, 0, 0, CREATE_METHOD_TABLE(UnlinkedProgramCodeBlock
) };
49 const ClassInfo
UnlinkedEvalCodeBlock::s_info
= { "UnlinkedEvalCodeBlock", &Base::s_info
, 0, 0, CREATE_METHOD_TABLE(UnlinkedEvalCodeBlock
) };
50 const ClassInfo
UnlinkedFunctionCodeBlock::s_info
= { "UnlinkedFunctionCodeBlock", &Base::s_info
, 0, 0, CREATE_METHOD_TABLE(UnlinkedFunctionCodeBlock
) };
52 static UnlinkedFunctionCodeBlock
* generateFunctionCodeBlock(VM
& vm
, UnlinkedFunctionExecutable
* executable
, const SourceCode
& source
, CodeSpecializationKind kind
, DebuggerMode debuggerMode
, ProfilerMode profilerMode
, UnlinkedFunctionKind functionKind
, bool bodyIncludesBraces
, ParserError
& error
)
54 RefPtr
<FunctionBodyNode
> body
= parse
<FunctionBodyNode
>(&vm
, source
, executable
->parameters(), executable
->name(), executable
->toStrictness(), JSParseFunctionCode
, error
, 0, bodyIncludesBraces
);
57 ASSERT(error
.m_type
!= ParserError::ErrorNone
);
61 if (executable
->forceUsesArguments())
62 body
->setUsesArguments();
63 body
->finishParsing(executable
->parameters(), executable
->name(), executable
->functionMode());
64 executable
->recordParse(body
->features(), body
->hasCapturedVariables());
66 UnlinkedFunctionCodeBlock
* result
= UnlinkedFunctionCodeBlock::create(&vm
, FunctionCode
, ExecutableInfo(body
->needsActivation(), body
->usesEval(), body
->isStrictMode(), kind
== CodeForConstruct
, functionKind
== UnlinkedBuiltinFunction
));
67 OwnPtr
<BytecodeGenerator
> generator(adoptPtr(new BytecodeGenerator(vm
, body
.get(), result
, debuggerMode
, profilerMode
)));
68 error
= generator
->generate();
70 if (error
.m_type
!= ParserError::ErrorNone
)
75 unsigned UnlinkedCodeBlock::addOrFindConstant(JSValue v
)
77 unsigned numberOfConstants
= numberOfConstantRegisters();
78 for (unsigned i
= 0; i
< numberOfConstants
; ++i
) {
79 if (getConstant(FirstConstantRegisterIndex
+ i
) == v
)
82 return addConstant(v
);
85 UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM
* vm
, Structure
* structure
, const SourceCode
& source
, FunctionBodyNode
* node
, UnlinkedFunctionKind kind
)
86 : Base(*vm
, structure
)
87 , m_numCapturedVariables(node
->capturedVariableCount())
88 , m_forceUsesArguments(node
->usesArguments())
89 , m_isInStrictContext(node
->isStrictMode())
90 , m_hasCapturedVariables(node
->hasCapturedVariables())
91 , m_isBuiltinFunction(kind
== UnlinkedBuiltinFunction
)
92 , m_name(node
->ident())
93 , m_inferredName(node
->inferredName())
94 , m_parameters(node
->parameters())
95 , m_firstLineOffset(node
->firstLine() - source
.firstLine())
96 , m_lineCount(node
->lastLine() - node
->firstLine())
97 , m_unlinkedFunctionNameStart(node
->functionNameStart() - source
.startOffset())
98 , m_unlinkedBodyStartColumn(node
->startColumn())
99 , m_unlinkedBodyEndColumn(m_lineCount
? node
->endColumn() : node
->endColumn() - node
->startColumn())
100 , m_startOffset(node
->source().startOffset() - source
.startOffset())
101 , m_sourceLength(node
->source().length())
102 , m_features(node
->features())
103 , m_functionMode(node
->functionMode())
107 size_t UnlinkedFunctionExecutable::parameterCount() const
109 return m_parameters
->size();
112 void UnlinkedFunctionExecutable::visitChildren(JSCell
* cell
, SlotVisitor
& visitor
)
114 UnlinkedFunctionExecutable
* thisObject
= jsCast
<UnlinkedFunctionExecutable
*>(cell
);
115 ASSERT_GC_OBJECT_INHERITS(thisObject
, info());
116 COMPILE_ASSERT(StructureFlags
& OverridesVisitChildren
, OverridesVisitChildrenWithoutSettingFlag
);
117 ASSERT(thisObject
->structure()->typeInfo().overridesVisitChildren());
118 Base::visitChildren(thisObject
, visitor
);
119 visitor
.append(&thisObject
->m_codeBlockForCall
);
120 visitor
.append(&thisObject
->m_codeBlockForConstruct
);
121 visitor
.append(&thisObject
->m_nameValue
);
122 visitor
.append(&thisObject
->m_symbolTableForCall
);
123 visitor
.append(&thisObject
->m_symbolTableForConstruct
);
126 FunctionExecutable
* UnlinkedFunctionExecutable::link(VM
& vm
, const SourceCode
& source
, size_t lineOffset
)
128 unsigned firstLine
= lineOffset
+ m_firstLineOffset
;
129 bool startColumnIsOnFirstSourceLine
= !m_firstLineOffset
;
130 unsigned startColumn
= m_unlinkedBodyStartColumn
+ (startColumnIsOnFirstSourceLine
? source
.startColumn() : 1);
131 bool endColumnIsOnStartLine
= !m_lineCount
;
132 unsigned endColumn
= m_unlinkedBodyEndColumn
+ (endColumnIsOnStartLine
? startColumn
: 1);
133 SourceCode
code(source
.provider(), m_startOffset
, m_startOffset
+ m_sourceLength
, firstLine
, startColumn
);
134 return FunctionExecutable::create(vm
, code
, this, firstLine
, firstLine
+ m_lineCount
, startColumn
, endColumn
);
137 UnlinkedFunctionExecutable
* UnlinkedFunctionExecutable::fromGlobalCode(const Identifier
& name
, ExecState
* exec
, Debugger
*, const SourceCode
& source
, JSObject
** exception
)
141 CodeCache
* codeCache
= vm
.codeCache();
142 UnlinkedFunctionExecutable
* executable
= codeCache
->getFunctionExecutableFromGlobalCode(vm
, name
, source
, error
);
144 if (exec
->lexicalGlobalObject()->hasDebugger())
145 exec
->lexicalGlobalObject()->debugger()->sourceParsed(exec
, source
.provider(), error
.m_line
, error
.m_message
);
147 if (error
.m_type
!= ParserError::ErrorNone
) {
148 *exception
= error
.toErrorObject(exec
->lexicalGlobalObject(), source
);
155 UnlinkedFunctionCodeBlock
* UnlinkedFunctionExecutable::codeBlockFor(VM
& vm
, const SourceCode
& source
, CodeSpecializationKind specializationKind
, DebuggerMode debuggerMode
, ProfilerMode profilerMode
, bool bodyIncludesBraces
, ParserError
& error
)
157 switch (specializationKind
) {
159 if (UnlinkedFunctionCodeBlock
* codeBlock
= m_codeBlockForCall
.get())
162 case CodeForConstruct
:
163 if (UnlinkedFunctionCodeBlock
* codeBlock
= m_codeBlockForConstruct
.get())
168 UnlinkedFunctionCodeBlock
* result
= generateFunctionCodeBlock(vm
, this, source
, specializationKind
, debuggerMode
, profilerMode
, isBuiltinFunction() ? UnlinkedBuiltinFunction
: UnlinkedNormalFunction
, bodyIncludesBraces
, error
);
170 if (error
.m_type
!= ParserError::ErrorNone
)
173 switch (specializationKind
) {
175 m_codeBlockForCall
.set(vm
, this, result
);
176 m_symbolTableForCall
.set(vm
, this, result
->symbolTable());
178 case CodeForConstruct
:
179 m_codeBlockForConstruct
.set(vm
, this, result
);
180 m_symbolTableForConstruct
.set(vm
, this, result
->symbolTable());
186 String
UnlinkedFunctionExecutable::paramString() const
188 FunctionParameters
& parameters
= *m_parameters
;
189 StringBuilder builder
;
190 for (size_t pos
= 0; pos
< parameters
.size(); ++pos
) {
191 if (!builder
.isEmpty())
192 builder
.appendLiteral(", ");
193 parameters
.at(pos
)->toString(builder
);
195 return builder
.toString();
198 UnlinkedCodeBlock::UnlinkedCodeBlock(VM
* vm
, Structure
* structure
, CodeType codeType
, const ExecutableInfo
& info
)
199 : Base(*vm
, structure
)
201 , m_numCalleeRegisters(0)
204 , m_argumentsRegister(VirtualRegister())
205 , m_globalObjectRegister(VirtualRegister())
206 , m_needsFullScopeChain(info
.m_needsActivation
)
207 , m_usesEval(info
.m_usesEval
)
208 , m_isNumericCompareFunction(false)
209 , m_isStrictMode(info
.m_isStrictMode
)
210 , m_isConstructor(info
.m_isConstructor
)
211 , m_hasCapturedVariables(false)
212 , m_isBuiltinFunction(info
.m_isBuiltinFunction
)
215 , m_endColumn(UINT_MAX
)
217 , m_codeType(codeType
)
218 , m_arrayProfileCount(0)
219 , m_arrayAllocationProfileCount(0)
220 , m_objectAllocationProfileCount(0)
221 , m_valueProfileCount(0)
222 , m_llintCallLinkInfoCount(0)
223 #if ENABLE(BYTECODE_COMMENTS)
224 , m_bytecodeCommentIterator(0)
230 void UnlinkedCodeBlock::visitChildren(JSCell
* cell
, SlotVisitor
& visitor
)
232 UnlinkedCodeBlock
* thisObject
= jsCast
<UnlinkedCodeBlock
*>(cell
);
233 ASSERT_GC_OBJECT_INHERITS(thisObject
, info());
234 COMPILE_ASSERT(StructureFlags
& OverridesVisitChildren
, OverridesVisitChildrenWithoutSettingFlag
);
235 ASSERT(thisObject
->structure()->typeInfo().overridesVisitChildren());
236 Base::visitChildren(thisObject
, visitor
);
237 visitor
.append(&thisObject
->m_symbolTable
);
238 for (FunctionExpressionVector::iterator ptr
= thisObject
->m_functionDecls
.begin(), end
= thisObject
->m_functionDecls
.end(); ptr
!= end
; ++ptr
)
240 for (FunctionExpressionVector::iterator ptr
= thisObject
->m_functionExprs
.begin(), end
= thisObject
->m_functionExprs
.end(); ptr
!= end
; ++ptr
)
242 visitor
.appendValues(thisObject
->m_constantRegisters
.data(), thisObject
->m_constantRegisters
.size());
243 if (thisObject
->m_rareData
) {
244 for (size_t i
= 0, end
= thisObject
->m_rareData
->m_regexps
.size(); i
!= end
; i
++)
245 visitor
.append(&thisObject
->m_rareData
->m_regexps
[i
]);
249 int UnlinkedCodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset
)
251 ASSERT(bytecodeOffset
< instructions().count());
257 expressionRangeForBytecodeOffset(bytecodeOffset
, divot
, startOffset
, endOffset
, line
, column
);
261 inline void UnlinkedCodeBlock::getLineAndColumn(ExpressionRangeInfo
& info
,
262 unsigned& line
, unsigned& column
)
265 case ExpressionRangeInfo::FatLineMode
:
266 info
.decodeFatLineMode(line
, column
);
268 case ExpressionRangeInfo::FatColumnMode
:
269 info
.decodeFatColumnMode(line
, column
);
271 case ExpressionRangeInfo::FatLineAndColumnMode
: {
272 unsigned fatIndex
= info
.position
;
273 ExpressionRangeInfo::FatPosition
& fatPos
= m_rareData
->m_expressionInfoFatPositions
[fatIndex
];
275 column
= fatPos
.column
;
282 static void dumpLineColumnEntry(size_t index
, const UnlinkedInstructionStream
& instructionStream
, unsigned instructionOffset
, unsigned line
, unsigned column
)
284 const auto& instructions
= instructionStream
.unpackForDebugging();
285 OpcodeID opcode
= instructions
[instructionOffset
].u
.opcode
;
286 const char* event
= "";
287 if (opcode
== op_debug
) {
288 switch (instructions
[instructionOffset
+ 1].u
.operand
) {
289 case WillExecuteProgram
: event
= " WillExecuteProgram"; break;
290 case DidExecuteProgram
: event
= " DidExecuteProgram"; break;
291 case DidEnterCallFrame
: event
= " DidEnterCallFrame"; break;
292 case DidReachBreakpoint
: event
= " DidReachBreakpoint"; break;
293 case WillLeaveCallFrame
: event
= " WillLeaveCallFrame"; break;
294 case WillExecuteStatement
: event
= " WillExecuteStatement"; break;
297 dataLogF(" [%zu] pc %u @ line %u col %u : %s%s\n", index
, instructionOffset
, line
, column
, opcodeNames
[opcode
], event
);
300 void UnlinkedCodeBlock::dumpExpressionRangeInfo()
302 Vector
<ExpressionRangeInfo
>& expressionInfo
= m_expressionInfo
;
304 size_t size
= m_expressionInfo
.size();
305 dataLogF("UnlinkedCodeBlock %p expressionRangeInfo[%zu] {\n", this, size
);
306 for (size_t i
= 0; i
< size
; i
++) {
307 ExpressionRangeInfo
& info
= expressionInfo
[i
];
310 getLineAndColumn(info
, line
, column
);
311 dumpLineColumnEntry(i
, instructions(), info
.instructionOffset
, line
, column
);
317 void UnlinkedCodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset
,
318 int& divot
, int& startOffset
, int& endOffset
, unsigned& line
, unsigned& column
)
320 ASSERT(bytecodeOffset
< instructions().count());
322 if (!m_expressionInfo
.size()) {
331 Vector
<ExpressionRangeInfo
>& expressionInfo
= m_expressionInfo
;
334 int high
= expressionInfo
.size();
336 int mid
= low
+ (high
- low
) / 2;
337 if (expressionInfo
[mid
].instructionOffset
<= bytecodeOffset
)
346 ExpressionRangeInfo
& info
= expressionInfo
[low
- 1];
347 startOffset
= info
.startOffset
;
348 endOffset
= info
.endOffset
;
349 divot
= info
.divotPoint
;
350 getLineAndColumn(info
, line
, column
);
353 void UnlinkedCodeBlock::addExpressionInfo(unsigned instructionOffset
,
354 int divot
, int startOffset
, int endOffset
, unsigned line
, unsigned column
)
356 if (divot
> ExpressionRangeInfo::MaxDivot
) {
357 // Overflow has occurred, we can only give line number info for errors for this region
361 } else if (startOffset
> ExpressionRangeInfo::MaxOffset
) {
362 // If the start offset is out of bounds we clear both offsets
363 // so we only get the divot marker. Error message will have to be reduced
364 // to line and charPosition number.
367 } else if (endOffset
> ExpressionRangeInfo::MaxOffset
) {
368 // The end offset is only used for additional context, and is much more likely
369 // to overflow (eg. function call arguments) so we are willing to drop it without
370 // dropping the rest of the range.
374 unsigned positionMode
=
375 (line
<= ExpressionRangeInfo::MaxFatLineModeLine
&& column
<= ExpressionRangeInfo::MaxFatLineModeColumn
)
376 ? ExpressionRangeInfo::FatLineMode
377 : (line
<= ExpressionRangeInfo::MaxFatColumnModeLine
&& column
<= ExpressionRangeInfo::MaxFatColumnModeColumn
)
378 ? ExpressionRangeInfo::FatColumnMode
379 : ExpressionRangeInfo::FatLineAndColumnMode
;
381 ExpressionRangeInfo info
;
382 info
.instructionOffset
= instructionOffset
;
383 info
.divotPoint
= divot
;
384 info
.startOffset
= startOffset
;
385 info
.endOffset
= endOffset
;
387 info
.mode
= positionMode
;
388 switch (positionMode
) {
389 case ExpressionRangeInfo::FatLineMode
:
390 info
.encodeFatLineMode(line
, column
);
392 case ExpressionRangeInfo::FatColumnMode
:
393 info
.encodeFatColumnMode(line
, column
);
395 case ExpressionRangeInfo::FatLineAndColumnMode
: {
396 createRareDataIfNecessary();
397 unsigned fatIndex
= m_rareData
->m_expressionInfoFatPositions
.size();
398 ExpressionRangeInfo::FatPosition fatPos
= { line
, column
};
399 m_rareData
->m_expressionInfoFatPositions
.append(fatPos
);
400 info
.position
= fatIndex
;
404 m_expressionInfo
.append(info
);
407 void UnlinkedProgramCodeBlock::visitChildren(JSCell
* cell
, SlotVisitor
& visitor
)
409 UnlinkedProgramCodeBlock
* thisObject
= jsCast
<UnlinkedProgramCodeBlock
*>(cell
);
410 ASSERT_GC_OBJECT_INHERITS(thisObject
, info());
411 COMPILE_ASSERT(StructureFlags
& OverridesVisitChildren
, OverridesVisitChildrenWithoutSettingFlag
);
412 ASSERT(thisObject
->structure()->typeInfo().overridesVisitChildren());
413 Base::visitChildren(thisObject
, visitor
);
414 for (size_t i
= 0, end
= thisObject
->m_functionDeclarations
.size(); i
!= end
; i
++)
415 visitor
.append(&thisObject
->m_functionDeclarations
[i
].second
);
418 UnlinkedCodeBlock::~UnlinkedCodeBlock()
422 void UnlinkedProgramCodeBlock::destroy(JSCell
* cell
)
424 jsCast
<UnlinkedProgramCodeBlock
*>(cell
)->~UnlinkedProgramCodeBlock();
427 void UnlinkedEvalCodeBlock::destroy(JSCell
* cell
)
429 jsCast
<UnlinkedEvalCodeBlock
*>(cell
)->~UnlinkedEvalCodeBlock();
432 void UnlinkedFunctionCodeBlock::destroy(JSCell
* cell
)
434 jsCast
<UnlinkedFunctionCodeBlock
*>(cell
)->~UnlinkedFunctionCodeBlock();
437 void UnlinkedFunctionExecutable::destroy(JSCell
* cell
)
439 jsCast
<UnlinkedFunctionExecutable
*>(cell
)->~UnlinkedFunctionExecutable();
442 void UnlinkedCodeBlock::setInstructions(std::unique_ptr
<UnlinkedInstructionStream
> instructions
)
444 m_unlinkedInstructions
= WTF::move(instructions
);
447 const UnlinkedInstructionStream
& UnlinkedCodeBlock::instructions() const
449 ASSERT(m_unlinkedInstructions
.get());
450 return *m_unlinkedInstructions
;