]>
Commit | Line | Data |
---|---|---|
93a37866 A |
1 | /* |
2 | * Copyright (C) 2012, 2013 Apple Inc. All Rights Reserved. | |
3 | * | |
4 | * Redistribution and use in source and binary forms, with or without | |
5 | * modification, are permitted provided that the following conditions | |
6 | * are met: | |
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. | |
12 | * | |
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. | |
24 | */ | |
25 | ||
26 | #include "config.h" | |
27 | ||
28 | #include "UnlinkedCodeBlock.h" | |
29 | ||
30 | #include "BytecodeGenerator.h" | |
31 | #include "ClassInfo.h" | |
32 | #include "CodeCache.h" | |
33 | #include "Executable.h" | |
34 | #include "JSString.h" | |
35 | #include "Operations.h" | |
36 | #include "Parser.h" | |
37 | #include "SourceProvider.h" | |
38 | #include "Structure.h" | |
39 | #include "SymbolTable.h" | |
40 | ||
41 | namespace JSC { | |
42 | ||
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) }; | |
49 | ||
50 | static UnlinkedFunctionCodeBlock* generateFunctionCodeBlock(VM& vm, JSScope* scope, UnlinkedFunctionExecutable* executable, const SourceCode& source, CodeSpecializationKind kind, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) | |
51 | { | |
52 | RefPtr<FunctionBodyNode> body = parse<FunctionBodyNode>(&vm, source, executable->parameters(), executable->name(), executable->isInStrictContext() ? JSParseStrict : JSParseNormal, JSParseFunctionCode, error); | |
53 | ||
54 | if (!body) { | |
55 | ASSERT(error.m_type != ParserError::ErrorNone); | |
56 | return 0; | |
57 | } | |
58 | ||
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()); | |
63 | ||
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(); | |
67 | body->destroyData(); | |
68 | if (error.m_type != ParserError::ErrorNone) | |
69 | return 0; | |
70 | return result; | |
71 | } | |
72 | ||
73 | unsigned UnlinkedCodeBlock::addOrFindConstant(JSValue v) | |
74 | { | |
75 | unsigned numberOfConstants = numberOfConstantRegisters(); | |
76 | for (unsigned i = 0; i < numberOfConstants; ++i) { | |
77 | if (getConstant(FirstConstantRegisterIndex + i) == v) | |
78 | return i; | |
79 | } | |
80 | return addConstant(v); | |
81 | } | |
82 | ||
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()) | |
100 | { | |
101 | } | |
102 | ||
103 | size_t UnlinkedFunctionExecutable::parameterCount() const | |
104 | { | |
105 | return m_parameters->size(); | |
106 | } | |
107 | ||
108 | void UnlinkedFunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) | |
109 | { | |
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); | |
120 | } | |
121 | ||
122 | FunctionExecutable* UnlinkedFunctionExecutable::link(VM& vm, const SourceCode& source, size_t lineOffset, size_t sourceOffset) | |
123 | { | |
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); | |
129 | } | |
130 | ||
131 | UnlinkedFunctionExecutable* UnlinkedFunctionExecutable::fromGlobalCode(const Identifier& name, ExecState* exec, Debugger*, const SourceCode& source, JSObject** exception) | |
132 | { | |
133 | ParserError error; | |
134 | CodeCache* codeCache = exec->vm().codeCache(); | |
135 | UnlinkedFunctionExecutable* executable = codeCache->getFunctionExecutableFromGlobalCode(exec->vm(), name, source, error); | |
136 | ||
137 | if (exec->lexicalGlobalObject()->hasDebugger()) | |
138 | exec->lexicalGlobalObject()->debugger()->sourceParsed(exec, source.provider(), error.m_line, error.m_message); | |
139 | ||
140 | if (error.m_type != ParserError::ErrorNone) { | |
141 | *exception = error.toErrorObject(exec->lexicalGlobalObject(), source); | |
142 | return 0; | |
143 | } | |
144 | ||
145 | return executable; | |
146 | } | |
147 | ||
148 | UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(VM& vm, JSScope* scope, const SourceCode& source, CodeSpecializationKind specializationKind, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) | |
149 | { | |
150 | switch (specializationKind) { | |
151 | case CodeForCall: | |
152 | if (UnlinkedFunctionCodeBlock* codeBlock = m_codeBlockForCall.get()) | |
153 | return codeBlock; | |
154 | break; | |
155 | case CodeForConstruct: | |
156 | if (UnlinkedFunctionCodeBlock* codeBlock = m_codeBlockForConstruct.get()) | |
157 | return codeBlock; | |
158 | break; | |
159 | } | |
160 | ||
161 | UnlinkedFunctionCodeBlock* result = generateFunctionCodeBlock(vm, scope, this, source, specializationKind, debuggerMode, profilerMode, error); | |
162 | ||
163 | if (error.m_type != ParserError::ErrorNone) | |
164 | return 0; | |
165 | ||
166 | switch (specializationKind) { | |
167 | case CodeForCall: | |
168 | m_codeBlockForCall.set(vm, this, result); | |
169 | m_symbolTableForCall.set(vm, this, result->symbolTable()); | |
170 | break; | |
171 | case CodeForConstruct: | |
172 | m_codeBlockForConstruct.set(vm, this, result); | |
173 | m_symbolTableForConstruct.set(vm, this, result->symbolTable()); | |
174 | break; | |
175 | } | |
176 | return result; | |
177 | } | |
178 | ||
179 | String UnlinkedFunctionExecutable::paramString() const | |
180 | { | |
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()); | |
187 | } | |
188 | return builder.toString(); | |
189 | } | |
190 | ||
191 | UnlinkedCodeBlock::UnlinkedCodeBlock(VM* vm, Structure* structure, CodeType codeType, const ExecutableInfo& info) | |
192 | : Base(*vm, structure) | |
193 | , m_numVars(0) | |
194 | , m_numCalleeRegisters(0) | |
195 | , m_numParameters(0) | |
196 | , m_vm(vm) | |
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) | |
205 | , m_firstLine(0) | |
206 | , m_lineCount(0) | |
207 | , m_features(0) | |
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) | |
218 | #endif | |
219 | { | |
220 | ||
221 | } | |
222 | ||
223 | void UnlinkedCodeBlock::visitChildren(JSCell* cell, SlotVisitor& visitor) | |
224 | { | |
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) | |
232 | visitor.append(ptr); | |
233 | for (FunctionExpressionVector::iterator ptr = thisObject->m_functionExprs.begin(), end = thisObject->m_functionExprs.end(); ptr != end; ++ptr) | |
234 | visitor.append(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]); | |
239 | } | |
240 | } | |
241 | ||
242 | int UnlinkedCodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset) | |
243 | { | |
244 | ASSERT(bytecodeOffset < instructions().size()); | |
245 | int divot; | |
246 | int startOffset; | |
247 | int endOffset; | |
248 | unsigned line; | |
249 | unsigned column; | |
250 | expressionRangeForBytecodeOffset(bytecodeOffset, divot, startOffset, endOffset, line, column); | |
251 | return line; | |
252 | } | |
253 | ||
254 | void UnlinkedCodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset, | |
255 | int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column) | |
256 | { | |
257 | ASSERT(bytecodeOffset < instructions().size()); | |
258 | ||
259 | if (!m_expressionInfo.size()) { | |
260 | startOffset = 0; | |
261 | endOffset = 0; | |
262 | divot = 0; | |
263 | line = 0; | |
264 | column = 0; | |
265 | return; | |
266 | } | |
267 | ||
268 | Vector<ExpressionRangeInfo>& expressionInfo = m_expressionInfo; | |
269 | ||
270 | int low = 0; | |
271 | int high = expressionInfo.size(); | |
272 | while (low < high) { | |
273 | int mid = low + (high - low) / 2; | |
274 | if (expressionInfo[mid].instructionOffset <= bytecodeOffset) | |
275 | low = mid + 1; | |
276 | else | |
277 | high = mid; | |
278 | } | |
279 | ||
280 | if (!low) | |
281 | low = 1; | |
282 | ||
283 | ExpressionRangeInfo& info = expressionInfo[low - 1]; | |
284 | startOffset = info.startOffset; | |
285 | endOffset = info.endOffset; | |
286 | divot = info.divotPoint; | |
287 | ||
288 | switch (info.mode) { | |
289 | case ExpressionRangeInfo::FatLineMode: | |
290 | info.decodeFatLineMode(line, column); | |
291 | break; | |
292 | case ExpressionRangeInfo::FatColumnMode: | |
293 | info.decodeFatColumnMode(line, column); | |
294 | break; | |
295 | case ExpressionRangeInfo::FatLineAndColumnMode: { | |
296 | unsigned fatIndex = info.position; | |
297 | ExpressionRangeInfo::FatPosition& fatPos = m_rareData->m_expressionInfoFatPositions[fatIndex]; | |
298 | line = fatPos.line; | |
299 | column = fatPos.column; | |
300 | break; | |
301 | } | |
302 | } // switch | |
303 | } | |
304 | ||
305 | void UnlinkedCodeBlock::addExpressionInfo(unsigned instructionOffset, | |
306 | int divot, int startOffset, int endOffset, unsigned line, unsigned column) | |
307 | { | |
308 | if (divot > ExpressionRangeInfo::MaxDivot) { | |
309 | // Overflow has occurred, we can only give line number info for errors for this region | |
310 | divot = 0; | |
311 | startOffset = 0; | |
312 | endOffset = 0; | |
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. | |
317 | startOffset = 0; | |
318 | endOffset = 0; | |
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. | |
323 | endOffset = 0; | |
324 | } | |
325 | ||
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; | |
332 | ||
333 | ExpressionRangeInfo info; | |
334 | info.instructionOffset = instructionOffset; | |
335 | info.divotPoint = divot; | |
336 | info.startOffset = startOffset; | |
337 | info.endOffset = endOffset; | |
338 | ||
339 | info.mode = positionMode; | |
340 | switch (positionMode) { | |
341 | case ExpressionRangeInfo::FatLineMode: | |
342 | info.encodeFatLineMode(line, column); | |
343 | break; | |
344 | case ExpressionRangeInfo::FatColumnMode: | |
345 | info.encodeFatColumnMode(line, column); | |
346 | break; | |
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; | |
353 | } | |
354 | } // switch | |
355 | ||
356 | m_expressionInfo.append(info); | |
357 | } | |
358 | ||
359 | void UnlinkedProgramCodeBlock::visitChildren(JSCell* cell, SlotVisitor& visitor) | |
360 | { | |
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); | |
368 | } | |
369 | ||
370 | UnlinkedCodeBlock::~UnlinkedCodeBlock() | |
371 | { | |
372 | } | |
373 | ||
374 | void UnlinkedProgramCodeBlock::destroy(JSCell* cell) | |
375 | { | |
376 | jsCast<UnlinkedProgramCodeBlock*>(cell)->~UnlinkedProgramCodeBlock(); | |
377 | } | |
378 | ||
379 | void UnlinkedEvalCodeBlock::destroy(JSCell* cell) | |
380 | { | |
381 | jsCast<UnlinkedEvalCodeBlock*>(cell)->~UnlinkedEvalCodeBlock(); | |
382 | } | |
383 | ||
384 | void UnlinkedFunctionCodeBlock::destroy(JSCell* cell) | |
385 | { | |
386 | jsCast<UnlinkedFunctionCodeBlock*>(cell)->~UnlinkedFunctionCodeBlock(); | |
387 | } | |
388 | ||
389 | void UnlinkedFunctionExecutable::destroy(JSCell* cell) | |
390 | { | |
391 | jsCast<UnlinkedFunctionExecutable*>(cell)->~UnlinkedFunctionExecutable(); | |
392 | } | |
393 | ||
394 | } | |
395 |