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 "Operations.h"
37 #include "SourceProvider.h"
38 #include "Structure.h"
39 #include "SymbolTable.h"
43 const ClassInfo
UnlinkedFunctionExecutable::s_info
= { "UnlinkedFunctionExecutable", 0, 0, 0, CREATE_METHOD_TABLE(UnlinkedFunctionExecutable
) };
44 const ClassInfo
UnlinkedCodeBlock::s_info
= { "UnlinkedCodeBlock", 0, 0, 0, CREATE_METHOD_TABLE(UnlinkedCodeBlock
) };
45 const ClassInfo
UnlinkedGlobalCodeBlock::s_info
= { "UnlinkedGlobalCodeBlock", &Base::s_info
, 0, 0, CREATE_METHOD_TABLE(UnlinkedGlobalCodeBlock
) };
46 const ClassInfo
UnlinkedProgramCodeBlock::s_info
= { "UnlinkedProgramCodeBlock", &Base::s_info
, 0, 0, CREATE_METHOD_TABLE(UnlinkedProgramCodeBlock
) };
47 const ClassInfo
UnlinkedEvalCodeBlock::s_info
= { "UnlinkedEvalCodeBlock", &Base::s_info
, 0, 0, CREATE_METHOD_TABLE(UnlinkedEvalCodeBlock
) };
48 const ClassInfo
UnlinkedFunctionCodeBlock::s_info
= { "UnlinkedFunctionCodeBlock", &Base::s_info
, 0, 0, CREATE_METHOD_TABLE(UnlinkedFunctionCodeBlock
) };
50 static UnlinkedFunctionCodeBlock
* generateFunctionCodeBlock(VM
& vm
, JSScope
* scope
, UnlinkedFunctionExecutable
* executable
, const SourceCode
& source
, CodeSpecializationKind kind
, DebuggerMode debuggerMode
, ProfilerMode profilerMode
, ParserError
& error
)
52 RefPtr
<FunctionBodyNode
> body
= parse
<FunctionBodyNode
>(&vm
, source
, executable
->parameters(), executable
->name(), executable
->isInStrictContext() ? JSParseStrict
: JSParseNormal
, JSParseFunctionCode
, error
);
55 ASSERT(error
.m_type
!= ParserError::ErrorNone
);
59 if (executable
->forceUsesArguments())
60 body
->setUsesArguments();
61 body
->finishParsing(executable
->parameters(), executable
->name(), executable
->functionNameIsInScopeToggle());
62 executable
->recordParse(body
->features(), body
->hasCapturedVariables(), body
->lineNo(), body
->lastLine());
64 UnlinkedFunctionCodeBlock
* result
= UnlinkedFunctionCodeBlock::create(&vm
, FunctionCode
, ExecutableInfo(body
->needsActivation(), body
->usesEval(), body
->isStrictMode(), kind
== CodeForConstruct
));
65 OwnPtr
<BytecodeGenerator
> generator(adoptPtr(new BytecodeGenerator(vm
, scope
, body
.get(), result
, debuggerMode
, profilerMode
)));
66 error
= generator
->generate();
68 if (error
.m_type
!= ParserError::ErrorNone
)
73 unsigned UnlinkedCodeBlock::addOrFindConstant(JSValue v
)
75 unsigned numberOfConstants
= numberOfConstantRegisters();
76 for (unsigned i
= 0; i
< numberOfConstants
; ++i
) {
77 if (getConstant(FirstConstantRegisterIndex
+ i
) == v
)
80 return addConstant(v
);
83 UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM
* vm
, Structure
* structure
, const SourceCode
& source
, FunctionBodyNode
* node
)
84 : Base(*vm
, structure
)
85 , m_numCapturedVariables(node
->capturedVariableCount())
86 , m_forceUsesArguments(node
->usesArguments())
87 , m_isInStrictContext(node
->isStrictMode())
88 , m_hasCapturedVariables(node
->hasCapturedVariables())
89 , m_name(node
->ident())
90 , m_inferredName(node
->inferredName())
91 , m_parameters(node
->parameters())
92 , m_firstLineOffset(node
->firstLine() - source
.firstLine())
93 , m_lineCount(node
->lastLine() - node
->firstLine())
94 , m_functionStartOffset(node
->functionStart() - source
.startOffset())
95 , m_functionStartColumn(node
->startColumn())
96 , m_startOffset(node
->source().startOffset() - source
.startOffset())
97 , m_sourceLength(node
->source().length())
98 , m_features(node
->features())
99 , m_functionNameIsInScopeToggle(node
->functionNameIsInScopeToggle())
103 size_t UnlinkedFunctionExecutable::parameterCount() const
105 return m_parameters
->size();
108 void UnlinkedFunctionExecutable::visitChildren(JSCell
* cell
, SlotVisitor
& visitor
)
110 UnlinkedFunctionExecutable
* thisObject
= jsCast
<UnlinkedFunctionExecutable
*>(cell
);
111 ASSERT_GC_OBJECT_INHERITS(thisObject
, &s_info
);
112 COMPILE_ASSERT(StructureFlags
& OverridesVisitChildren
, OverridesVisitChildrenWithoutSettingFlag
);
113 ASSERT(thisObject
->structure()->typeInfo().overridesVisitChildren());
114 Base::visitChildren(thisObject
, visitor
);
115 visitor
.append(&thisObject
->m_codeBlockForCall
);
116 visitor
.append(&thisObject
->m_codeBlockForConstruct
);
117 visitor
.append(&thisObject
->m_nameValue
);
118 visitor
.append(&thisObject
->m_symbolTableForCall
);
119 visitor
.append(&thisObject
->m_symbolTableForConstruct
);
122 FunctionExecutable
* UnlinkedFunctionExecutable::link(VM
& vm
, const SourceCode
& source
, size_t lineOffset
, size_t sourceOffset
)
124 unsigned firstLine
= lineOffset
+ m_firstLineOffset
;
125 unsigned startOffset
= sourceOffset
+ m_startOffset
;
126 unsigned startColumn
= m_functionStartColumn
+ 1; // startColumn should start from 1, not 0.
127 SourceCode
code(source
.provider(), startOffset
, startOffset
+ m_sourceLength
, firstLine
, startColumn
);
128 return FunctionExecutable::create(vm
, code
, this, firstLine
, firstLine
+ m_lineCount
, startColumn
);
131 UnlinkedFunctionExecutable
* UnlinkedFunctionExecutable::fromGlobalCode(const Identifier
& name
, ExecState
* exec
, Debugger
*, const SourceCode
& source
, JSObject
** exception
)
134 CodeCache
* codeCache
= exec
->vm().codeCache();
135 UnlinkedFunctionExecutable
* executable
= codeCache
->getFunctionExecutableFromGlobalCode(exec
->vm(), name
, source
, error
);
137 if (exec
->lexicalGlobalObject()->hasDebugger())
138 exec
->lexicalGlobalObject()->debugger()->sourceParsed(exec
, source
.provider(), error
.m_line
, error
.m_message
);
140 if (error
.m_type
!= ParserError::ErrorNone
) {
141 *exception
= error
.toErrorObject(exec
->lexicalGlobalObject(), source
);
148 UnlinkedFunctionCodeBlock
* UnlinkedFunctionExecutable::codeBlockFor(VM
& vm
, JSScope
* scope
, const SourceCode
& source
, CodeSpecializationKind specializationKind
, DebuggerMode debuggerMode
, ProfilerMode profilerMode
, ParserError
& error
)
150 switch (specializationKind
) {
152 if (UnlinkedFunctionCodeBlock
* codeBlock
= m_codeBlockForCall
.get())
155 case CodeForConstruct
:
156 if (UnlinkedFunctionCodeBlock
* codeBlock
= m_codeBlockForConstruct
.get())
161 UnlinkedFunctionCodeBlock
* result
= generateFunctionCodeBlock(vm
, scope
, this, source
, specializationKind
, debuggerMode
, profilerMode
, error
);
163 if (error
.m_type
!= ParserError::ErrorNone
)
166 switch (specializationKind
) {
168 m_codeBlockForCall
.set(vm
, this, result
);
169 m_symbolTableForCall
.set(vm
, this, result
->symbolTable());
171 case CodeForConstruct
:
172 m_codeBlockForConstruct
.set(vm
, this, result
);
173 m_symbolTableForConstruct
.set(vm
, this, result
->symbolTable());
179 String
UnlinkedFunctionExecutable::paramString() const
181 FunctionParameters
& parameters
= *m_parameters
;
182 StringBuilder builder
;
183 for (size_t pos
= 0; pos
< parameters
.size(); ++pos
) {
184 if (!builder
.isEmpty())
185 builder
.appendLiteral(", ");
186 builder
.append(parameters
.at(pos
).string());
188 return builder
.toString();
191 UnlinkedCodeBlock::UnlinkedCodeBlock(VM
* vm
, Structure
* structure
, CodeType codeType
, const ExecutableInfo
& info
)
192 : Base(*vm
, structure
)
194 , m_numCalleeRegisters(0)
197 , m_argumentsRegister(-1)
198 , m_globalObjectRegister(-1)
199 , m_needsFullScopeChain(info
.m_needsActivation
)
200 , m_usesEval(info
.m_usesEval
)
201 , m_isNumericCompareFunction(false)
202 , m_isStrictMode(info
.m_isStrictMode
)
203 , m_isConstructor(info
.m_isConstructor
)
204 , m_hasCapturedVariables(false)
208 , m_codeType(codeType
)
209 , m_resolveOperationCount(0)
210 , m_putToBaseOperationCount(1)
211 , m_arrayProfileCount(0)
212 , m_arrayAllocationProfileCount(0)
213 , m_objectAllocationProfileCount(0)
214 , m_valueProfileCount(0)
215 , m_llintCallLinkInfoCount(0)
216 #if ENABLE(BYTECODE_COMMENTS)
217 , m_bytecodeCommentIterator(0)
223 void UnlinkedCodeBlock::visitChildren(JSCell
* cell
, SlotVisitor
& visitor
)
225 UnlinkedCodeBlock
* thisObject
= jsCast
<UnlinkedCodeBlock
*>(cell
);
226 ASSERT_GC_OBJECT_INHERITS(thisObject
, &s_info
);
227 COMPILE_ASSERT(StructureFlags
& OverridesVisitChildren
, OverridesVisitChildrenWithoutSettingFlag
);
228 ASSERT(thisObject
->structure()->typeInfo().overridesVisitChildren());
229 Base::visitChildren(thisObject
, visitor
);
230 visitor
.append(&thisObject
->m_symbolTable
);
231 for (FunctionExpressionVector::iterator ptr
= thisObject
->m_functionDecls
.begin(), end
= thisObject
->m_functionDecls
.end(); ptr
!= end
; ++ptr
)
233 for (FunctionExpressionVector::iterator ptr
= thisObject
->m_functionExprs
.begin(), end
= thisObject
->m_functionExprs
.end(); ptr
!= end
; ++ptr
)
235 visitor
.appendValues(thisObject
->m_constantRegisters
.data(), thisObject
->m_constantRegisters
.size());
236 if (thisObject
->m_rareData
) {
237 for (size_t i
= 0, end
= thisObject
->m_rareData
->m_regexps
.size(); i
!= end
; i
++)
238 visitor
.append(&thisObject
->m_rareData
->m_regexps
[i
]);
242 int UnlinkedCodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset
)
244 ASSERT(bytecodeOffset
< instructions().size());
250 expressionRangeForBytecodeOffset(bytecodeOffset
, divot
, startOffset
, endOffset
, line
, column
);
254 void UnlinkedCodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset
,
255 int& divot
, int& startOffset
, int& endOffset
, unsigned& line
, unsigned& column
)
257 ASSERT(bytecodeOffset
< instructions().size());
259 if (!m_expressionInfo
.size()) {
268 Vector
<ExpressionRangeInfo
>& expressionInfo
= m_expressionInfo
;
271 int high
= expressionInfo
.size();
273 int mid
= low
+ (high
- low
) / 2;
274 if (expressionInfo
[mid
].instructionOffset
<= bytecodeOffset
)
283 ExpressionRangeInfo
& info
= expressionInfo
[low
- 1];
284 startOffset
= info
.startOffset
;
285 endOffset
= info
.endOffset
;
286 divot
= info
.divotPoint
;
289 case ExpressionRangeInfo::FatLineMode
:
290 info
.decodeFatLineMode(line
, column
);
292 case ExpressionRangeInfo::FatColumnMode
:
293 info
.decodeFatColumnMode(line
, column
);
295 case ExpressionRangeInfo::FatLineAndColumnMode
: {
296 unsigned fatIndex
= info
.position
;
297 ExpressionRangeInfo::FatPosition
& fatPos
= m_rareData
->m_expressionInfoFatPositions
[fatIndex
];
299 column
= fatPos
.column
;
305 void UnlinkedCodeBlock::addExpressionInfo(unsigned instructionOffset
,
306 int divot
, int startOffset
, int endOffset
, unsigned line
, unsigned column
)
308 if (divot
> ExpressionRangeInfo::MaxDivot
) {
309 // Overflow has occurred, we can only give line number info for errors for this region
313 } else if (startOffset
> ExpressionRangeInfo::MaxOffset
) {
314 // If the start offset is out of bounds we clear both offsets
315 // so we only get the divot marker. Error message will have to be reduced
316 // to line and charPosition number.
319 } else if (endOffset
> ExpressionRangeInfo::MaxOffset
) {
320 // The end offset is only used for additional context, and is much more likely
321 // to overflow (eg. function call arguments) so we are willing to drop it without
322 // dropping the rest of the range.
326 unsigned positionMode
=
327 (line
<= ExpressionRangeInfo::MaxFatLineModeLine
&& column
<= ExpressionRangeInfo::MaxFatLineModeColumn
)
328 ? ExpressionRangeInfo::FatLineMode
329 : (line
<= ExpressionRangeInfo::MaxFatColumnModeLine
&& column
<= ExpressionRangeInfo::MaxFatColumnModeColumn
)
330 ? ExpressionRangeInfo::FatColumnMode
331 : ExpressionRangeInfo::FatLineAndColumnMode
;
333 ExpressionRangeInfo info
;
334 info
.instructionOffset
= instructionOffset
;
335 info
.divotPoint
= divot
;
336 info
.startOffset
= startOffset
;
337 info
.endOffset
= endOffset
;
339 info
.mode
= positionMode
;
340 switch (positionMode
) {
341 case ExpressionRangeInfo::FatLineMode
:
342 info
.encodeFatLineMode(line
, column
);
344 case ExpressionRangeInfo::FatColumnMode
:
345 info
.encodeFatColumnMode(line
, column
);
347 case ExpressionRangeInfo::FatLineAndColumnMode
: {
348 createRareDataIfNecessary();
349 unsigned fatIndex
= m_rareData
->m_expressionInfoFatPositions
.size();
350 ExpressionRangeInfo::FatPosition fatPos
= { line
, column
};
351 m_rareData
->m_expressionInfoFatPositions
.append(fatPos
);
352 info
.position
= fatIndex
;
356 m_expressionInfo
.append(info
);
359 void UnlinkedProgramCodeBlock::visitChildren(JSCell
* cell
, SlotVisitor
& visitor
)
361 UnlinkedProgramCodeBlock
* thisObject
= jsCast
<UnlinkedProgramCodeBlock
*>(cell
);
362 ASSERT_GC_OBJECT_INHERITS(thisObject
, &s_info
);
363 COMPILE_ASSERT(StructureFlags
& OverridesVisitChildren
, OverridesVisitChildrenWithoutSettingFlag
);
364 ASSERT(thisObject
->structure()->typeInfo().overridesVisitChildren());
365 Base::visitChildren(thisObject
, visitor
);
366 for (size_t i
= 0, end
= thisObject
->m_functionDeclarations
.size(); i
!= end
; i
++)
367 visitor
.append(&thisObject
->m_functionDeclarations
[i
].second
);
370 UnlinkedCodeBlock::~UnlinkedCodeBlock()
374 void UnlinkedProgramCodeBlock::destroy(JSCell
* cell
)
376 jsCast
<UnlinkedProgramCodeBlock
*>(cell
)->~UnlinkedProgramCodeBlock();
379 void UnlinkedEvalCodeBlock::destroy(JSCell
* cell
)
381 jsCast
<UnlinkedEvalCodeBlock
*>(cell
)->~UnlinkedEvalCodeBlock();
384 void UnlinkedFunctionCodeBlock::destroy(JSCell
* cell
)
386 jsCast
<UnlinkedFunctionCodeBlock
*>(cell
)->~UnlinkedFunctionCodeBlock();
389 void UnlinkedFunctionExecutable::destroy(JSCell
* cell
)
391 jsCast
<UnlinkedFunctionExecutable
*>(cell
)->~UnlinkedFunctionExecutable();