2 * Copyright (C) 2012-2013, 2015-2016 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 "BytecodeRewriter.h"
32 #include "ClassInfo.h"
33 #include "CodeCache.h"
34 #include "ExecutableInfo.h"
35 #include "FunctionOverrides.h"
36 #include "JSCInlines.h"
39 #include "PreciseJumpTargetsInlines.h"
40 #include "SourceProvider.h"
41 #include "Structure.h"
42 #include "SymbolTable.h"
43 #include "UnlinkedEvalCodeBlock.h"
44 #include "UnlinkedFunctionCodeBlock.h"
45 #include "UnlinkedInstructionStream.h"
46 #include "UnlinkedModuleProgramCodeBlock.h"
47 #include "UnlinkedProgramCodeBlock.h"
48 #include <wtf/DataLog.h>
52 const ClassInfo UnlinkedCodeBlock::s_info = { "UnlinkedCodeBlock", 0, 0, CREATE_METHOD_TABLE(UnlinkedCodeBlock) };
54 UnlinkedCodeBlock::UnlinkedCodeBlock(VM* vm, Structure* structure, CodeType codeType, const ExecutableInfo& info, DebuggerMode debuggerMode)
55 : Base(*vm, structure)
57 , m_numCalleeLocals(0)
59 , m_globalObjectRegister(VirtualRegister())
60 , m_usesEval(info.usesEval())
61 , m_isStrictMode(info.isStrictMode())
62 , m_isConstructor(info.isConstructor())
63 , m_hasCapturedVariables(false)
64 , m_isBuiltinFunction(info.isBuiltinFunction())
65 , m_superBinding(static_cast<unsigned>(info.superBinding()))
66 , m_scriptMode(static_cast<unsigned>(info.scriptMode()))
67 , m_isArrowFunctionContext(info.isArrowFunctionContext())
68 , m_isClassContext(info.isClassContext())
69 , m_wasCompiledWithDebuggingOpcodes(debuggerMode == DebuggerMode::DebuggerOn || Options::forceDebuggerBytecodeGeneration())
70 , m_constructorKind(static_cast<unsigned>(info.constructorKind()))
71 , m_derivedContextType(static_cast<unsigned>(info.derivedContextType()))
72 , m_evalContextType(static_cast<unsigned>(info.evalContextType()))
74 , m_endColumn(UINT_MAX)
75 , m_didOptimize(MixedTriState)
76 , m_parseMode(info.parseMode())
78 , m_codeType(codeType)
79 , m_arrayProfileCount(0)
80 , m_arrayAllocationProfileCount(0)
81 , m_objectAllocationProfileCount(0)
82 , m_valueProfileCount(0)
83 , m_llintCallLinkInfoCount(0)
85 for (auto& constantRegisterIndex : m_linkTimeConstants)
86 constantRegisterIndex = 0;
87 ASSERT(m_constructorKind == static_cast<unsigned>(info.constructorKind()));
90 void UnlinkedCodeBlock::visitChildren(JSCell* cell, SlotVisitor& visitor)
92 UnlinkedCodeBlock* thisObject = jsCast<UnlinkedCodeBlock*>(cell);
93 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
94 Base::visitChildren(thisObject, visitor);
95 auto locker = holdLock(*thisObject);
96 for (FunctionExpressionVector::iterator ptr = thisObject->m_functionDecls.begin(), end = thisObject->m_functionDecls.end(); ptr != end; ++ptr)
98 for (FunctionExpressionVector::iterator ptr = thisObject->m_functionExprs.begin(), end = thisObject->m_functionExprs.end(); ptr != end; ++ptr)
100 visitor.appendValues(thisObject->m_constantRegisters.data(), thisObject->m_constantRegisters.size());
101 if (thisObject->m_unlinkedInstructions)
102 visitor.reportExtraMemoryVisited(thisObject->m_unlinkedInstructions->sizeInBytes());
103 if (thisObject->m_rareData) {
104 for (size_t i = 0, end = thisObject->m_rareData->m_regexps.size(); i != end; i++)
105 visitor.append(thisObject->m_rareData->m_regexps[i]);
109 size_t UnlinkedCodeBlock::estimatedSize(JSCell* cell)
111 UnlinkedCodeBlock* thisObject = jsCast<UnlinkedCodeBlock*>(cell);
112 size_t extraSize = thisObject->m_unlinkedInstructions ? thisObject->m_unlinkedInstructions->sizeInBytes() : 0;
113 return Base::estimatedSize(cell) + extraSize;
116 int UnlinkedCodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset)
118 ASSERT(bytecodeOffset < instructions().count());
124 expressionRangeForBytecodeOffset(bytecodeOffset, divot, startOffset, endOffset, line, column);
128 inline void UnlinkedCodeBlock::getLineAndColumn(const ExpressionRangeInfo& info,
129 unsigned& line, unsigned& column) const
132 case ExpressionRangeInfo::FatLineMode:
133 info.decodeFatLineMode(line, column);
135 case ExpressionRangeInfo::FatColumnMode:
136 info.decodeFatColumnMode(line, column);
138 case ExpressionRangeInfo::FatLineAndColumnMode: {
139 unsigned fatIndex = info.position;
140 ExpressionRangeInfo::FatPosition& fatPos = m_rareData->m_expressionInfoFatPositions[fatIndex];
142 column = fatPos.column;
149 static void dumpLineColumnEntry(size_t index, const UnlinkedInstructionStream& instructionStream, unsigned instructionOffset, unsigned line, unsigned column)
151 const auto& instructions = instructionStream.unpackForDebugging();
152 OpcodeID opcode = instructions[instructionOffset].u.opcode;
153 const char* event = "";
154 if (opcode == op_debug) {
155 switch (instructions[instructionOffset + 1].u.operand) {
156 case WillExecuteProgram: event = " WillExecuteProgram"; break;
157 case DidExecuteProgram: event = " DidExecuteProgram"; break;
158 case DidEnterCallFrame: event = " DidEnterCallFrame"; break;
159 case DidReachBreakpoint: event = " DidReachBreakpoint"; break;
160 case WillLeaveCallFrame: event = " WillLeaveCallFrame"; break;
161 case WillExecuteStatement: event = " WillExecuteStatement"; break;
162 case WillExecuteExpression: event = " WillExecuteExpression"; break;
165 dataLogF(" [%zu] pc %u @ line %u col %u : %s%s\n", index, instructionOffset, line, column, opcodeNames[opcode], event);
168 void UnlinkedCodeBlock::dumpExpressionRangeInfo()
170 Vector<ExpressionRangeInfo>& expressionInfo = m_expressionInfo;
172 size_t size = m_expressionInfo.size();
173 dataLogF("UnlinkedCodeBlock %p expressionRangeInfo[%zu] {\n", this, size);
174 for (size_t i = 0; i < size; i++) {
175 ExpressionRangeInfo& info = expressionInfo[i];
178 getLineAndColumn(info, line, column);
179 dumpLineColumnEntry(i, instructions(), info.instructionOffset, line, column);
185 void UnlinkedCodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset,
186 int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column) const
188 ASSERT(bytecodeOffset < instructions().count());
190 if (!m_expressionInfo.size()) {
199 const Vector<ExpressionRangeInfo>& expressionInfo = m_expressionInfo;
202 int high = expressionInfo.size();
204 int mid = low + (high - low) / 2;
205 if (expressionInfo[mid].instructionOffset <= bytecodeOffset)
214 const ExpressionRangeInfo& info = expressionInfo[low - 1];
215 startOffset = info.startOffset;
216 endOffset = info.endOffset;
217 divot = info.divotPoint;
218 getLineAndColumn(info, line, column);
221 void UnlinkedCodeBlock::addExpressionInfo(unsigned instructionOffset,
222 int divot, int startOffset, int endOffset, unsigned line, unsigned column)
224 if (divot > ExpressionRangeInfo::MaxDivot) {
225 // Overflow has occurred, we can only give line number info for errors for this region
229 } else if (startOffset > ExpressionRangeInfo::MaxOffset) {
230 // If the start offset is out of bounds we clear both offsets
231 // so we only get the divot marker. Error message will have to be reduced
232 // to line and charPosition number.
235 } else if (endOffset > ExpressionRangeInfo::MaxOffset) {
236 // The end offset is only used for additional context, and is much more likely
237 // to overflow (eg. function call arguments) so we are willing to drop it without
238 // dropping the rest of the range.
242 unsigned positionMode =
243 (line <= ExpressionRangeInfo::MaxFatLineModeLine && column <= ExpressionRangeInfo::MaxFatLineModeColumn)
244 ? ExpressionRangeInfo::FatLineMode
245 : (line <= ExpressionRangeInfo::MaxFatColumnModeLine && column <= ExpressionRangeInfo::MaxFatColumnModeColumn)
246 ? ExpressionRangeInfo::FatColumnMode
247 : ExpressionRangeInfo::FatLineAndColumnMode;
249 ExpressionRangeInfo info;
250 info.instructionOffset = instructionOffset;
251 info.divotPoint = divot;
252 info.startOffset = startOffset;
253 info.endOffset = endOffset;
255 info.mode = positionMode;
256 switch (positionMode) {
257 case ExpressionRangeInfo::FatLineMode:
258 info.encodeFatLineMode(line, column);
260 case ExpressionRangeInfo::FatColumnMode:
261 info.encodeFatColumnMode(line, column);
263 case ExpressionRangeInfo::FatLineAndColumnMode: {
264 createRareDataIfNecessary();
265 unsigned fatIndex = m_rareData->m_expressionInfoFatPositions.size();
266 ExpressionRangeInfo::FatPosition fatPos = { line, column };
267 m_rareData->m_expressionInfoFatPositions.append(fatPos);
268 info.position = fatIndex;
272 m_expressionInfo.append(info);
275 bool UnlinkedCodeBlock::typeProfilerExpressionInfoForBytecodeOffset(unsigned bytecodeOffset, unsigned& startDivot, unsigned& endDivot)
277 static const bool verbose = false;
280 dataLogF("Don't have assignment info for offset:%u\n", bytecodeOffset);
281 startDivot = UINT_MAX;
286 auto iter = m_rareData->m_typeProfilerInfoMap.find(bytecodeOffset);
287 if (iter == m_rareData->m_typeProfilerInfoMap.end()) {
289 dataLogF("Don't have assignment info for offset:%u\n", bytecodeOffset);
290 startDivot = UINT_MAX;
295 RareData::TypeProfilerExpressionRange& range = iter->value;
296 startDivot = range.m_startDivot;
297 endDivot = range.m_endDivot;
301 void UnlinkedCodeBlock::addTypeProfilerExpressionInfo(unsigned instructionOffset, unsigned startDivot, unsigned endDivot)
303 createRareDataIfNecessary();
304 RareData::TypeProfilerExpressionRange range;
305 range.m_startDivot = startDivot;
306 range.m_endDivot = endDivot;
307 m_rareData->m_typeProfilerInfoMap.set(instructionOffset, range);
310 UnlinkedCodeBlock::~UnlinkedCodeBlock()
314 void UnlinkedCodeBlock::setInstructions(std::unique_ptr<UnlinkedInstructionStream> instructions)
316 ASSERT(instructions);
318 auto locker = holdLock(*this);
319 m_unlinkedInstructions = WTFMove(instructions);
321 Heap::heap(this)->reportExtraMemoryAllocated(m_unlinkedInstructions->sizeInBytes());
324 const UnlinkedInstructionStream& UnlinkedCodeBlock::instructions() const
326 ASSERT(m_unlinkedInstructions.get());
327 return *m_unlinkedInstructions;
330 UnlinkedHandlerInfo* UnlinkedCodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset, RequiredHandler requiredHandler)
332 return handlerForIndex(bytecodeOffset, requiredHandler);
335 UnlinkedHandlerInfo* UnlinkedCodeBlock::handlerForIndex(unsigned index, RequiredHandler requiredHandler)
339 return UnlinkedHandlerInfo::handlerForIndex(m_rareData->m_exceptionHandlers, index, requiredHandler);
342 void UnlinkedCodeBlock::applyModification(BytecodeRewriter& rewriter)
344 // Before applying the changes, we adjust the jumps based on the original bytecode offset, the offset to the jump target, and
345 // the insertion information.
347 BytecodeGraph<UnlinkedCodeBlock>& graph = rewriter.graph();
348 UnlinkedInstruction* instructionsBegin = graph.instructions().begin();
350 for (int bytecodeOffset = 0, instructionCount = graph.instructions().size(); bytecodeOffset < instructionCount;) {
351 UnlinkedInstruction* current = instructionsBegin + bytecodeOffset;
352 OpcodeID opcodeID = current[0].u.opcode;
353 extractStoredJumpTargetsForBytecodeOffset(this, vm()->interpreter, instructionsBegin, bytecodeOffset, [&](int32_t& relativeOffset) {
354 relativeOffset = rewriter.adjustJumpTarget(bytecodeOffset, bytecodeOffset + relativeOffset);
356 bytecodeOffset += opcodeLength(opcodeID);
359 // Then, exception handlers should be adjusted.
361 for (UnlinkedHandlerInfo& handler : m_rareData->m_exceptionHandlers) {
362 handler.target = rewriter.adjustAbsoluteOffset(handler.target);
363 handler.start = rewriter.adjustAbsoluteOffset(handler.start);
364 handler.end = rewriter.adjustAbsoluteOffset(handler.end);
367 for (size_t i = 0; i < m_rareData->m_opProfileControlFlowBytecodeOffsets.size(); ++i)
368 m_rareData->m_opProfileControlFlowBytecodeOffsets[i] = rewriter.adjustAbsoluteOffset(m_rareData->m_opProfileControlFlowBytecodeOffsets[i]);
370 if (!m_rareData->m_typeProfilerInfoMap.isEmpty()) {
371 HashMap<unsigned, RareData::TypeProfilerExpressionRange> adjustedTypeProfilerInfoMap;
372 for (auto& entry : m_rareData->m_typeProfilerInfoMap)
373 adjustedTypeProfilerInfoMap.set(rewriter.adjustAbsoluteOffset(entry.key), entry.value);
374 m_rareData->m_typeProfilerInfoMap.swap(adjustedTypeProfilerInfoMap);
378 for (size_t i = 0; i < m_propertyAccessInstructions.size(); ++i)
379 m_propertyAccessInstructions[i] = rewriter.adjustAbsoluteOffset(m_propertyAccessInstructions[i]);
381 for (size_t i = 0; i < m_expressionInfo.size(); ++i)
382 m_expressionInfo[i].instructionOffset = rewriter.adjustAbsoluteOffset(m_expressionInfo[i].instructionOffset);
384 // Then, modify the unlinked instructions.
385 rewriter.applyModification();
387 // And recompute the jump target based on the modified unlinked instructions.
388 m_jumpTargets.clear();
389 recomputePreciseJumpTargets(this, graph.instructions().begin(), graph.instructions().size(), m_jumpTargets);
392 void UnlinkedCodeBlock::shrinkToFit()
394 auto locker = holdLock(*this);
396 m_jumpTargets.shrinkToFit();
397 m_identifiers.shrinkToFit();
398 m_bitVectors.shrinkToFit();
399 m_constantRegisters.shrinkToFit();
400 m_constantsSourceCodeRepresentation.shrinkToFit();
401 m_functionDecls.shrinkToFit();
402 m_functionExprs.shrinkToFit();
403 m_propertyAccessInstructions.shrinkToFit();
404 m_expressionInfo.shrinkToFit();
407 m_rareData->m_exceptionHandlers.shrinkToFit();
408 m_rareData->m_regexps.shrinkToFit();
409 m_rareData->m_constantBuffers.shrinkToFit();
410 m_rareData->m_switchJumpTables.shrinkToFit();
411 m_rareData->m_stringSwitchJumpTables.shrinkToFit();
412 m_rareData->m_expressionInfoFatPositions.shrinkToFit();
416 void UnlinkedCodeBlock::dump(PrintStream&) const