]> git.saurik.com Git - apple/javascriptcore.git/blob - bytecode/UnlinkedCodeBlock.cpp
JavaScriptCore-1218.tar.gz
[apple/javascriptcore.git] / bytecode / UnlinkedCodeBlock.cpp
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