]> git.saurik.com Git - apple/javascriptcore.git/blame - bytecode/UnlinkedCodeBlock.cpp
JavaScriptCore-1218.34.tar.gz
[apple/javascriptcore.git] / bytecode / UnlinkedCodeBlock.cpp
CommitLineData
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
41namespace JSC {
42
43const ClassInfo UnlinkedFunctionExecutable::s_info = { "UnlinkedFunctionExecutable", 0, 0, 0, CREATE_METHOD_TABLE(UnlinkedFunctionExecutable) };
44const ClassInfo UnlinkedCodeBlock::s_info = { "UnlinkedCodeBlock", 0, 0, 0, CREATE_METHOD_TABLE(UnlinkedCodeBlock) };
45const ClassInfo UnlinkedGlobalCodeBlock::s_info = { "UnlinkedGlobalCodeBlock", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(UnlinkedGlobalCodeBlock) };
46const ClassInfo UnlinkedProgramCodeBlock::s_info = { "UnlinkedProgramCodeBlock", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(UnlinkedProgramCodeBlock) };
47const ClassInfo UnlinkedEvalCodeBlock::s_info = { "UnlinkedEvalCodeBlock", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(UnlinkedEvalCodeBlock) };
48const ClassInfo UnlinkedFunctionCodeBlock::s_info = { "UnlinkedFunctionCodeBlock", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(UnlinkedFunctionCodeBlock) };
49
50static 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
73unsigned 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
83UnlinkedFunctionExecutable::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
103size_t UnlinkedFunctionExecutable::parameterCount() const
104{
105 return m_parameters->size();
106}
107
108void 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
122FunctionExecutable* 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
131UnlinkedFunctionExecutable* 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
148UnlinkedFunctionCodeBlock* 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
179String 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
191UnlinkedCodeBlock::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
223void 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
242int 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
254void 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
305void 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
359void 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
370UnlinkedCodeBlock::~UnlinkedCodeBlock()
371{
372}
373
374void UnlinkedProgramCodeBlock::destroy(JSCell* cell)
375{
376 jsCast<UnlinkedProgramCodeBlock*>(cell)->~UnlinkedProgramCodeBlock();
377}
378
379void UnlinkedEvalCodeBlock::destroy(JSCell* cell)
380{
381 jsCast<UnlinkedEvalCodeBlock*>(cell)->~UnlinkedEvalCodeBlock();
382}
383
384void UnlinkedFunctionCodeBlock::destroy(JSCell* cell)
385{
386 jsCast<UnlinkedFunctionCodeBlock*>(cell)->~UnlinkedFunctionCodeBlock();
387}
388
389void UnlinkedFunctionExecutable::destroy(JSCell* cell)
390{
391 jsCast<UnlinkedFunctionExecutable*>(cell)->~UnlinkedFunctionExecutable();
392}
393
394}
395