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