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