]> git.saurik.com Git - apple/javascriptcore.git/blame_incremental - bytecode/UnlinkedCodeBlock.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / bytecode / UnlinkedCodeBlock.cpp
... / ...
CommitLineData
1/*
2 * Copyright (C) 2012, 2013, 2015 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 "FunctionOverrides.h"
35#include "JSString.h"
36#include "JSCInlines.h"
37#include "Parser.h"
38#include "SourceProvider.h"
39#include "Structure.h"
40#include "SymbolTable.h"
41#include "UnlinkedInstructionStream.h"
42#include <wtf/DataLog.h>
43
44namespace JSC {
45
46static_assert(sizeof(UnlinkedFunctionExecutable) <= 128, "UnlinkedFunctionExecutable should fit in a 128-byte cell.");
47
48const ClassInfo UnlinkedFunctionExecutable::s_info = { "UnlinkedFunctionExecutable", 0, 0, CREATE_METHOD_TABLE(UnlinkedFunctionExecutable) };
49const ClassInfo UnlinkedCodeBlock::s_info = { "UnlinkedCodeBlock", 0, 0, CREATE_METHOD_TABLE(UnlinkedCodeBlock) };
50const ClassInfo UnlinkedGlobalCodeBlock::s_info = { "UnlinkedGlobalCodeBlock", &Base::s_info, 0, CREATE_METHOD_TABLE(UnlinkedGlobalCodeBlock) };
51const ClassInfo UnlinkedProgramCodeBlock::s_info = { "UnlinkedProgramCodeBlock", &Base::s_info, 0, CREATE_METHOD_TABLE(UnlinkedProgramCodeBlock) };
52const ClassInfo UnlinkedEvalCodeBlock::s_info = { "UnlinkedEvalCodeBlock", &Base::s_info, 0, CREATE_METHOD_TABLE(UnlinkedEvalCodeBlock) };
53const ClassInfo UnlinkedFunctionCodeBlock::s_info = { "UnlinkedFunctionCodeBlock", &Base::s_info, 0, CREATE_METHOD_TABLE(UnlinkedFunctionCodeBlock) };
54
55static UnlinkedFunctionCodeBlock* generateFunctionCodeBlock(
56 VM& vm, UnlinkedFunctionExecutable* executable, const SourceCode& source,
57 CodeSpecializationKind kind, DebuggerMode debuggerMode, ProfilerMode profilerMode,
58 UnlinkedFunctionKind functionKind, ParserError& error)
59{
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);
65
66 if (!function) {
67 ASSERT(error.isValid());
68 return nullptr;
69 }
70
71 function->finishParsing(executable->parameters(), executable->name(), executable->functionMode());
72 executable->recordParse(function->features(), function->hasCapturedVariables());
73
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();
78 if (error.isValid())
79 return nullptr;
80 return result;
81}
82
83UnlinkedFunctionExecutable::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)
99 , m_features(0)
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())
105{
106 ASSERT(m_constructorKind == static_cast<unsigned>(node->constructorKind()));
107}
108
109size_t UnlinkedFunctionExecutable::parameterCount() const
110{
111 return m_parameters->size();
112}
113
114void UnlinkedFunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor)
115{
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);
124}
125
126FunctionExecutable* UnlinkedFunctionExecutable::link(VM& vm, const SourceCode& ownerSource, int overrideLineNumber)
127{
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;
132
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);
138
139 SourceCode code(source.provider(), startOffset, startOffset + m_sourceLength, firstLine, startColumn);
140 FunctionOverrides::OverrideInfo overrideInfo;
141 bool hasFunctionOverride = false;
142
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;
151 }
152 }
153
154 FunctionExecutable* result = FunctionExecutable::create(vm, code, this, firstLine, firstLine + lineCount, startColumn, endColumn);
155 if (overrideLineNumber != -1)
156 result->setOverrideLineNumber(overrideLineNumber);
157
158 if (UNLIKELY(hasFunctionOverride)) {
159 result->overrideParameterAndTypeProfilingStartEndOffsets(
160 overrideInfo.parametersStartOffset,
161 overrideInfo.typeProfilingStartOffset,
162 overrideInfo.typeProfilingEndOffset);
163 }
164
165 return result;
166}
167
168UnlinkedFunctionExecutable* UnlinkedFunctionExecutable::fromGlobalCode(
169 const Identifier& name, ExecState& exec, const SourceCode& source,
170 JSObject*& exception, int overrideLineNumber)
171{
172 ParserError error;
173 VM& vm = exec.vm();
174 CodeCache* codeCache = vm.codeCache();
175 UnlinkedFunctionExecutable* executable = codeCache->getFunctionExecutableFromGlobalCode(vm, name, source, error);
176
177 auto& globalObject = *exec.lexicalGlobalObject();
178 if (globalObject.hasDebugger())
179 globalObject.debugger()->sourceParsed(&exec, source.provider(), error.line(), error.message());
180
181 if (error.isValid()) {
182 exception = error.toErrorObject(&globalObject, source, overrideLineNumber);
183 return nullptr;
184 }
185
186 return executable;
187}
188
189UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(
190 VM& vm, const SourceCode& source, CodeSpecializationKind specializationKind,
191 DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
192{
193 switch (specializationKind) {
194 case CodeForCall:
195 if (UnlinkedFunctionCodeBlock* codeBlock = m_codeBlockForCall.get())
196 return codeBlock;
197 break;
198 case CodeForConstruct:
199 if (UnlinkedFunctionCodeBlock* codeBlock = m_codeBlockForConstruct.get())
200 return codeBlock;
201 break;
202 }
203
204 UnlinkedFunctionCodeBlock* result = generateFunctionCodeBlock(
205 vm, this, source, specializationKind, debuggerMode, profilerMode,
206 isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction,
207 error);
208
209 if (error.isValid())
210 return nullptr;
211
212 switch (specializationKind) {
213 case CodeForCall:
214 m_codeBlockForCall.set(vm, this, result);
215 m_symbolTableForCall.set(vm, this, result->symbolTable());
216 break;
217 case CodeForConstruct:
218 m_codeBlockForConstruct.set(vm, this, result);
219 m_symbolTableForConstruct.set(vm, this, result->symbolTable());
220 break;
221 }
222 return result;
223}
224
225UnlinkedCodeBlock::UnlinkedCodeBlock(VM* vm, Structure* structure, CodeType codeType, const ExecutableInfo& info)
226 : Base(*vm, structure)
227 , m_numVars(0)
228 , m_numCalleeRegisters(0)
229 , m_numParameters(0)
230 , m_vm(vm)
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()))
239 , m_firstLine(0)
240 , m_lineCount(0)
241 , m_endColumn(UINT_MAX)
242 , m_features(0)
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)
251#endif
252{
253 for (auto& constantRegisterIndex : m_linkTimeConstants)
254 constantRegisterIndex = 0;
255 ASSERT(m_constructorKind == static_cast<unsigned>(info.constructorKind()));
256}
257
258void UnlinkedCodeBlock::visitChildren(JSCell* cell, SlotVisitor& visitor)
259{
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)
265 visitor.append(ptr);
266 for (FunctionExpressionVector::iterator ptr = thisObject->m_functionExprs.begin(), end = thisObject->m_functionExprs.end(); ptr != end; ++ptr)
267 visitor.append(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]);
272 }
273}
274
275int UnlinkedCodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset)
276{
277 ASSERT(bytecodeOffset < instructions().count());
278 int divot;
279 int startOffset;
280 int endOffset;
281 unsigned line;
282 unsigned column;
283 expressionRangeForBytecodeOffset(bytecodeOffset, divot, startOffset, endOffset, line, column);
284 return line;
285}
286
287inline void UnlinkedCodeBlock::getLineAndColumn(ExpressionRangeInfo& info,
288 unsigned& line, unsigned& column)
289{
290 switch (info.mode) {
291 case ExpressionRangeInfo::FatLineMode:
292 info.decodeFatLineMode(line, column);
293 break;
294 case ExpressionRangeInfo::FatColumnMode:
295 info.decodeFatColumnMode(line, column);
296 break;
297 case ExpressionRangeInfo::FatLineAndColumnMode: {
298 unsigned fatIndex = info.position;
299 ExpressionRangeInfo::FatPosition& fatPos = m_rareData->m_expressionInfoFatPositions[fatIndex];
300 line = fatPos.line;
301 column = fatPos.column;
302 break;
303 }
304 } // switch
305}
306
307#ifndef NDEBUG
308static void dumpLineColumnEntry(size_t index, const UnlinkedInstructionStream& instructionStream, unsigned instructionOffset, unsigned line, unsigned column)
309{
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;
321 }
322 }
323 dataLogF(" [%zu] pc %u @ line %u col %u : %s%s\n", index, instructionOffset, line, column, opcodeNames[opcode], event);
324}
325
326void UnlinkedCodeBlock::dumpExpressionRangeInfo()
327{
328 Vector<ExpressionRangeInfo>& expressionInfo = m_expressionInfo;
329
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];
334 unsigned line;
335 unsigned column;
336 getLineAndColumn(info, line, column);
337 dumpLineColumnEntry(i, instructions(), info.instructionOffset, line, column);
338 }
339 dataLog("}\n");
340}
341#endif
342
343void UnlinkedCodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset,
344 int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column)
345{
346 ASSERT(bytecodeOffset < instructions().count());
347
348 if (!m_expressionInfo.size()) {
349 startOffset = 0;
350 endOffset = 0;
351 divot = 0;
352 line = 0;
353 column = 0;
354 return;
355 }
356
357 Vector<ExpressionRangeInfo>& expressionInfo = m_expressionInfo;
358
359 int low = 0;
360 int high = expressionInfo.size();
361 while (low < high) {
362 int mid = low + (high - low) / 2;
363 if (expressionInfo[mid].instructionOffset <= bytecodeOffset)
364 low = mid + 1;
365 else
366 high = mid;
367 }
368
369 if (!low)
370 low = 1;
371
372 ExpressionRangeInfo& info = expressionInfo[low - 1];
373 startOffset = info.startOffset;
374 endOffset = info.endOffset;
375 divot = info.divotPoint;
376 getLineAndColumn(info, line, column);
377}
378
379void UnlinkedCodeBlock::addExpressionInfo(unsigned instructionOffset,
380 int divot, int startOffset, int endOffset, unsigned line, unsigned column)
381{
382 if (divot > ExpressionRangeInfo::MaxDivot) {
383 // Overflow has occurred, we can only give line number info for errors for this region
384 divot = 0;
385 startOffset = 0;
386 endOffset = 0;
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.
391 startOffset = 0;
392 endOffset = 0;
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.
397 endOffset = 0;
398 }
399
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;
406
407 ExpressionRangeInfo info;
408 info.instructionOffset = instructionOffset;
409 info.divotPoint = divot;
410 info.startOffset = startOffset;
411 info.endOffset = endOffset;
412
413 info.mode = positionMode;
414 switch (positionMode) {
415 case ExpressionRangeInfo::FatLineMode:
416 info.encodeFatLineMode(line, column);
417 break;
418 case ExpressionRangeInfo::FatColumnMode:
419 info.encodeFatColumnMode(line, column);
420 break;
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;
427 }
428 } // switch
429
430 m_expressionInfo.append(info);
431}
432
433bool UnlinkedCodeBlock::typeProfilerExpressionInfoForBytecodeOffset(unsigned bytecodeOffset, unsigned& startDivot, unsigned& endDivot)
434{
435 static const bool verbose = false;
436 auto iter = m_typeProfilerInfoMap.find(bytecodeOffset);
437 if (iter == m_typeProfilerInfoMap.end()) {
438 if (verbose)
439 dataLogF("Don't have assignment info for offset:%u\n", bytecodeOffset);
440 startDivot = UINT_MAX;
441 endDivot = UINT_MAX;
442 return false;
443 }
444
445 TypeProfilerExpressionRange& range = iter->value;
446 startDivot = range.m_startDivot;
447 endDivot = range.m_endDivot;
448 return true;
449}
450
451void UnlinkedCodeBlock::addTypeProfilerExpressionInfo(unsigned instructionOffset, unsigned startDivot, unsigned endDivot)
452{
453 TypeProfilerExpressionRange range;
454 range.m_startDivot = startDivot;
455 range.m_endDivot = endDivot;
456 m_typeProfilerInfoMap.set(instructionOffset, range);
457}
458
459void UnlinkedProgramCodeBlock::visitChildren(JSCell* cell, SlotVisitor& visitor)
460{
461 UnlinkedProgramCodeBlock* thisObject = jsCast<UnlinkedProgramCodeBlock*>(cell);
462 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
463 Base::visitChildren(thisObject, visitor);
464}
465
466UnlinkedCodeBlock::~UnlinkedCodeBlock()
467{
468}
469
470void UnlinkedProgramCodeBlock::destroy(JSCell* cell)
471{
472 jsCast<UnlinkedProgramCodeBlock*>(cell)->~UnlinkedProgramCodeBlock();
473}
474
475void UnlinkedEvalCodeBlock::destroy(JSCell* cell)
476{
477 jsCast<UnlinkedEvalCodeBlock*>(cell)->~UnlinkedEvalCodeBlock();
478}
479
480void UnlinkedFunctionCodeBlock::destroy(JSCell* cell)
481{
482 jsCast<UnlinkedFunctionCodeBlock*>(cell)->~UnlinkedFunctionCodeBlock();
483}
484
485void UnlinkedFunctionExecutable::destroy(JSCell* cell)
486{
487 jsCast<UnlinkedFunctionExecutable*>(cell)->~UnlinkedFunctionExecutable();
488}
489
490void UnlinkedCodeBlock::setInstructions(std::unique_ptr<UnlinkedInstructionStream> instructions)
491{
492 m_unlinkedInstructions = WTF::move(instructions);
493}
494
495const UnlinkedInstructionStream& UnlinkedCodeBlock::instructions() const
496{
497 ASSERT(m_unlinkedInstructions.get());
498 return *m_unlinkedInstructions;
499}
500
501}
502