1/*
2 * Copyright (C) 2012-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#pragma once
27
28#include "BytecodeConventions.h"
29#include "CodeType.h"
30#include "DFGExitProfile.h"
31#include "ExpressionRangeInfo.h"
32#include "HandlerInfo.h"
33#include "Identifier.h"
34#include "InstructionStream.h"
35#include "JSCast.h"
36#include "LockDuringMarking.h"
37#include "Opcode.h"
38#include "ParserModes.h"
39#include "RegExp.h"
40#include "SpecialPointer.h"
41#include "UnlinkedFunctionExecutable.h"
42#include "UnlinkedMetadataTable.h"
43#include "VirtualRegister.h"
44#include <algorithm>
45#include <wtf/BitVector.h>
46#include <wtf/HashSet.h>
47#include <wtf/TriState.h>
48#include <wtf/Vector.h>
49#include <wtf/text/UniquedStringImpl.h>
50
51namespace JSC {
52
53class BytecodeGenerator;
54class BytecodeLivenessAnalysis;
55class BytecodeRewriter;
56class CodeBlock;
57class Debugger;
58class FunctionExecutable;
59class ParserError;
60class ScriptExecutable;
61class SourceCode;
62class SourceProvider;
63class UnlinkedCodeBlock;
64class UnlinkedFunctionCodeBlock;
65class UnlinkedFunctionExecutable;
66struct ExecutableInfo;
67
68template<typename CodeBlockType>
69class CachedCodeBlock;
70
71typedef unsigned UnlinkedValueProfile;
72typedef unsigned UnlinkedArrayProfile;
73typedef unsigned UnlinkedArrayAllocationProfile;
74typedef unsigned UnlinkedObjectAllocationProfile;
75typedef unsigned UnlinkedLLIntCallLinkInfo;
76using ConstantIdentifierSetEntry = std::pair<IdentifierSet, unsigned>;
77
78struct UnlinkedStringJumpTable {
79 struct OffsetLocation {
80 int32_t branchOffset;
81 };
82
83 typedef HashMap<RefPtr<StringImpl>, OffsetLocation> StringOffsetTable;
84 StringOffsetTable offsetTable;
85
86 inline int32_t offsetForValue(StringImpl* value, int32_t defaultOffset)
87 {
88 StringOffsetTable::const_iterator end = offsetTable.end();
89 StringOffsetTable::const_iterator loc = offsetTable.find(value);
90 if (loc == end)
91 return defaultOffset;
92 return loc->value.branchOffset;
93 }
94
95};
96
97struct UnlinkedSimpleJumpTable {
98 Vector<int32_t> branchOffsets;
99 int32_t min;
100
101 int32_t offsetForValue(int32_t value, int32_t defaultOffset);
102 void add(int32_t key, int32_t offset)
103 {
104 if (!branchOffsets[key])
105 branchOffsets[key] = offset;
106 }
107};
108
109class UnlinkedCodeBlock : public JSCell {
110public:
111 typedef JSCell Base;
112 static const unsigned StructureFlags = Base::StructureFlags;
113
114 static const bool needsDestruction = true;
115
116 enum { CallFunction, ApplyFunction };
117
118 bool isConstructor() const { return m_isConstructor; }
119 bool isStrictMode() const { return m_isStrictMode; }
120 bool usesEval() const { return m_usesEval; }
121 SourceParseMode parseMode() const { return m_parseMode; }
122 bool isArrowFunction() const { return isArrowFunctionParseMode(parseMode()); }
123 DerivedContextType derivedContextType() const { return static_cast<DerivedContextType>(m_derivedContextType); }
124 EvalContextType evalContextType() const { return static_cast<EvalContextType>(m_evalContextType); }
125 bool isArrowFunctionContext() const { return m_isArrowFunctionContext; }
126 bool isClassContext() const { return m_isClassContext; }
127 bool hasTailCalls() const { return m_hasTailCalls; }
128 void setHasTailCalls() { m_hasTailCalls = true; }
129 bool allowDirectEvalCache() const { return !(m_features & NoEvalCacheFeature); }
130
131 void addExpressionInfo(unsigned instructionOffset, int divot,
132 int startOffset, int endOffset, unsigned line, unsigned column);
133
134 void addTypeProfilerExpressionInfo(unsigned instructionOffset, unsigned startDivot, unsigned endDivot);
135
136 bool hasExpressionInfo() { return m_expressionInfo.size(); }
137 const Vector<ExpressionRangeInfo>& expressionInfo() { return m_expressionInfo; }
138
139 // Special registers
140 void setThisRegister(VirtualRegister thisRegister) { m_thisRegister = thisRegister; }
141 void setScopeRegister(VirtualRegister scopeRegister) { m_scopeRegister = scopeRegister; }
142
143 // Parameter information
144 void setNumParameters(int newValue) { m_numParameters = newValue; }
145 void addParameter() { m_numParameters++; }
146 unsigned numParameters() const { return m_numParameters; }
147
148 // Constant Pools
149
150 size_t numberOfIdentifiers() const { return m_identifiers.size(); }
151 void addIdentifier(const Identifier& i) { return m_identifiers.append(i); }
152 const Identifier& identifier(int index) const { return m_identifiers[index]; }
153 const Vector<Identifier>& identifiers() const { return m_identifiers; }
154
155 BitVector& bitVector(size_t i) { ASSERT(m_rareData); return m_rareData->m_bitVectors[i]; }
156 unsigned addBitVector(BitVector&& bitVector)
157 {
158 createRareDataIfNecessary();
159 m_rareData->m_bitVectors.append(WTFMove(bitVector));
160 return m_rareData->m_bitVectors.size() - 1;
161 }
162
163 void addSetConstant(IdentifierSet& set)
164 {
165 createRareDataIfNecessary();
166 VM& vm = *this->vm();
167 auto locker = lockDuringMarking(vm.heap, cellLock());
168 unsigned result = m_constantRegisters.size();
169 m_constantRegisters.append(WriteBarrier<Unknown>());
170 m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other);
171 m_rareData->m_constantIdentifierSets.append(ConstantIdentifierSetEntry(set, result));
172 }
173
174 unsigned addConstant(JSValue v, SourceCodeRepresentation sourceCodeRepresentation = SourceCodeRepresentation::Other)
175 {
176 VM& vm = *this->vm();
177 auto locker = lockDuringMarking(vm.heap, cellLock());
178 unsigned result = m_constantRegisters.size();
179 m_constantRegisters.append(WriteBarrier<Unknown>());
180 m_constantRegisters.last().set(vm, this, v);
181 m_constantsSourceCodeRepresentation.append(sourceCodeRepresentation);
182 return result;
183 }
184 unsigned addConstant(LinkTimeConstant type)
185 {
186 VM& vm = *this->vm();
187 auto locker = lockDuringMarking(vm.heap, cellLock());
188 unsigned result = m_constantRegisters.size();
189 ASSERT(result);
190 unsigned index = static_cast<unsigned>(type);
191 ASSERT(index < LinkTimeConstantCount);
192 m_linkTimeConstants[index] = result;
193 m_constantRegisters.append(WriteBarrier<Unknown>());
194 m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other);
195 return result;
196 }
197
198 unsigned registerIndexForLinkTimeConstant(LinkTimeConstant type)
199 {
200 unsigned index = static_cast<unsigned>(type);
201 ASSERT(index < LinkTimeConstantCount);
202 return m_linkTimeConstants[index];
203 }
204
205 const Vector<WriteBarrier<Unknown>>& constantRegisters() { return m_constantRegisters; }
206 const WriteBarrier<Unknown>& constantRegister(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex]; }
207 ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; }
208 ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].get(); }
209 const Vector<SourceCodeRepresentation>& constantsSourceCodeRepresentation() { return m_constantsSourceCodeRepresentation; }
210
211 unsigned numberOfConstantIdentifierSets() const { return m_rareData ? m_rareData->m_constantIdentifierSets.size() : 0; }
212 const Vector<ConstantIdentifierSetEntry>& constantIdentifierSets() { ASSERT(m_rareData); return m_rareData->m_constantIdentifierSets; }
213
214 // Jumps
215 size_t numberOfJumpTargets() const { return m_jumpTargets.size(); }
216 void addJumpTarget(unsigned jumpTarget) { m_jumpTargets.append(jumpTarget); }
217 unsigned jumpTarget(int index) const { return m_jumpTargets[index]; }
218 unsigned lastJumpTarget() const { return m_jumpTargets.last(); }
219
220 UnlinkedHandlerInfo* handlerForBytecodeOffset(unsigned bytecodeOffset, RequiredHandler = RequiredHandler::AnyHandler);
221 UnlinkedHandlerInfo* handlerForIndex(unsigned, RequiredHandler = RequiredHandler::AnyHandler);
222
223 bool isBuiltinFunction() const { return m_isBuiltinFunction; }
224
225 ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); }
226 SuperBinding superBinding() const { return static_cast<SuperBinding>(m_superBinding); }
227 JSParserScriptMode scriptMode() const { return static_cast<JSParserScriptMode>(m_scriptMode); }
228
229 void shrinkToFit();
230
231 void setInstructions(std::unique_ptr<InstructionStream>);
232 const InstructionStream& instructions() const;
233
234 int numCalleeLocals() const { return m_numCalleeLocals; }
235 int numVars() const { return m_numVars; }
236
237 // Jump Tables
238
239 size_t numberOfSwitchJumpTables() const { return m_rareData ? m_rareData->m_switchJumpTables.size() : 0; }
240 UnlinkedSimpleJumpTable& addSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_switchJumpTables.append(UnlinkedSimpleJumpTable()); return m_rareData->m_switchJumpTables.last(); }
241 UnlinkedSimpleJumpTable& switchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_switchJumpTables[tableIndex]; }
242
243 size_t numberOfStringSwitchJumpTables() const { return m_rareData ? m_rareData->m_stringSwitchJumpTables.size() : 0; }
244 UnlinkedStringJumpTable& addStringSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_stringSwitchJumpTables.append(UnlinkedStringJumpTable()); return m_rareData->m_stringSwitchJumpTables.last(); }
245 UnlinkedStringJumpTable& stringSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_stringSwitchJumpTables[tableIndex]; }
246
247 unsigned addFunctionDecl(UnlinkedFunctionExecutable* n)
248 {
249 VM& vm = *this->vm();
250 auto locker = lockDuringMarking(vm.heap, cellLock());
251 unsigned size = m_functionDecls.size();
252 m_functionDecls.append(WriteBarrier<UnlinkedFunctionExecutable>());
253 m_functionDecls.last().set(vm, this, n);
254 return size;
255 }
256 UnlinkedFunctionExecutable* functionDecl(int index) { return m_functionDecls[index].get(); }
257 size_t numberOfFunctionDecls() { return m_functionDecls.size(); }
258 unsigned addFunctionExpr(UnlinkedFunctionExecutable* n)
259 {
260 VM& vm = *this->vm();
261 auto locker = lockDuringMarking(vm.heap, cellLock());
262 unsigned size = m_functionExprs.size();
263 m_functionExprs.append(WriteBarrier<UnlinkedFunctionExecutable>());
264 m_functionExprs.last().set(vm, this, n);
265 return size;
266 }
267 UnlinkedFunctionExecutable* functionExpr(int index) { return m_functionExprs[index].get(); }
268 size_t numberOfFunctionExprs() { return m_functionExprs.size(); }
269
270 // Exception handling support
271 size_t numberOfExceptionHandlers() const { return m_rareData ? m_rareData->m_exceptionHandlers.size() : 0; }
272 void addExceptionHandler(const UnlinkedHandlerInfo& handler) { createRareDataIfNecessary(); return m_rareData->m_exceptionHandlers.append(handler); }
273 UnlinkedHandlerInfo& exceptionHandler(int index) { ASSERT(m_rareData); return m_rareData->m_exceptionHandlers[index]; }
274
275 CodeType codeType() const { return static_cast<CodeType>(m_codeType); }
276
277 VirtualRegister thisRegister() const { return m_thisRegister; }
278 VirtualRegister scopeRegister() const { return m_scopeRegister; }
279
280 void addPropertyAccessInstruction(InstructionStream::Offset propertyAccessInstruction)
281 {
282 m_propertyAccessInstructions.append(propertyAccessInstruction);
283 }
284
285 size_t numberOfPropertyAccessInstructions() const { return m_propertyAccessInstructions.size(); }
286 const Vector<InstructionStream::Offset>& propertyAccessInstructions() const { return m_propertyAccessInstructions; }
287
288 bool hasRareData() const { return m_rareData.get(); }
289
290 int lineNumberForBytecodeOffset(unsigned bytecodeOffset);
291
292 void expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& divot,
293 int& startOffset, int& endOffset, unsigned& line, unsigned& column) const;
294
295 bool typeProfilerExpressionInfoForBytecodeOffset(unsigned bytecodeOffset, unsigned& startDivot, unsigned& endDivot);
296
297 void recordParse(CodeFeatures features, bool hasCapturedVariables, unsigned lineCount, unsigned endColumn)
298 {
299 m_features = features;
300 m_hasCapturedVariables = hasCapturedVariables;
301 m_lineCount = lineCount;
302 // For the UnlinkedCodeBlock, startColumn is always 0.
303 m_endColumn = endColumn;
304 }
305
306 const String& sourceURLDirective() const { return m_sourceURLDirective; }
307 const String& sourceMappingURLDirective() const { return m_sourceMappingURLDirective; }
308 void setSourceURLDirective(const String& sourceURL) { m_sourceURLDirective = sourceURL; }
309 void setSourceMappingURLDirective(const String& sourceMappingURL) { m_sourceMappingURLDirective = sourceMappingURL; }
310
311 CodeFeatures codeFeatures() const { return m_features; }
312 bool hasCapturedVariables() const { return m_hasCapturedVariables; }
313 unsigned lineCount() const { return m_lineCount; }
314 ALWAYS_INLINE unsigned startColumn() const { return 0; }
315 unsigned endColumn() const { return m_endColumn; }
316
317 void addOpProfileControlFlowBytecodeOffset(InstructionStream::Offset offset)
318 {
319 createRareDataIfNecessary();
320 m_rareData->m_opProfileControlFlowBytecodeOffsets.append(offset);
321 }
322 const Vector<InstructionStream::Offset>& opProfileControlFlowBytecodeOffsets() const
323 {
324 ASSERT(m_rareData);
325 return m_rareData->m_opProfileControlFlowBytecodeOffsets;
326 }
327 bool hasOpProfileControlFlowBytecodeOffsets() const
328 {
329 return m_rareData && !m_rareData->m_opProfileControlFlowBytecodeOffsets.isEmpty();
330 }
331
332 void dumpExpressionRangeInfo(); // For debugging purpose only.
333
334 bool wasCompiledWithDebuggingOpcodes() const { return m_codeGenerationMode.contains(CodeGenerationMode::Debugger); }
335 bool wasCompiledWithTypeProfilerOpcodes() const { return m_codeGenerationMode.contains(CodeGenerationMode::TypeProfiler); }
336 bool wasCompiledWithControlFlowProfilerOpcodes() const { return m_codeGenerationMode.contains(CodeGenerationMode::ControlFlowProfiler); }
337 OptionSet<CodeGenerationMode> codeGenerationMode() const { return m_codeGenerationMode; }
338
339 TriState didOptimize() const { return static_cast<TriState>(m_didOptimize); }
340 void setDidOptimize(TriState didOptimize) { m_didOptimize = static_cast<unsigned>(didOptimize); }
341
342 static constexpr unsigned maxAge = 7;
343
344 unsigned age() const { return m_age; }
345 void resetAge() { m_age = 0; }
346
347 void dump(PrintStream&) const;
348
349 BytecodeLivenessAnalysis& livenessAnalysis(CodeBlock* codeBlock)
350 {
351 if (m_liveness)
352 return *m_liveness;
353 return livenessAnalysisSlow(codeBlock);
354 }
355
356#if ENABLE(DFG_JIT)
357 bool hasExitSite(const ConcurrentJSLocker& locker, const DFG::FrequentExitSite& site) const
358 {
359 return m_exitProfile.hasExitSite(locker, site);
360 }
361
362 bool hasExitSite(const DFG::FrequentExitSite& site)
363 {
364 ConcurrentJSLocker locker(m_lock);
365 return hasExitSite(locker, site);
366 }
367
368 DFG::ExitProfile& exitProfile() { return m_exitProfile; }
369#endif
370
371 UnlinkedMetadataTable& metadata() { return m_metadata.get(); }
372
373 size_t metadataSizeInBytes()
374 {
375 return m_metadata->sizeInBytes();
376 }
377
378
379protected:
380 UnlinkedCodeBlock(VM*, Structure*, CodeType, const ExecutableInfo&, OptionSet<CodeGenerationMode>);
381
382 template<typename CodeBlockType>
383 UnlinkedCodeBlock(Decoder&, Structure*, const CachedCodeBlock<CodeBlockType>&);
384
385 ~UnlinkedCodeBlock();
386
387 void finishCreation(VM& vm)
388 {
389 Base::finishCreation(vm);
390 }
391
392private:
393 friend class BytecodeRewriter;
394 friend class BytecodeGenerator;
395
396 template<typename CodeBlockType>
397 friend class CachedCodeBlock;
398
399 void applyModification(BytecodeRewriter&, InstructionStreamWriter&);
400
401 void createRareDataIfNecessary()
402 {
403 if (!m_rareData) {
404 auto locker = lockDuringMarking(*heap(), cellLock());
405 m_rareData = std::make_unique<RareData>();
406 }
407 }
408
409 void getLineAndColumn(const ExpressionRangeInfo&, unsigned& line, unsigned& column) const;
410 BytecodeLivenessAnalysis& livenessAnalysisSlow(CodeBlock*);
411
412
413 VirtualRegister m_thisRegister;
414 VirtualRegister m_scopeRegister;
415
416 std::array<unsigned, LinkTimeConstantCount> m_linkTimeConstants;
417
418 unsigned m_usesEval : 1;
419 unsigned m_isStrictMode : 1;
420 unsigned m_isConstructor : 1;
421 unsigned m_hasCapturedVariables : 1;
422 unsigned m_isBuiltinFunction : 1;
423 unsigned m_superBinding : 1;
424 unsigned m_scriptMode: 1;
425 unsigned m_isArrowFunctionContext : 1;
426 unsigned m_isClassContext : 1;
427 unsigned m_hasTailCalls : 1;
428 unsigned m_constructorKind : 2;
429 unsigned m_derivedContextType : 2;
430 unsigned m_evalContextType : 2;
431 unsigned m_codeType : 2;
432 unsigned m_didOptimize : 2;
433 unsigned m_age : 3;
434 static_assert(((1U << 3) - 1) >= maxAge);
435public:
436 ConcurrentJSLock m_lock;
437private:
438 CodeFeatures m_features { 0 };
439 SourceParseMode m_parseMode;
440 OptionSet<CodeGenerationMode> m_codeGenerationMode;
441
442 unsigned m_lineCount { 0 };
443 unsigned m_endColumn { UINT_MAX };
444
445 int m_numVars { 0 };
446 int m_numCalleeLocals { 0 };
447 int m_numParameters { 0 };
448
449 String m_sourceURLDirective;
450 String m_sourceMappingURLDirective;
451
452 Vector<InstructionStream::Offset> m_jumpTargets;
453 Ref<UnlinkedMetadataTable> m_metadata;
454 std::unique_ptr<InstructionStream> m_instructions;
455 std::unique_ptr<BytecodeLivenessAnalysis> m_liveness;
456
457
458#if ENABLE(DFG_JIT)
459 DFG::ExitProfile m_exitProfile;
460#endif
461
462
463 Vector<InstructionStream::Offset> m_propertyAccessInstructions;
464
465 // Constant Pools
466 Vector<Identifier> m_identifiers;
467 Vector<WriteBarrier<Unknown>> m_constantRegisters;
468 Vector<SourceCodeRepresentation> m_constantsSourceCodeRepresentation;
469 typedef Vector<WriteBarrier<UnlinkedFunctionExecutable>> FunctionExpressionVector;
470 FunctionExpressionVector m_functionDecls;
471 FunctionExpressionVector m_functionExprs;
472
473public:
474 struct RareData {
475 WTF_MAKE_STRUCT_FAST_ALLOCATED;
476
477 Vector<UnlinkedHandlerInfo> m_exceptionHandlers;
478
479 // Jump Tables
480 Vector<UnlinkedSimpleJumpTable> m_switchJumpTables;
481 Vector<UnlinkedStringJumpTable> m_stringSwitchJumpTables;
482
483 Vector<ExpressionRangeInfo::FatPosition> m_expressionInfoFatPositions;
484
485 struct TypeProfilerExpressionRange {
486 unsigned m_startDivot;
487 unsigned m_endDivot;
488 };
489 HashMap<unsigned, TypeProfilerExpressionRange> m_typeProfilerInfoMap;
490 Vector<InstructionStream::Offset> m_opProfileControlFlowBytecodeOffsets;
491 Vector<BitVector> m_bitVectors;
492 Vector<ConstantIdentifierSetEntry> m_constantIdentifierSets;
493 };
494
495 void addOutOfLineJumpTarget(InstructionStream::Offset, int target);
496 int outOfLineJumpOffset(InstructionStream::Offset);
497 int outOfLineJumpOffset(const InstructionStream::Ref& instruction)
498 {
499 return outOfLineJumpOffset(instruction.offset());
500 }
501
502private:
503 using OutOfLineJumpTargets = HashMap<InstructionStream::Offset, int>;
504
505 OutOfLineJumpTargets replaceOutOfLineJumpTargets()
506 {
507 OutOfLineJumpTargets newJumpTargets;
508 std::swap(m_outOfLineJumpTargets, newJumpTargets);
509 return newJumpTargets;
510 }
511
512 OutOfLineJumpTargets m_outOfLineJumpTargets;
513 std::unique_ptr<RareData> m_rareData;
514 Vector<ExpressionRangeInfo> m_expressionInfo;
515
516protected:
517 static void visitChildren(JSCell*, SlotVisitor&);
518 static size_t estimatedSize(JSCell*, VM&);
519
520public:
521 DECLARE_INFO;
522};
523
524}
525