e8be1718d9597096b4c6e5beb687af2806fd2c69
[WebKit-https.git] / Source / JavaScriptCore / bytecode / UnlinkedCodeBlock.cpp
1 /*
2  * Copyright (C) 2012-2017 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", nullptr, nullptr, nullptr, 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_hasTailCalls(false)
74     , m_lineCount(0)
75     , m_endColumn(UINT_MAX)
76     , m_didOptimize(MixedTriState)
77     , m_parseMode(info.parseMode())
78     , m_features(0)
79     , m_codeType(codeType)
80     , m_arrayProfileCount(0)
81     , m_arrayAllocationProfileCount(0)
82     , m_objectAllocationProfileCount(0)
83     , m_valueProfileCount(0)
84     , m_llintCallLinkInfoCount(0)
85 {
86     for (auto& constantRegisterIndex : m_linkTimeConstants)
87         constantRegisterIndex = 0;
88     ASSERT(m_constructorKind == static_cast<unsigned>(info.constructorKind()));
89 }
90
91 void UnlinkedCodeBlock::visitChildren(JSCell* cell, SlotVisitor& visitor)
92 {
93     UnlinkedCodeBlock* thisObject = jsCast<UnlinkedCodeBlock*>(cell);
94     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
95     Base::visitChildren(thisObject, visitor);
96     auto locker = holdLock(*thisObject);
97     for (FunctionExpressionVector::iterator ptr = thisObject->m_functionDecls.begin(), end = thisObject->m_functionDecls.end(); ptr != end; ++ptr)
98         visitor.append(*ptr);
99     for (FunctionExpressionVector::iterator ptr = thisObject->m_functionExprs.begin(), end = thisObject->m_functionExprs.end(); ptr != end; ++ptr)
100         visitor.append(*ptr);
101     visitor.appendValues(thisObject->m_constantRegisters.data(), thisObject->m_constantRegisters.size());
102     if (thisObject->m_unlinkedInstructions)
103         visitor.reportExtraMemoryVisited(thisObject->m_unlinkedInstructions->sizeInBytes());
104     if (thisObject->m_rareData) {
105         for (size_t i = 0, end = thisObject->m_rareData->m_regexps.size(); i != end; i++)
106             visitor.append(thisObject->m_rareData->m_regexps[i]);
107     }
108 }
109
110 size_t UnlinkedCodeBlock::estimatedSize(JSCell* cell)
111 {
112     UnlinkedCodeBlock* thisObject = jsCast<UnlinkedCodeBlock*>(cell);
113     size_t extraSize = thisObject->m_unlinkedInstructions ? thisObject->m_unlinkedInstructions->sizeInBytes() : 0;
114     return Base::estimatedSize(cell) + extraSize;
115 }
116
117 int UnlinkedCodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset)
118 {
119     ASSERT(bytecodeOffset < instructions().count());
120     int divot;
121     int startOffset;
122     int endOffset;
123     unsigned line;
124     unsigned column;
125     expressionRangeForBytecodeOffset(bytecodeOffset, divot, startOffset, endOffset, line, column);
126     return line;
127 }
128
129 inline void UnlinkedCodeBlock::getLineAndColumn(const ExpressionRangeInfo& info,
130     unsigned& line, unsigned& column) const
131 {
132     switch (info.mode) {
133     case ExpressionRangeInfo::FatLineMode:
134         info.decodeFatLineMode(line, column);
135         break;
136     case ExpressionRangeInfo::FatColumnMode:
137         info.decodeFatColumnMode(line, column);
138         break;
139     case ExpressionRangeInfo::FatLineAndColumnMode: {
140         unsigned fatIndex = info.position;
141         ExpressionRangeInfo::FatPosition& fatPos = m_rareData->m_expressionInfoFatPositions[fatIndex];
142         line = fatPos.line;
143         column = fatPos.column;
144         break;
145     }
146     } // switch
147 }
148
149 #ifndef NDEBUG
150 static void dumpLineColumnEntry(size_t index, const UnlinkedInstructionStream& instructionStream, unsigned instructionOffset, unsigned line, unsigned column)
151 {
152     const auto& instructions = instructionStream.unpackForDebugging();
153     OpcodeID opcode = instructions[instructionOffset].u.opcode;
154     const char* event = "";
155     if (opcode == op_debug) {
156         switch (instructions[instructionOffset + 1].u.operand) {
157         case WillExecuteProgram: event = " WillExecuteProgram"; break;
158         case DidExecuteProgram: event = " DidExecuteProgram"; break;
159         case DidEnterCallFrame: event = " DidEnterCallFrame"; break;
160         case DidReachBreakpoint: event = " DidReachBreakpoint"; break;
161         case WillLeaveCallFrame: event = " WillLeaveCallFrame"; break;
162         case WillExecuteStatement: event = " WillExecuteStatement"; break;
163         case WillExecuteExpression: event = " WillExecuteExpression"; break;
164         }
165     }
166     dataLogF("  [%zu] pc %u @ line %u col %u : %s%s\n", index, instructionOffset, line, column, opcodeNames[opcode], event);
167 }
168
169 void UnlinkedCodeBlock::dumpExpressionRangeInfo()
170 {
171     Vector<ExpressionRangeInfo>& expressionInfo = m_expressionInfo;
172
173     size_t size = m_expressionInfo.size();
174     dataLogF("UnlinkedCodeBlock %p expressionRangeInfo[%zu] {\n", this, size);
175     for (size_t i = 0; i < size; i++) {
176         ExpressionRangeInfo& info = expressionInfo[i];
177         unsigned line;
178         unsigned column;
179         getLineAndColumn(info, line, column);
180         dumpLineColumnEntry(i, instructions(), info.instructionOffset, line, column);
181     }
182     dataLog("}\n");
183 }
184 #endif
185
186 void UnlinkedCodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset,
187     int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column) const
188 {
189     ASSERT(bytecodeOffset < instructions().count());
190
191     if (!m_expressionInfo.size()) {
192         startOffset = 0;
193         endOffset = 0;
194         divot = 0;
195         line = 0;
196         column = 0;
197         return;
198     }
199
200     const Vector<ExpressionRangeInfo>& expressionInfo = m_expressionInfo;
201
202     int low = 0;
203     int high = expressionInfo.size();
204     while (low < high) {
205         int mid = low + (high - low) / 2;
206         if (expressionInfo[mid].instructionOffset <= bytecodeOffset)
207             low = mid + 1;
208         else
209             high = mid;
210     }
211
212     if (!low)
213         low = 1;
214
215     const ExpressionRangeInfo& info = expressionInfo[low - 1];
216     startOffset = info.startOffset;
217     endOffset = info.endOffset;
218     divot = info.divotPoint;
219     getLineAndColumn(info, line, column);
220 }
221
222 void UnlinkedCodeBlock::addExpressionInfo(unsigned instructionOffset,
223     int divot, int startOffset, int endOffset, unsigned line, unsigned column)
224 {
225     if (divot > ExpressionRangeInfo::MaxDivot) {
226         // Overflow has occurred, we can only give line number info for errors for this region
227         divot = 0;
228         startOffset = 0;
229         endOffset = 0;
230     } else if (startOffset > ExpressionRangeInfo::MaxOffset) {
231         // If the start offset is out of bounds we clear both offsets
232         // so we only get the divot marker. Error message will have to be reduced
233         // to line and charPosition number.
234         startOffset = 0;
235         endOffset = 0;
236     } else if (endOffset > ExpressionRangeInfo::MaxOffset) {
237         // The end offset is only used for additional context, and is much more likely
238         // to overflow (eg. function call arguments) so we are willing to drop it without
239         // dropping the rest of the range.
240         endOffset = 0;
241     }
242
243     unsigned positionMode =
244         (line <= ExpressionRangeInfo::MaxFatLineModeLine && column <= ExpressionRangeInfo::MaxFatLineModeColumn) 
245         ? ExpressionRangeInfo::FatLineMode
246         : (line <= ExpressionRangeInfo::MaxFatColumnModeLine && column <= ExpressionRangeInfo::MaxFatColumnModeColumn)
247         ? ExpressionRangeInfo::FatColumnMode
248         : ExpressionRangeInfo::FatLineAndColumnMode;
249
250     ExpressionRangeInfo info;
251     info.instructionOffset = instructionOffset;
252     info.divotPoint = divot;
253     info.startOffset = startOffset;
254     info.endOffset = endOffset;
255
256     info.mode = positionMode;
257     switch (positionMode) {
258     case ExpressionRangeInfo::FatLineMode:
259         info.encodeFatLineMode(line, column);
260         break;
261     case ExpressionRangeInfo::FatColumnMode:
262         info.encodeFatColumnMode(line, column);
263         break;
264     case ExpressionRangeInfo::FatLineAndColumnMode: {
265         createRareDataIfNecessary();
266         unsigned fatIndex = m_rareData->m_expressionInfoFatPositions.size();
267         ExpressionRangeInfo::FatPosition fatPos = { line, column };
268         m_rareData->m_expressionInfoFatPositions.append(fatPos);
269         info.position = fatIndex;
270     }
271     } // switch
272
273     m_expressionInfo.append(info);
274 }
275
276 bool UnlinkedCodeBlock::typeProfilerExpressionInfoForBytecodeOffset(unsigned bytecodeOffset, unsigned& startDivot, unsigned& endDivot)
277 {
278     static const bool verbose = false;
279     if (!m_rareData) {
280         if (verbose)
281             dataLogF("Don't have assignment info for offset:%u\n", bytecodeOffset);
282         startDivot = UINT_MAX;
283         endDivot = UINT_MAX;
284         return false;
285     }
286
287     auto iter = m_rareData->m_typeProfilerInfoMap.find(bytecodeOffset);
288     if (iter == m_rareData->m_typeProfilerInfoMap.end()) {
289         if (verbose)
290             dataLogF("Don't have assignment info for offset:%u\n", bytecodeOffset);
291         startDivot = UINT_MAX;
292         endDivot = UINT_MAX;
293         return false;
294     }
295     
296     RareData::TypeProfilerExpressionRange& range = iter->value;
297     startDivot = range.m_startDivot;
298     endDivot = range.m_endDivot;
299     return true;
300 }
301
302 void UnlinkedCodeBlock::addTypeProfilerExpressionInfo(unsigned instructionOffset, unsigned startDivot, unsigned endDivot)
303 {
304     createRareDataIfNecessary();
305     RareData::TypeProfilerExpressionRange range;
306     range.m_startDivot = startDivot;
307     range.m_endDivot = endDivot;
308     m_rareData->m_typeProfilerInfoMap.set(instructionOffset, range);
309 }
310
311 UnlinkedCodeBlock::~UnlinkedCodeBlock()
312 {
313 }
314
315 void UnlinkedCodeBlock::setInstructions(std::unique_ptr<UnlinkedInstructionStream> instructions)
316 {
317     ASSERT(instructions);
318     {
319         auto locker = holdLock(*this);
320         m_unlinkedInstructions = WTFMove(instructions);
321     }
322     Heap::heap(this)->reportExtraMemoryAllocated(m_unlinkedInstructions->sizeInBytes());
323 }
324
325 const UnlinkedInstructionStream& UnlinkedCodeBlock::instructions() const
326 {
327     ASSERT(m_unlinkedInstructions.get());
328     return *m_unlinkedInstructions;
329 }
330
331 UnlinkedHandlerInfo* UnlinkedCodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset, RequiredHandler requiredHandler)
332 {
333     return handlerForIndex(bytecodeOffset, requiredHandler);
334 }
335
336 UnlinkedHandlerInfo* UnlinkedCodeBlock::handlerForIndex(unsigned index, RequiredHandler requiredHandler)
337 {
338     if (!m_rareData)
339         return nullptr;
340     return UnlinkedHandlerInfo::handlerForIndex(m_rareData->m_exceptionHandlers, index, requiredHandler);
341 }
342
343 void UnlinkedCodeBlock::applyModification(BytecodeRewriter& rewriter)
344 {
345     // Before applying the changes, we adjust the jumps based on the original bytecode offset, the offset to the jump target, and
346     // the insertion information.
347
348     BytecodeGraph<UnlinkedCodeBlock>& graph = rewriter.graph();
349     UnlinkedInstruction* instructionsBegin = graph.instructions().begin();
350
351     for (int bytecodeOffset = 0, instructionCount = graph.instructions().size(); bytecodeOffset < instructionCount;) {
352         UnlinkedInstruction* current = instructionsBegin + bytecodeOffset;
353         OpcodeID opcodeID = current[0].u.opcode;
354         extractStoredJumpTargetsForBytecodeOffset(this, instructionsBegin, bytecodeOffset, [&](int32_t& relativeOffset) {
355             relativeOffset = rewriter.adjustJumpTarget(bytecodeOffset, bytecodeOffset + relativeOffset);
356         });
357         bytecodeOffset += opcodeLength(opcodeID);
358     }
359
360     // Then, exception handlers should be adjusted.
361     if (m_rareData) {
362         for (UnlinkedHandlerInfo& handler : m_rareData->m_exceptionHandlers) {
363             handler.target = rewriter.adjustAbsoluteOffset(handler.target);
364             handler.start = rewriter.adjustAbsoluteOffset(handler.start);
365             handler.end = rewriter.adjustAbsoluteOffset(handler.end);
366         }
367
368         for (size_t i = 0; i < m_rareData->m_opProfileControlFlowBytecodeOffsets.size(); ++i)
369             m_rareData->m_opProfileControlFlowBytecodeOffsets[i] = rewriter.adjustAbsoluteOffset(m_rareData->m_opProfileControlFlowBytecodeOffsets[i]);
370
371         if (!m_rareData->m_typeProfilerInfoMap.isEmpty()) {
372             HashMap<unsigned, RareData::TypeProfilerExpressionRange> adjustedTypeProfilerInfoMap;
373             for (auto& entry : m_rareData->m_typeProfilerInfoMap)
374                 adjustedTypeProfilerInfoMap.set(rewriter.adjustAbsoluteOffset(entry.key), entry.value);
375             m_rareData->m_typeProfilerInfoMap.swap(adjustedTypeProfilerInfoMap);
376         }
377     }
378
379     for (size_t i = 0; i < m_propertyAccessInstructions.size(); ++i)
380         m_propertyAccessInstructions[i] = rewriter.adjustAbsoluteOffset(m_propertyAccessInstructions[i]);
381
382     for (size_t i = 0; i < m_expressionInfo.size(); ++i)
383         m_expressionInfo[i].instructionOffset = rewriter.adjustAbsoluteOffset(m_expressionInfo[i].instructionOffset);
384
385     // Then, modify the unlinked instructions.
386     rewriter.applyModification();
387
388     // And recompute the jump target based on the modified unlinked instructions.
389     m_jumpTargets.clear();
390     recomputePreciseJumpTargets(this, graph.instructions().begin(), graph.instructions().size(), m_jumpTargets);
391 }
392
393 void UnlinkedCodeBlock::shrinkToFit()
394 {
395     auto locker = holdLock(*this);
396     
397     m_jumpTargets.shrinkToFit();
398     m_identifiers.shrinkToFit();
399     m_bitVectors.shrinkToFit();
400     m_constantRegisters.shrinkToFit();
401     m_constantsSourceCodeRepresentation.shrinkToFit();
402     m_functionDecls.shrinkToFit();
403     m_functionExprs.shrinkToFit();
404     m_propertyAccessInstructions.shrinkToFit();
405     m_expressionInfo.shrinkToFit();
406
407     if (m_rareData) {
408         m_rareData->m_exceptionHandlers.shrinkToFit();
409         m_rareData->m_regexps.shrinkToFit();
410         m_rareData->m_constantBuffers.shrinkToFit();
411         m_rareData->m_switchJumpTables.shrinkToFit();
412         m_rareData->m_stringSwitchJumpTables.shrinkToFit();
413         m_rareData->m_expressionInfoFatPositions.shrinkToFit();
414         m_rareData->m_opProfileControlFlowBytecodeOffsets.shrinkToFit();
415     }
416 }
417
418 void UnlinkedCodeBlock::dump(PrintStream&) const
419 {
420 }
421
422 } // namespace JSC