BaselineJIT.h (21157B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef jit_BaselineJIT_h 8 #define jit_BaselineJIT_h 9 10 #include "mozilla/Assertions.h" 11 #include "mozilla/Likely.h" 12 #include "mozilla/Maybe.h" 13 #include "mozilla/MemoryReporting.h" 14 #include "mozilla/Span.h" 15 16 #include <stddef.h> 17 #include <stdint.h> 18 19 #include "jsfriendapi.h" 20 21 #include "jit/IonTypes.h" 22 #include "jit/JitCode.h" 23 #include "jit/JitContext.h" 24 #include "jit/JitOptions.h" 25 #include "jit/shared/Assembler-shared.h" 26 #include "js/Principals.h" 27 #include "js/TypeDecls.h" 28 #include "js/Vector.h" 29 #include "threading/ProtectedData.h" 30 #include "util/TrailingArray.h" 31 #include "vm/JSScript.h" 32 33 namespace js { 34 35 class InterpreterFrame; 36 class RunState; 37 38 namespace jit { 39 40 class BaselineFrame; 41 class ExceptionBailoutInfo; 42 class IonCompileTask; 43 class JitActivation; 44 class JSJitFrameIter; 45 46 // Base class for entries mapping a pc offset to a native code offset. 47 class BasePCToNativeEntry { 48 uint32_t pcOffset_; 49 uint32_t nativeOffset_; 50 51 public: 52 BasePCToNativeEntry(uint32_t pcOffset, uint32_t nativeOffset) 53 : pcOffset_(pcOffset), nativeOffset_(nativeOffset) {} 54 uint32_t pcOffset() const { return pcOffset_; } 55 uint32_t nativeOffset() const { return nativeOffset_; } 56 }; 57 58 // Class used during Baseline compilation to store the native code offset for 59 // resume offset ops. 60 class ResumeOffsetEntry : public BasePCToNativeEntry { 61 public: 62 using BasePCToNativeEntry::BasePCToNativeEntry; 63 }; 64 65 using ResumeOffsetEntryVector = 66 Vector<ResumeOffsetEntry, 16, SystemAllocPolicy>; 67 68 // Largest script that the baseline compiler will attempt to compile. 69 #if defined(JS_CODEGEN_ARM) 70 // ARM branches can only reach 32MB, and the macroassembler doesn't mitigate 71 // that limitation. Use a stricter limit on the acceptable script size to 72 // avoid crashing when branches go out of range. 73 static constexpr uint32_t BaselineMaxScriptLength = 1000000u; 74 #else 75 static constexpr uint32_t BaselineMaxScriptLength = 0x0fffffffu; 76 #endif 77 78 // Limit the locals on a given script so that stack check on baseline frames 79 // doesn't overflow a uint32_t value. 80 // (BaselineMaxScriptSlots * sizeof(Value)) must fit within a uint32_t. 81 // 82 // This also applies to the Baseline Interpreter: it ensures we don't run out 83 // of stack space (and throw over-recursion exceptions) for scripts with a huge 84 // number of locals. The C++ interpreter avoids this by having heap-allocated 85 // stack frames. 86 static constexpr uint32_t BaselineMaxScriptSlots = 0xffffu; 87 88 // An entry in the BaselineScript return address table. These entries are used 89 // to determine the bytecode pc for a return address into Baseline code. 90 // 91 // There must be an entry for each location where we can end up calling into 92 // C++ (directly or via script/trampolines) and C++ can request the current 93 // bytecode pc (this includes anything that may throw an exception, GC, or walk 94 // the stack). We currently add entries for each: 95 // 96 // * callVM 97 // * IC 98 // * DebugTrap (trampoline call) 99 // * JSOp::Resume (because this is like a scripted call) 100 // 101 // Note: see also BaselineFrame::HAS_OVERRIDE_PC. 102 class RetAddrEntry { 103 // Offset from the start of the JIT code where call instruction is. 104 uint32_t returnOffset_; 105 106 // The offset of this bytecode op within the JSScript. 107 uint32_t pcOffset_ : 28; 108 109 public: 110 enum class Kind : uint32_t { 111 // An IC for a JOF_IC op. 112 IC, 113 114 // A callVM for an op. 115 CallVM, 116 117 // A callVM not for an op (e.g., in the prologue) that can't 118 // trigger debug mode. 119 NonOpCallVM, 120 121 // A callVM for the over-recursion check on function entry. 122 StackCheck, 123 124 // A callVM for an interrupt check. 125 InterruptCheck, 126 127 // DebugTrapHandler (for debugger breakpoints/stepping). 128 DebugTrap, 129 130 // A callVM for Debug{Prologue,AfterYield,Epilogue}. 131 DebugPrologue, 132 DebugAfterYield, 133 DebugEpilogue, 134 135 Invalid 136 }; 137 138 private: 139 // What this entry is for. 140 uint32_t kind_ : 4; 141 142 public: 143 RetAddrEntry(uint32_t pcOffset, Kind kind, CodeOffset retOffset) 144 : returnOffset_(uint32_t(retOffset.offset())), 145 pcOffset_(pcOffset), 146 kind_(uint32_t(kind)) { 147 MOZ_ASSERT(returnOffset_ == retOffset.offset(), 148 "retOffset must fit in returnOffset_"); 149 150 // The pc offset must fit in at least 28 bits, since we shave off 4 for 151 // the Kind enum. 152 MOZ_ASSERT(pcOffset_ == pcOffset); 153 static_assert(BaselineMaxScriptLength <= (1u << 28) - 1); 154 MOZ_ASSERT(pcOffset <= BaselineMaxScriptLength); 155 156 MOZ_ASSERT(kind < Kind::Invalid); 157 MOZ_ASSERT(this->kind() == kind, "kind must fit in kind_ bit field"); 158 } 159 160 CodeOffset returnOffset() const { return CodeOffset(returnOffset_); } 161 162 uint32_t pcOffset() const { return pcOffset_; } 163 164 jsbytecode* pc(JSScript* script) const { 165 return script->offsetToPC(pcOffset_); 166 } 167 168 Kind kind() const { 169 MOZ_ASSERT(kind_ < uint32_t(Kind::Invalid)); 170 return Kind(kind_); 171 } 172 }; 173 174 // [SMDOC] BaselineScript 175 // 176 // This holds the metadata generated by the BaselineCompiler. The machine code 177 // associated with this is owned by a JitCode instance. This class instance is 178 // followed by several arrays: 179 // 180 // <BaselineScript itself> 181 // -- 182 // uint8_t*[] resumeEntryList() 183 // RetAddrEntry[] retAddrEntries() 184 // OSREntry[] osrEntries() 185 // DebugTrapEntry[] debugTrapEntries() 186 // 187 // Note: The arrays are arranged in order of descending alignment requires so 188 // that padding is not required. 189 class alignas(uintptr_t) BaselineScript final 190 : public TrailingArray<BaselineScript> { 191 private: 192 // Code pointer containing the actual method. 193 HeapPtr<JitCode*> method_ = nullptr; 194 195 // An ion compilation that is ready, but isn't linked yet. 196 MainThreadData<IonCompileTask*> pendingIonCompileTask_{nullptr}; 197 198 // Baseline Interpreter can enter Baseline Compiler code at this address. This 199 // is right after the warm-up counter check in the prologue. 200 uint32_t warmUpCheckPrologueOffset_ = 0; 201 202 // The offsets for the toggledJump instructions for profiler instrumentation. 203 uint32_t profilerEnterToggleOffset_ = 0; 204 uint32_t profilerExitToggleOffset_ = 0; 205 206 private: 207 // Offset (in bytes) from `this` to the start of each trailing array. Each 208 // array ends where following one begins. There is no implicit padding (except 209 // possible at very end). 210 Offset resumeEntriesOffset_ = 0; 211 Offset retAddrEntriesOffset_ = 0; 212 Offset osrEntriesOffset_ = 0; 213 Offset debugTrapEntriesOffset_ = 0; 214 Offset allocBytes_ = 0; 215 216 // See `Flag` type below. 217 uint8_t flags_ = 0; 218 219 // End of fields. 220 221 public: 222 enum Flag { 223 // Flag set when compiled for use with Debugger. Handles various 224 // Debugger hooks and compiles toggled calls for traps. 225 HAS_DEBUG_INSTRUMENTATION = 1 << 0, 226 227 // Flag is set if this script has profiling instrumentation turned on. 228 PROFILER_INSTRUMENTATION_ON = 1 << 1, 229 }; 230 231 // Native code offset for OSR from Baseline Interpreter into Baseline JIT at 232 // JSOp::LoopHead ops. 233 class OSREntry : public BasePCToNativeEntry { 234 public: 235 using BasePCToNativeEntry::BasePCToNativeEntry; 236 }; 237 238 // Native code offset for a debug trap when the script is compiled with debug 239 // instrumentation. 240 class DebugTrapEntry : public BasePCToNativeEntry { 241 public: 242 using BasePCToNativeEntry::BasePCToNativeEntry; 243 }; 244 245 private: 246 // Layout helpers 247 Offset resumeEntriesOffset() const { return resumeEntriesOffset_; } 248 Offset retAddrEntriesOffset() const { return retAddrEntriesOffset_; } 249 Offset osrEntriesOffset() const { return osrEntriesOffset_; } 250 Offset debugTrapEntriesOffset() const { return debugTrapEntriesOffset_; } 251 Offset endOffset() const { return allocBytes_; } 252 253 // Use BaselineScript::New to create new instances. It will properly 254 // allocate trailing objects. 255 BaselineScript(uint32_t warmUpCheckPrologueOffset, 256 uint32_t profilerEnterToggleOffset, 257 uint32_t profilerExitToggleOffset) 258 : warmUpCheckPrologueOffset_(warmUpCheckPrologueOffset), 259 profilerEnterToggleOffset_(profilerEnterToggleOffset), 260 profilerExitToggleOffset_(profilerExitToggleOffset) {} 261 262 template <typename T> 263 mozilla::Span<T> makeSpan(Offset start, Offset end) { 264 return mozilla::Span{offsetToPointer<T>(start), numElements<T>(start, end)}; 265 } 266 267 // We store the native code address corresponding to each bytecode offset in 268 // the script's resumeOffsets list. 269 mozilla::Span<uint8_t*> resumeEntryList() { 270 return makeSpan<uint8_t*>(resumeEntriesOffset(), retAddrEntriesOffset()); 271 } 272 273 // See each type for documentation of these arrays. 274 mozilla::Span<RetAddrEntry> retAddrEntries() { 275 return makeSpan<RetAddrEntry>(retAddrEntriesOffset(), osrEntriesOffset()); 276 } 277 mozilla::Span<OSREntry> osrEntries() { 278 return makeSpan<OSREntry>(osrEntriesOffset(), debugTrapEntriesOffset()); 279 } 280 mozilla::Span<DebugTrapEntry> debugTrapEntries() { 281 return makeSpan<DebugTrapEntry>(debugTrapEntriesOffset(), endOffset()); 282 } 283 284 public: 285 static BaselineScript* New(JSContext* cx, uint32_t warmUpCheckPrologueOffset, 286 uint32_t profilerEnterToggleOffset, 287 uint32_t profilerExitToggleOffset, 288 size_t retAddrEntries, size_t osrEntries, 289 size_t debugTrapEntries, size_t resumeEntries); 290 291 // Copies the given BaselineScript and all trailing arrays. 292 // Both BaselineScripts will refer to the same method and IonCompileTask (if 293 // any), but those objects won't be compiled. 294 static BaselineScript* Copy(JSContext* cx, BaselineScript* bs); 295 296 static void Destroy(JS::GCContext* gcx, BaselineScript* script); 297 298 void trace(JSTracer* trc); 299 300 static inline size_t offsetOfMethod() { 301 return offsetof(BaselineScript, method_); 302 } 303 304 void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, 305 size_t* data) const { 306 *data += mallocSizeOf(this); 307 } 308 309 void setHasDebugInstrumentation() { flags_ |= HAS_DEBUG_INSTRUMENTATION; } 310 bool hasDebugInstrumentation() const { 311 return flags_ & HAS_DEBUG_INSTRUMENTATION; 312 } 313 314 uint8_t* warmUpCheckPrologueAddr() const { 315 return method_->raw() + warmUpCheckPrologueOffset_; 316 } 317 318 JitCode* method() const { return method_; } 319 void setMethod(JitCode* code) { 320 MOZ_ASSERT(!method_); 321 method_ = code; 322 } 323 324 bool containsCodeAddress(uint8_t* addr) const { 325 return method()->raw() <= addr && 326 addr <= method()->raw() + method()->instructionsSize(); 327 } 328 329 uint8_t* returnAddressForEntry(const RetAddrEntry& ent); 330 331 const RetAddrEntry& retAddrEntryFromPCOffset(uint32_t pcOffset, 332 RetAddrEntry::Kind kind); 333 const RetAddrEntry& prologueRetAddrEntry(RetAddrEntry::Kind kind); 334 const RetAddrEntry& retAddrEntryFromReturnOffset(CodeOffset returnOffset); 335 const RetAddrEntry& retAddrEntryFromReturnAddress(const uint8_t* returnAddr); 336 337 uint8_t* nativeCodeForOSREntry(uint32_t pcOffset); 338 339 static bool OSREntryForFrame(JSContext* cx, BaselineFrame* frame, 340 uint8_t** entry); 341 342 void copyRetAddrEntries(const RetAddrEntry* entries); 343 void copyOSREntries(const OSREntry* entries); 344 void copyDebugTrapEntries(const DebugTrapEntry* entries); 345 346 // Copy resumeOffsets list from |script| and convert the pcOffsets 347 // to native addresses in the Baseline code based on |entries|. 348 void computeResumeNativeOffsets(JSScript* script, 349 const ResumeOffsetEntryVector& entries); 350 351 // Return the bytecode offset for a given native code address. Be careful 352 // when using this method: it's an approximation and not guaranteed to be the 353 // correct pc. 354 jsbytecode* approximatePcForNativeAddress(JSScript* script, 355 uint8_t* nativeAddress); 356 357 // Toggle debug traps (used for breakpoints and step mode) in the script. 358 // If |pc| is nullptr, toggle traps for all ops in the script. Else, only 359 // toggle traps at |pc|. 360 void toggleDebugTraps(JSScript* script, jsbytecode* pc); 361 362 void toggleProfilerInstrumentation(bool enable); 363 bool isProfilerInstrumentationOn() const { 364 return flags_ & PROFILER_INSTRUMENTATION_ON; 365 } 366 367 static size_t offsetOfResumeEntriesOffset() { 368 static_assert(sizeof(Offset) == sizeof(uint32_t), 369 "JIT expect Offset to be uint32_t"); 370 return offsetof(BaselineScript, resumeEntriesOffset_); 371 } 372 373 bool hasPendingIonCompileTask() const { return !!pendingIonCompileTask_; } 374 375 js::jit::IonCompileTask* pendingIonCompileTask() { 376 MOZ_ASSERT(hasPendingIonCompileTask()); 377 return pendingIonCompileTask_; 378 } 379 void setPendingIonCompileTask(JSRuntime* rt, JSScript* script, 380 js::jit::IonCompileTask* task); 381 void removePendingIonCompileTask(JSRuntime* rt, JSScript* script); 382 383 size_t allocBytes() const { return allocBytes_; } 384 }; 385 static_assert( 386 sizeof(BaselineScript) % sizeof(uintptr_t) == 0, 387 "The data attached to the script must be aligned for fast JIT access."); 388 389 enum class BaselineTier { Interpreter, Compiler }; 390 391 template <BaselineTier Tier> 392 MethodStatus CanEnterBaselineMethod(JSContext* cx, RunState& state); 393 394 MethodStatus CanEnterBaselineInterpreterAtBranch(JSContext* cx, 395 InterpreterFrame* fp); 396 397 JitExecStatus EnterBaselineInterpreterAtBranch(JSContext* cx, 398 InterpreterFrame* fp, 399 jsbytecode* pc); 400 401 bool CanBaselineInterpretScript(JSScript* script); 402 403 // Called by the Baseline Interpreter to compile a script for the Baseline JIT. 404 // |res| is set to the native code address in the BaselineScript to jump to, or 405 // nullptr if we were unable to compile this script. 406 bool BaselineCompileFromBaselineInterpreter(JSContext* cx, BaselineFrame* frame, 407 uint8_t** res); 408 409 void FinishDiscardBaselineScript(JS::GCContext* gcx, JSScript* script); 410 411 void AddSizeOfBaselineData(JSScript* script, mozilla::MallocSizeOf mallocSizeOf, 412 size_t* data); 413 414 void ToggleBaselineProfiling(JSContext* cx, bool enable); 415 416 struct alignas(uintptr_t) BaselineBailoutInfo { 417 // Pointer into the current C stack, where overwriting will start. 418 uint8_t* incomingStack = nullptr; 419 420 // The top and bottom heapspace addresses of the reconstructed stack 421 // which will be copied to the bottom. 422 uint8_t* copyStackTop = nullptr; 423 uint8_t* copyStackBottom = nullptr; 424 425 // The value of the frame pointer register on resume. 426 void* resumeFramePtr = nullptr; 427 428 // The native code address to resume into. 429 void* resumeAddr = nullptr; 430 431 // The bytecode pc of try block and fault block. 432 jsbytecode* tryPC = nullptr; 433 jsbytecode* faultPC = nullptr; 434 435 // We use this to transfer exception information out from 436 // buildExpressionStack, since it would be too risky to throw from 437 // there. 438 jsid tempId = PropertyKey::Void(); 439 440 // Number of baseline frames to push on the stack. 441 uint32_t numFrames = 0; 442 443 // The bailout kind. 444 mozilla::Maybe<BailoutKind> bailoutKind = {}; 445 446 BaselineBailoutInfo() = default; 447 BaselineBailoutInfo(const BaselineBailoutInfo&) = default; 448 449 void operator=(const BaselineBailoutInfo&) = delete; 450 451 void trace(JSTracer* aTrc); 452 }; 453 454 enum class BailoutReason { 455 Normal, 456 ExceptionHandler, 457 Invalidate, 458 }; 459 460 [[nodiscard]] bool BailoutIonToBaseline( 461 JSContext* cx, JitActivation* activation, const JSJitFrameIter& iter, 462 BaselineBailoutInfo** bailoutInfo, 463 const ExceptionBailoutInfo* exceptionInfo, BailoutReason reason); 464 465 enum class BaselineOption : uint8_t { 466 ForceDebugInstrumentation = 1 << 0, 467 ForceMainThreadCompilation = 1 << 1, 468 }; 469 470 using BaselineOptions = EnumFlags<BaselineOption>; 471 472 bool DispatchOffThreadBaselineBatchEager(JSContext* cx); 473 bool DispatchOffThreadBaselineBatch(JSContext* cx); 474 475 MethodStatus BaselineCompile(JSContext* cx, JSScript* script, 476 BaselineOptions options); 477 478 // Class storing the generated Baseline Interpreter code for the runtime. 479 class BaselineInterpreter { 480 public: 481 struct CallVMOffsets { 482 uint32_t debugPrologueOffset = 0; 483 uint32_t debugEpilogueOffset = 0; 484 uint32_t debugAfterYieldOffset = 0; 485 }; 486 struct ICReturnOffset { 487 uint32_t offset; 488 JSOp op; 489 ICReturnOffset(uint32_t offset, JSOp op) : offset(offset), op(op) {} 490 }; 491 using ICReturnOffsetVector = Vector<ICReturnOffset, 0, SystemAllocPolicy>; 492 493 private: 494 // The interpreter code. 495 JitCode* code_ = nullptr; 496 497 // Offset of the code to start interpreting a bytecode op. 498 uint32_t interpretOpOffset_ = 0; 499 500 // Like interpretOpOffset_ but skips the debug trap for the current op. 501 uint32_t interpretOpNoDebugTrapOffset_ = 0; 502 503 // Early Ion bailouts will enter at this address. This is after frame 504 // construction and environment initialization. 505 uint32_t bailoutPrologueOffset_ = 0; 506 507 // The offsets for the toggledJump instructions for profiler instrumentation. 508 uint32_t profilerEnterToggleOffset_ = 0; 509 uint32_t profilerExitToggleOffset_ = 0; 510 511 // Offset of the jump (tail call) to the debug trap handler trampoline code. 512 // When the debugger is enabled, NOPs are patched to calls to this location. 513 uint32_t debugTrapHandlerOffset_ = 0; 514 515 // The offsets of toggled jumps for debugger instrumentation. 516 using CodeOffsetVector = Vector<uint32_t, 0, SystemAllocPolicy>; 517 CodeOffsetVector debugInstrumentationOffsets_; 518 519 // Offsets of toggled calls to the DebugTrapHandler trampoline (for 520 // breakpoints and stepping). 521 CodeOffsetVector debugTrapOffsets_; 522 523 // Offsets of toggled jumps for code coverage. 524 CodeOffsetVector codeCoverageOffsets_; 525 526 // Offsets of IC calls for IsIonInlinableOp ops, for Ion bailouts. 527 ICReturnOffsetVector icReturnOffsets_; 528 529 // Offsets of some callVMs for BaselineDebugModeOSR. 530 CallVMOffsets callVMOffsets_; 531 532 uint8_t* codeAtOffset(uint32_t offset) const { 533 MOZ_ASSERT(offset > 0); 534 MOZ_ASSERT(offset < code_->instructionsSize()); 535 return codeRaw() + offset; 536 } 537 538 public: 539 BaselineInterpreter() = default; 540 541 BaselineInterpreter(const BaselineInterpreter&) = delete; 542 void operator=(const BaselineInterpreter&) = delete; 543 544 void init(JitCode* code, uint32_t interpretOpOffset, 545 uint32_t interpretOpNoDebugTrapOffset, 546 uint32_t bailoutPrologueOffset, uint32_t profilerEnterToggleOffset, 547 uint32_t profilerExitToggleOffset, uint32_t debugTrapHandlerOffset, 548 CodeOffsetVector&& debugInstrumentationOffsets, 549 CodeOffsetVector&& debugTrapOffsets, 550 CodeOffsetVector&& codeCoverageOffsets, 551 ICReturnOffsetVector&& icReturnOffsets, 552 const CallVMOffsets& callVMOffsets); 553 554 uint8_t* codeRaw() const { return code_->raw(); } 555 556 uint8_t* retAddrForDebugPrologueCallVM() const { 557 return codeAtOffset(callVMOffsets_.debugPrologueOffset); 558 } 559 uint8_t* retAddrForDebugEpilogueCallVM() const { 560 return codeAtOffset(callVMOffsets_.debugEpilogueOffset); 561 } 562 uint8_t* retAddrForDebugAfterYieldCallVM() const { 563 return codeAtOffset(callVMOffsets_.debugAfterYieldOffset); 564 } 565 uint8_t* bailoutPrologueEntryAddr() const { 566 return codeAtOffset(bailoutPrologueOffset_); 567 } 568 569 uint8_t* retAddrForIC(JSOp op) const; 570 571 TrampolinePtr interpretOpAddr() const { 572 return TrampolinePtr(codeAtOffset(interpretOpOffset_)); 573 } 574 TrampolinePtr interpretOpNoDebugTrapAddr() const { 575 return TrampolinePtr(codeAtOffset(interpretOpNoDebugTrapOffset_)); 576 } 577 578 void toggleProfilerInstrumentation(bool enable); 579 void toggleDebuggerInstrumentation(bool enable); 580 581 void toggleCodeCoverageInstrumentationUnchecked(bool enable); 582 void toggleCodeCoverageInstrumentation(bool enable); 583 }; 584 585 [[nodiscard]] bool GenerateBaselineInterpreter( 586 JSContext* cx, BaselineInterpreter& interpreter); 587 588 inline bool IsBaselineJitEnabled(JSContext* cx) { 589 if (MOZ_UNLIKELY(!IsBaselineInterpreterEnabled())) { 590 return false; 591 } 592 if (MOZ_LIKELY(JitOptions.baselineJit)) { 593 return true; 594 } 595 if (JitOptions.jitForTrustedPrincipals) { 596 JS::Realm* realm = js::GetContextRealm(cx); 597 return realm && JS::GetRealmPrincipals(realm) && 598 JS::GetRealmPrincipals(realm)->isSystemOrAddonPrincipal(); 599 } 600 return false; 601 } 602 603 } // namespace jit 604 } // namespace js 605 606 namespace JS { 607 608 template <> 609 struct DeletePolicy<js::jit::BaselineScript> { 610 explicit DeletePolicy(JSRuntime* rt) : rt_(rt) {} 611 void operator()(const js::jit::BaselineScript* script); 612 613 private: 614 JSRuntime* rt_; 615 }; 616 617 template <> 618 struct GCPolicy<js::jit::BaselineScript*> { 619 static void trace(JSTracer* trc, js::jit::BaselineScript** thingp, 620 const char* name) { 621 (*thingp)->trace(trc); 622 } 623 }; 624 625 } // namespace JS 626 627 #endif /* jit_BaselineJIT_h */