2 * Copyright (C) 2012, 2013, 2015 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"
34 #include "FunctionOverrides.h"
36 #include "JSCInlines.h"
38 #include "SourceProvider.h"
39 #include "Structure.h"
40 #include "SymbolTable.h"
41 #include "UnlinkedInstructionStream.h"
42 #include <wtf/DataLog.h>
46 static_assert(sizeof(UnlinkedFunctionExecutable
) <= 128, "UnlinkedFunctionExecutable should fit in a 128-byte cell.");
48 const ClassInfo
UnlinkedFunctionExecutable::s_info
= { "UnlinkedFunctionExecutable", 0, 0, CREATE_METHOD_TABLE(UnlinkedFunctionExecutable
) };
49 const ClassInfo
UnlinkedCodeBlock::s_info
= { "UnlinkedCodeBlock", 0, 0, CREATE_METHOD_TABLE(UnlinkedCodeBlock
) };
50 const ClassInfo
UnlinkedGlobalCodeBlock::s_info
= { "UnlinkedGlobalCodeBlock", &Base::s_info
, 0, CREATE_METHOD_TABLE(UnlinkedGlobalCodeBlock
) };
51 const ClassInfo
UnlinkedProgramCodeBlock::s_info
= { "UnlinkedProgramCodeBlock", &Base::s_info
, 0, CREATE_METHOD_TABLE(UnlinkedProgramCodeBlock
) };
52 const ClassInfo
UnlinkedEvalCodeBlock::s_info
= { "UnlinkedEvalCodeBlock", &Base::s_info
, 0, CREATE_METHOD_TABLE(UnlinkedEvalCodeBlock
) };
53 const ClassInfo
UnlinkedFunctionCodeBlock::s_info
= { "UnlinkedFunctionCodeBlock", &Base::s_info
, 0, CREATE_METHOD_TABLE(UnlinkedFunctionCodeBlock
) };
55 static UnlinkedFunctionCodeBlock
* generateFunctionCodeBlock(
56 VM
& vm
, UnlinkedFunctionExecutable
* executable
, const SourceCode
& source
,
57 CodeSpecializationKind kind
, DebuggerMode debuggerMode
, ProfilerMode profilerMode
,
58 UnlinkedFunctionKind functionKind
, ParserError
& error
)
60 JSParserBuiltinMode builtinMode
= executable
->isBuiltinFunction() ? JSParserBuiltinMode::Builtin
: JSParserBuiltinMode::NotBuiltin
;
61 JSParserStrictMode strictMode
= executable
->isInStrictContext() ? JSParserStrictMode::Strict
: JSParserStrictMode::NotStrict
;
62 std::unique_ptr
<FunctionNode
> function
= parse
<FunctionNode
>(
63 &vm
, source
, executable
->parameters(), executable
->name(), builtinMode
,
64 strictMode
, JSParserCodeType::Function
, error
, 0);
67 ASSERT(error
.isValid());
71 function
->finishParsing(executable
->parameters(), executable
->name(), executable
->functionMode());
72 executable
->recordParse(function
->features(), function
->hasCapturedVariables());
74 UnlinkedFunctionCodeBlock
* result
= UnlinkedFunctionCodeBlock::create(&vm
, FunctionCode
,
75 ExecutableInfo(function
->needsActivation(), function
->usesEval(), function
->isStrictMode(), kind
== CodeForConstruct
, functionKind
== UnlinkedBuiltinFunction
, executable
->constructorKind()));
76 auto generator(std::make_unique
<BytecodeGenerator
>(vm
, function
.get(), result
, debuggerMode
, profilerMode
));
77 error
= generator
->generate();
83 UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM
* vm
, Structure
* structure
, const SourceCode
& source
, RefPtr
<SourceProvider
>&& sourceOverride
, FunctionBodyNode
* node
, UnlinkedFunctionKind kind
)
84 : Base(*vm
, structure
)
85 , m_name(node
->ident())
86 , m_inferredName(node
->inferredName())
87 , m_parameters(node
->parameters())
88 , m_sourceOverride(WTF::move(sourceOverride
))
89 , m_firstLineOffset(node
->firstLine() - source
.firstLine())
90 , m_lineCount(node
->lastLine() - node
->firstLine())
91 , m_unlinkedFunctionNameStart(node
->functionNameStart() - source
.startOffset())
92 , m_unlinkedBodyStartColumn(node
->startColumn())
93 , m_unlinkedBodyEndColumn(m_lineCount
? node
->endColumn() : node
->endColumn() - node
->startColumn())
94 , m_startOffset(node
->source().startOffset() - source
.startOffset())
95 , m_sourceLength(node
->source().length())
96 , m_parametersStartOffset(node
->parametersStart())
97 , m_typeProfilingStartOffset(node
->functionKeywordStart())
98 , m_typeProfilingEndOffset(node
->startStartOffset() + node
->source().length() - 1)
100 , m_isInStrictContext(node
->isInStrictContext())
101 , m_hasCapturedVariables(false)
102 , m_isBuiltinFunction(kind
== UnlinkedBuiltinFunction
)
103 , m_constructorKind(static_cast<unsigned>(node
->constructorKind()))
104 , m_functionMode(node
->functionMode())
106 ASSERT(m_constructorKind
== static_cast<unsigned>(node
->constructorKind()));
109 size_t UnlinkedFunctionExecutable::parameterCount() const
111 return m_parameters
->size();
114 void UnlinkedFunctionExecutable::visitChildren(JSCell
* cell
, SlotVisitor
& visitor
)
116 UnlinkedFunctionExecutable
* thisObject
= jsCast
<UnlinkedFunctionExecutable
*>(cell
);
117 ASSERT_GC_OBJECT_INHERITS(thisObject
, info());
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
& ownerSource
, int overrideLineNumber
)
128 SourceCode source
= m_sourceOverride
? SourceCode(m_sourceOverride
) : ownerSource
;
129 unsigned firstLine
= source
.firstLine() + m_firstLineOffset
;
130 unsigned startOffset
= source
.startOffset() + m_startOffset
;
131 unsigned lineCount
= m_lineCount
;
133 // Adjust to one-based indexing.
134 bool startColumnIsOnFirstSourceLine
= !m_firstLineOffset
;
135 unsigned startColumn
= m_unlinkedBodyStartColumn
+ (startColumnIsOnFirstSourceLine
? source
.startColumn() : 1);
136 bool endColumnIsOnStartLine
= !lineCount
;
137 unsigned endColumn
= m_unlinkedBodyEndColumn
+ (endColumnIsOnStartLine
? startColumn
: 1);
139 SourceCode
code(source
.provider(), startOffset
, startOffset
+ m_sourceLength
, firstLine
, startColumn
);
140 FunctionOverrides::OverrideInfo overrideInfo
;
141 bool hasFunctionOverride
= false;
143 if (UNLIKELY(Options::functionOverrides())) {
144 hasFunctionOverride
= FunctionOverrides::initializeOverrideFor(code
, overrideInfo
);
145 if (hasFunctionOverride
) {
146 firstLine
= overrideInfo
.firstLine
;
147 lineCount
= overrideInfo
.lineCount
;
148 startColumn
= overrideInfo
.startColumn
;
149 endColumn
= overrideInfo
.endColumn
;
150 code
= overrideInfo
.sourceCode
;
154 FunctionExecutable
* result
= FunctionExecutable::create(vm
, code
, this, firstLine
, firstLine
+ lineCount
, startColumn
, endColumn
);
155 if (overrideLineNumber
!= -1)
156 result
->setOverrideLineNumber(overrideLineNumber
);
158 if (UNLIKELY(hasFunctionOverride
)) {
159 result
->overrideParameterAndTypeProfilingStartEndOffsets(
160 overrideInfo
.parametersStartOffset
,
161 overrideInfo
.typeProfilingStartOffset
,
162 overrideInfo
.typeProfilingEndOffset
);
168 UnlinkedFunctionExecutable
* UnlinkedFunctionExecutable::fromGlobalCode(
169 const Identifier
& name
, ExecState
& exec
, const SourceCode
& source
,
170 JSObject
*& exception
, int overrideLineNumber
)
174 CodeCache
* codeCache
= vm
.codeCache();
175 UnlinkedFunctionExecutable
* executable
= codeCache
->getFunctionExecutableFromGlobalCode(vm
, name
, source
, error
);
177 auto& globalObject
= *exec
.lexicalGlobalObject();
178 if (globalObject
.hasDebugger())
179 globalObject
.debugger()->sourceParsed(&exec
, source
.provider(), error
.line(), error
.message());
181 if (error
.isValid()) {
182 exception
= error
.toErrorObject(&globalObject
, source
, overrideLineNumber
);
189 UnlinkedFunctionCodeBlock
* UnlinkedFunctionExecutable::codeBlockFor(
190 VM
& vm
, const SourceCode
& source
, CodeSpecializationKind specializationKind
,
191 DebuggerMode debuggerMode
, ProfilerMode profilerMode
, ParserError
& error
)
193 switch (specializationKind
) {
195 if (UnlinkedFunctionCodeBlock
* codeBlock
= m_codeBlockForCall
.get())
198 case CodeForConstruct
:
199 if (UnlinkedFunctionCodeBlock
* codeBlock
= m_codeBlockForConstruct
.get())
204 UnlinkedFunctionCodeBlock
* result
= generateFunctionCodeBlock(
205 vm
, this, source
, specializationKind
, debuggerMode
, profilerMode
,
206 isBuiltinFunction() ? UnlinkedBuiltinFunction
: UnlinkedNormalFunction
,
212 switch (specializationKind
) {
214 m_codeBlockForCall
.set(vm
, this, result
);
215 m_symbolTableForCall
.set(vm
, this, result
->symbolTable());
217 case CodeForConstruct
:
218 m_codeBlockForConstruct
.set(vm
, this, result
);
219 m_symbolTableForConstruct
.set(vm
, this, result
->symbolTable());
225 UnlinkedCodeBlock::UnlinkedCodeBlock(VM
* vm
, Structure
* structure
, CodeType codeType
, const ExecutableInfo
& info
)
226 : Base(*vm
, structure
)
228 , m_numCalleeRegisters(0)
231 , m_globalObjectRegister(VirtualRegister())
232 , m_needsFullScopeChain(info
.needsActivation())
233 , m_usesEval(info
.usesEval())
234 , m_isStrictMode(info
.isStrictMode())
235 , m_isConstructor(info
.isConstructor())
236 , m_hasCapturedVariables(false)
237 , m_isBuiltinFunction(info
.isBuiltinFunction())
238 , m_constructorKind(static_cast<unsigned>(info
.constructorKind()))
241 , m_endColumn(UINT_MAX
)
243 , m_codeType(codeType
)
244 , m_arrayProfileCount(0)
245 , m_arrayAllocationProfileCount(0)
246 , m_objectAllocationProfileCount(0)
247 , m_valueProfileCount(0)
248 , m_llintCallLinkInfoCount(0)
249 #if ENABLE(BYTECODE_COMMENTS)
250 , m_bytecodeCommentIterator(0)
253 for (auto& constantRegisterIndex
: m_linkTimeConstants
)
254 constantRegisterIndex
= 0;
255 ASSERT(m_constructorKind
== static_cast<unsigned>(info
.constructorKind()));
258 void UnlinkedCodeBlock::visitChildren(JSCell
* cell
, SlotVisitor
& visitor
)
260 UnlinkedCodeBlock
* thisObject
= jsCast
<UnlinkedCodeBlock
*>(cell
);
261 ASSERT_GC_OBJECT_INHERITS(thisObject
, info());
262 Base::visitChildren(thisObject
, visitor
);
263 visitor
.append(&thisObject
->m_symbolTable
);
264 for (FunctionExpressionVector::iterator ptr
= thisObject
->m_functionDecls
.begin(), end
= thisObject
->m_functionDecls
.end(); ptr
!= end
; ++ptr
)
266 for (FunctionExpressionVector::iterator ptr
= thisObject
->m_functionExprs
.begin(), end
= thisObject
->m_functionExprs
.end(); ptr
!= end
; ++ptr
)
268 visitor
.appendValues(thisObject
->m_constantRegisters
.data(), thisObject
->m_constantRegisters
.size());
269 if (thisObject
->m_rareData
) {
270 for (size_t i
= 0, end
= thisObject
->m_rareData
->m_regexps
.size(); i
!= end
; i
++)
271 visitor
.append(&thisObject
->m_rareData
->m_regexps
[i
]);
275 int UnlinkedCodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset
)
277 ASSERT(bytecodeOffset
< instructions().count());
283 expressionRangeForBytecodeOffset(bytecodeOffset
, divot
, startOffset
, endOffset
, line
, column
);
287 inline void UnlinkedCodeBlock::getLineAndColumn(ExpressionRangeInfo
& info
,
288 unsigned& line
, unsigned& column
)
291 case ExpressionRangeInfo::FatLineMode
:
292 info
.decodeFatLineMode(line
, column
);
294 case ExpressionRangeInfo::FatColumnMode
:
295 info
.decodeFatColumnMode(line
, column
);
297 case ExpressionRangeInfo::FatLineAndColumnMode
: {
298 unsigned fatIndex
= info
.position
;
299 ExpressionRangeInfo::FatPosition
& fatPos
= m_rareData
->m_expressionInfoFatPositions
[fatIndex
];
301 column
= fatPos
.column
;
308 static void dumpLineColumnEntry(size_t index
, const UnlinkedInstructionStream
& instructionStream
, unsigned instructionOffset
, unsigned line
, unsigned column
)
310 const auto& instructions
= instructionStream
.unpackForDebugging();
311 OpcodeID opcode
= instructions
[instructionOffset
].u
.opcode
;
312 const char* event
= "";
313 if (opcode
== op_debug
) {
314 switch (instructions
[instructionOffset
+ 1].u
.operand
) {
315 case WillExecuteProgram
: event
= " WillExecuteProgram"; break;
316 case DidExecuteProgram
: event
= " DidExecuteProgram"; break;
317 case DidEnterCallFrame
: event
= " DidEnterCallFrame"; break;
318 case DidReachBreakpoint
: event
= " DidReachBreakpoint"; break;
319 case WillLeaveCallFrame
: event
= " WillLeaveCallFrame"; break;
320 case WillExecuteStatement
: event
= " WillExecuteStatement"; break;
323 dataLogF(" [%zu] pc %u @ line %u col %u : %s%s\n", index
, instructionOffset
, line
, column
, opcodeNames
[opcode
], event
);
326 void UnlinkedCodeBlock::dumpExpressionRangeInfo()
328 Vector
<ExpressionRangeInfo
>& expressionInfo
= m_expressionInfo
;
330 size_t size
= m_expressionInfo
.size();
331 dataLogF("UnlinkedCodeBlock %p expressionRangeInfo[%zu] {\n", this, size
);
332 for (size_t i
= 0; i
< size
; i
++) {
333 ExpressionRangeInfo
& info
= expressionInfo
[i
];
336 getLineAndColumn(info
, line
, column
);
337 dumpLineColumnEntry(i
, instructions(), info
.instructionOffset
, line
, column
);
343 void UnlinkedCodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset
,
344 int& divot
, int& startOffset
, int& endOffset
, unsigned& line
, unsigned& column
)
346 ASSERT(bytecodeOffset
< instructions().count());
348 if (!m_expressionInfo
.size()) {
357 Vector
<ExpressionRangeInfo
>& expressionInfo
= m_expressionInfo
;
360 int high
= expressionInfo
.size();
362 int mid
= low
+ (high
- low
) / 2;
363 if (expressionInfo
[mid
].instructionOffset
<= bytecodeOffset
)
372 ExpressionRangeInfo
& info
= expressionInfo
[low
- 1];
373 startOffset
= info
.startOffset
;
374 endOffset
= info
.endOffset
;
375 divot
= info
.divotPoint
;
376 getLineAndColumn(info
, line
, column
);
379 void UnlinkedCodeBlock::addExpressionInfo(unsigned instructionOffset
,
380 int divot
, int startOffset
, int endOffset
, unsigned line
, unsigned column
)
382 if (divot
> ExpressionRangeInfo::MaxDivot
) {
383 // Overflow has occurred, we can only give line number info for errors for this region
387 } else if (startOffset
> ExpressionRangeInfo::MaxOffset
) {
388 // If the start offset is out of bounds we clear both offsets
389 // so we only get the divot marker. Error message will have to be reduced
390 // to line and charPosition number.
393 } else if (endOffset
> ExpressionRangeInfo::MaxOffset
) {
394 // The end offset is only used for additional context, and is much more likely
395 // to overflow (eg. function call arguments) so we are willing to drop it without
396 // dropping the rest of the range.
400 unsigned positionMode
=
401 (line
<= ExpressionRangeInfo::MaxFatLineModeLine
&& column
<= ExpressionRangeInfo::MaxFatLineModeColumn
)
402 ? ExpressionRangeInfo::FatLineMode
403 : (line
<= ExpressionRangeInfo::MaxFatColumnModeLine
&& column
<= ExpressionRangeInfo::MaxFatColumnModeColumn
)
404 ? ExpressionRangeInfo::FatColumnMode
405 : ExpressionRangeInfo::FatLineAndColumnMode
;
407 ExpressionRangeInfo info
;
408 info
.instructionOffset
= instructionOffset
;
409 info
.divotPoint
= divot
;
410 info
.startOffset
= startOffset
;
411 info
.endOffset
= endOffset
;
413 info
.mode
= positionMode
;
414 switch (positionMode
) {
415 case ExpressionRangeInfo::FatLineMode
:
416 info
.encodeFatLineMode(line
, column
);
418 case ExpressionRangeInfo::FatColumnMode
:
419 info
.encodeFatColumnMode(line
, column
);
421 case ExpressionRangeInfo::FatLineAndColumnMode
: {
422 createRareDataIfNecessary();
423 unsigned fatIndex
= m_rareData
->m_expressionInfoFatPositions
.size();
424 ExpressionRangeInfo::FatPosition fatPos
= { line
, column
};
425 m_rareData
->m_expressionInfoFatPositions
.append(fatPos
);
426 info
.position
= fatIndex
;
430 m_expressionInfo
.append(info
);
433 bool UnlinkedCodeBlock::typeProfilerExpressionInfoForBytecodeOffset(unsigned bytecodeOffset
, unsigned& startDivot
, unsigned& endDivot
)
435 static const bool verbose
= false;
436 auto iter
= m_typeProfilerInfoMap
.find(bytecodeOffset
);
437 if (iter
== m_typeProfilerInfoMap
.end()) {
439 dataLogF("Don't have assignment info for offset:%u\n", bytecodeOffset
);
440 startDivot
= UINT_MAX
;
445 TypeProfilerExpressionRange
& range
= iter
->value
;
446 startDivot
= range
.m_startDivot
;
447 endDivot
= range
.m_endDivot
;
451 void UnlinkedCodeBlock::addTypeProfilerExpressionInfo(unsigned instructionOffset
, unsigned startDivot
, unsigned endDivot
)
453 TypeProfilerExpressionRange range
;
454 range
.m_startDivot
= startDivot
;
455 range
.m_endDivot
= endDivot
;
456 m_typeProfilerInfoMap
.set(instructionOffset
, range
);
459 void UnlinkedProgramCodeBlock::visitChildren(JSCell
* cell
, SlotVisitor
& visitor
)
461 UnlinkedProgramCodeBlock
* thisObject
= jsCast
<UnlinkedProgramCodeBlock
*>(cell
);
462 ASSERT_GC_OBJECT_INHERITS(thisObject
, info());
463 Base::visitChildren(thisObject
, visitor
);
466 UnlinkedCodeBlock::~UnlinkedCodeBlock()
470 void UnlinkedProgramCodeBlock::destroy(JSCell
* cell
)
472 jsCast
<UnlinkedProgramCodeBlock
*>(cell
)->~UnlinkedProgramCodeBlock();
475 void UnlinkedEvalCodeBlock::destroy(JSCell
* cell
)
477 jsCast
<UnlinkedEvalCodeBlock
*>(cell
)->~UnlinkedEvalCodeBlock();
480 void UnlinkedFunctionCodeBlock::destroy(JSCell
* cell
)
482 jsCast
<UnlinkedFunctionCodeBlock
*>(cell
)->~UnlinkedFunctionCodeBlock();
485 void UnlinkedFunctionExecutable::destroy(JSCell
* cell
)
487 jsCast
<UnlinkedFunctionExecutable
*>(cell
)->~UnlinkedFunctionExecutable();
490 void UnlinkedCodeBlock::setInstructions(std::unique_ptr
<UnlinkedInstructionStream
> instructions
)
492 m_unlinkedInstructions
= WTF::move(instructions
);
495 const UnlinkedInstructionStream
& UnlinkedCodeBlock::instructions() const
497 ASSERT(m_unlinkedInstructions
.get());
498 return *m_unlinkedInstructions
;