912aad13e76cb7b1afa8099ed0dd392de5f80ff3
[WebKit-https.git] / Source / JavaScriptCore / bytecode / UnlinkedCodeBlock.cpp
1 /*
2  * Copyright (C) 2012-2013, 2015-2016 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 "BytecodeRewriter.h"
32 #include "ClassInfo.h"
33 #include "CodeCache.h"
34 #include "ExecutableInfo.h"
35 #include "FunctionOverrides.h"
36 #include "JSCInlines.h"
37 #include "JSString.h"
38 #include "Parser.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>
49
50 namespace JSC {
51
52 const ClassInfo UnlinkedCodeBlock::s_info = { "UnlinkedCodeBlock", 0, 0, CREATE_METHOD_TABLE(UnlinkedCodeBlock) };
53
54 UnlinkedCodeBlock::UnlinkedCodeBlock(VM* vm, Structure* structure, CodeType codeType, const ExecutableInfo& info, DebuggerMode debuggerMode)
55     : Base(*vm, structure)
56     , m_numVars(0)
57     , m_numCalleeLocals(0)
58     , m_numParameters(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()))
73     , m_lineCount(0)
74     , m_endColumn(UINT_MAX)
75     , m_didOptimize(MixedTriState)
76     , m_parseMode(info.parseMode())
77     , m_features(0)
78     , m_codeType(codeType)
79     , m_arrayProfileCount(0)
80     , m_arrayAllocationProfileCount(0)
81     , m_objectAllocationProfileCount(0)
82     , m_valueProfileCount(0)
83     , m_llintCallLinkInfoCount(0)
84 {
85     for (auto& constantRegisterIndex : m_linkTimeConstants)
86         constantRegisterIndex = 0;
87     ASSERT(m_constructorKind == static_cast<unsigned>(info.constructorKind()));
88 }
89
90 void UnlinkedCodeBlock::visitChildren(JSCell* cell, SlotVisitor& visitor)
91 {
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)
97         visitor.append(ptr);
98     for (FunctionExpressionVector::iterator ptr = thisObject->m_functionExprs.begin(), end = thisObject->m_functionExprs.end(); ptr != end; ++ptr)
99         visitor.append(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]);
106     }
107 }
108
109 size_t UnlinkedCodeBlock::estimatedSize(JSCell* cell)
110 {
111     UnlinkedCodeBlock* thisObject = jsCast<UnlinkedCodeBlock*>(cell);
112     size_t extraSize = thisObject->m_unlinkedInstructions ? thisObject->m_unlinkedInstructions->sizeInBytes() : 0;
113     return Base::estimatedSize(cell) + extraSize;
114 }
115
116 int UnlinkedCodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset)
117 {
118     ASSERT(bytecodeOffset < instructions().count());
119     int divot;
120     int startOffset;
121     int endOffset;
122     unsigned line;
123     unsigned column;
124     expressionRangeForBytecodeOffset(bytecodeOffset, divot, startOffset, endOffset, line, column);
125     return line;
126 }
127
128 inline void UnlinkedCodeBlock::getLineAndColumn(const ExpressionRangeInfo& info,
129     unsigned& line, unsigned& column) const
130 {
131     switch (info.mode) {
132     case ExpressionRangeInfo::FatLineMode:
133         info.decodeFatLineMode(line, column);
134         break;
135     case ExpressionRangeInfo::FatColumnMode:
136         info.decodeFatColumnMode(line, column);
137         break;
138     case ExpressionRangeInfo::FatLineAndColumnMode: {
139         unsigned fatIndex = info.position;
140         ExpressionRangeInfo::FatPosition& fatPos = m_rareData->m_expressionInfoFatPositions[fatIndex];
141         line = fatPos.line;
142         column = fatPos.column;
143         break;
144     }
145     } // switch
146 }
147
148 #ifndef NDEBUG
149 static void dumpLineColumnEntry(size_t index, const UnlinkedInstructionStream& instructionStream, unsigned instructionOffset, unsigned line, unsigned column)
150 {
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;
163         }
164     }
165     dataLogF("  [%zu] pc %u @ line %u col %u : %s%s\n", index, instructionOffset, line, column, opcodeNames[opcode], event);
166 }
167
168 void UnlinkedCodeBlock::dumpExpressionRangeInfo()
169 {
170     Vector<ExpressionRangeInfo>& expressionInfo = m_expressionInfo;
171
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];
176         unsigned line;
177         unsigned column;
178         getLineAndColumn(info, line, column);
179         dumpLineColumnEntry(i, instructions(), info.instructionOffset, line, column);
180     }
181     dataLog("}\n");
182 }
183 #endif
184
185 void UnlinkedCodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset,
186     int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column) const
187 {
188     ASSERT(bytecodeOffset < instructions().count());
189
190     if (!m_expressionInfo.size()) {
191         startOffset = 0;
192         endOffset = 0;
193         divot = 0;
194         line = 0;
195         column = 0;
196         return;
197     }
198
199     const Vector<ExpressionRangeInfo>& expressionInfo = m_expressionInfo;
200
201     int low = 0;
202     int high = expressionInfo.size();
203     while (low < high) {
204         int mid = low + (high - low) / 2;
205         if (expressionInfo[mid].instructionOffset <= bytecodeOffset)
206             low = mid + 1;
207         else
208             high = mid;
209     }
210
211     if (!low)
212         low = 1;
213
214     const ExpressionRangeInfo& info = expressionInfo[low - 1];
215     startOffset = info.startOffset;
216     endOffset = info.endOffset;
217     divot = info.divotPoint;
218     getLineAndColumn(info, line, column);
219 }
220
221 void UnlinkedCodeBlock::addExpressionInfo(unsigned instructionOffset,
222     int divot, int startOffset, int endOffset, unsigned line, unsigned column)
223 {
224     if (divot > ExpressionRangeInfo::MaxDivot) {
225         // Overflow has occurred, we can only give line number info for errors for this region
226         divot = 0;
227         startOffset = 0;
228         endOffset = 0;
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.
233         startOffset = 0;
234         endOffset = 0;
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.
239         endOffset = 0;
240     }
241
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;
248
249     ExpressionRangeInfo info;
250     info.instructionOffset = instructionOffset;
251     info.divotPoint = divot;
252     info.startOffset = startOffset;
253     info.endOffset = endOffset;
254
255     info.mode = positionMode;
256     switch (positionMode) {
257     case ExpressionRangeInfo::FatLineMode:
258         info.encodeFatLineMode(line, column);
259         break;
260     case ExpressionRangeInfo::FatColumnMode:
261         info.encodeFatColumnMode(line, column);
262         break;
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;
269     }
270     } // switch
271
272     m_expressionInfo.append(info);
273 }
274
275 bool UnlinkedCodeBlock::typeProfilerExpressionInfoForBytecodeOffset(unsigned bytecodeOffset, unsigned& startDivot, unsigned& endDivot)
276 {
277     static const bool verbose = false;
278     if (!m_rareData) {
279         if (verbose)
280             dataLogF("Don't have assignment info for offset:%u\n", bytecodeOffset);
281         startDivot = UINT_MAX;
282         endDivot = UINT_MAX;
283         return false;
284     }
285
286     auto iter = m_rareData->m_typeProfilerInfoMap.find(bytecodeOffset);
287     if (iter == m_rareData->m_typeProfilerInfoMap.end()) {
288         if (verbose)
289             dataLogF("Don't have assignment info for offset:%u\n", bytecodeOffset);
290         startDivot = UINT_MAX;
291         endDivot = UINT_MAX;
292         return false;
293     }
294     
295     RareData::TypeProfilerExpressionRange& range = iter->value;
296     startDivot = range.m_startDivot;
297     endDivot = range.m_endDivot;
298     return true;
299 }
300
301 void UnlinkedCodeBlock::addTypeProfilerExpressionInfo(unsigned instructionOffset, unsigned startDivot, unsigned endDivot)
302 {
303     createRareDataIfNecessary();
304     RareData::TypeProfilerExpressionRange range;
305     range.m_startDivot = startDivot;
306     range.m_endDivot = endDivot;
307     m_rareData->m_typeProfilerInfoMap.set(instructionOffset, range);
308 }
309
310 UnlinkedCodeBlock::~UnlinkedCodeBlock()
311 {
312 }
313
314 void UnlinkedCodeBlock::setInstructions(std::unique_ptr<UnlinkedInstructionStream> instructions)
315 {
316     ASSERT(instructions);
317     {
318         auto locker = holdLock(*this);
319         m_unlinkedInstructions = WTFMove(instructions);
320     }
321     Heap::heap(this)->reportExtraMemoryAllocated(m_unlinkedInstructions->sizeInBytes());
322 }
323
324 const UnlinkedInstructionStream& UnlinkedCodeBlock::instructions() const
325 {
326     ASSERT(m_unlinkedInstructions.get());
327     return *m_unlinkedInstructions;
328 }
329
330 UnlinkedHandlerInfo* UnlinkedCodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset, RequiredHandler requiredHandler)
331 {
332     return handlerForIndex(bytecodeOffset, requiredHandler);
333 }
334
335 UnlinkedHandlerInfo* UnlinkedCodeBlock::handlerForIndex(unsigned index, RequiredHandler requiredHandler)
336 {
337     if (!m_rareData)
338         return nullptr;
339     return UnlinkedHandlerInfo::handlerForIndex(m_rareData->m_exceptionHandlers, index, requiredHandler);
340 }
341
342 void UnlinkedCodeBlock::applyModification(BytecodeRewriter& rewriter)
343 {
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.
346
347     BytecodeGraph<UnlinkedCodeBlock>& graph = rewriter.graph();
348     UnlinkedInstruction* instructionsBegin = graph.instructions().begin();
349
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);
355         });
356         bytecodeOffset += opcodeLength(opcodeID);
357     }
358
359     // Then, exception handlers should be adjusted.
360     if (m_rareData) {
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);
365         }
366
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]);
369
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);
375         }
376     }
377
378     for (size_t i = 0; i < m_propertyAccessInstructions.size(); ++i)
379         m_propertyAccessInstructions[i] = rewriter.adjustAbsoluteOffset(m_propertyAccessInstructions[i]);
380
381     for (size_t i = 0; i < m_expressionInfo.size(); ++i)
382         m_expressionInfo[i].instructionOffset = rewriter.adjustAbsoluteOffset(m_expressionInfo[i].instructionOffset);
383
384     // Then, modify the unlinked instructions.
385     rewriter.applyModification();
386
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);
390 }
391
392 void UnlinkedCodeBlock::shrinkToFit()
393 {
394     auto locker = holdLock(*this);
395     
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();
405
406     if (m_rareData) {
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();
413     }
414 }
415
416 } // namespace JSC