BaselineCompileTask.cpp (4823B)
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 #include "jit/BaselineCompileTask.h" 8 #include "jit/JitRuntime.h" 9 #include "jit/JitScript.h" 10 #include "vm/HelperThreadState.h" 11 12 #include "vm/JSScript-inl.h" 13 #include "vm/Realm-inl.h" 14 15 using namespace js; 16 using namespace js::jit; 17 18 void BaselineCompileTask::runHelperThreadTask( 19 AutoLockHelperThreadState& locked) { 20 { 21 AutoUnlockHelperThreadState unlock(locked); 22 runTask(); 23 } 24 25 FinishOffThreadBaselineCompile(this, locked); 26 27 // Ping the main thread so that the compiled code can be incorporated at 28 // the next interrupt callback. 29 runtimeFromAnyThread()->mainContextFromAnyThread()->requestInterrupt( 30 InterruptReason::AttachOffThreadCompilations); 31 } 32 33 // Debugging RAII class which marks the current thread as performing 34 // an offthread baseline compilation. 35 class MOZ_RAII AutoEnterBaselineBackend { 36 public: 37 AutoEnterBaselineBackend() { 38 #ifdef DEBUG 39 JitContext* jcx = GetJitContext(); 40 jcx->enterBaselineBackend(); 41 #endif 42 } 43 44 #ifdef DEBUG 45 ~AutoEnterBaselineBackend() { 46 JitContext* jcx = GetJitContext(); 47 jcx->leaveBaselineBackend(); 48 } 49 #endif 50 }; 51 52 void BaselineCompileTask::markScriptsAsCompiling() { 53 for (auto* snapshot : snapshots_) { 54 JSScript* script = snapshot->script(); 55 script->jitScript()->setIsBaselineCompiling(script); 56 } 57 } 58 59 bool OffThreadBaselineSnapshot::compileOffThread(TempAllocator& temp, 60 CompileRealm* realm) { 61 masm_.emplace(temp, realm); 62 compiler_.emplace(temp, realm->runtime(), masm_.ref(), this); 63 64 if (!compiler_->init()) { 65 return false; 66 } 67 MethodStatus status = compiler_->compileOffThread(); 68 return status != Method_Error; 69 } 70 71 void BaselineCompileTask::runTask() { 72 jit::JitContext jctx(realm_->runtime()); 73 AutoEnterBaselineBackend enter; 74 75 TempAllocator* temp = alloc_->new_<TempAllocator>(alloc_); 76 if (!temp) { 77 failed_ = true; 78 return; 79 } 80 81 for (auto* snapshot : snapshots_) { 82 if (!snapshot->compileOffThread(*temp, realm_)) { 83 failed_ = true; 84 return; 85 } 86 } 87 } 88 89 /* static */ 90 void BaselineCompileTask::FinishOffThreadTask(BaselineCompileTask* task) { 91 for (auto* snapshot : task->snapshots_) { 92 JSScript* script = snapshot->script(); 93 if (script->isBaselineCompilingOffThread()) { 94 script->jitScript()->clearIsBaselineCompiling(script); 95 } 96 snapshot->compiler_.reset(); 97 snapshot->masm_.reset(); 98 } 99 100 // The task is allocated into its LifoAlloc, so destroying that will 101 // destroy the task and all other data accumulated during compilation. 102 js_delete(task->alloc_); 103 } 104 105 void BaselineCompileTask::finishOnMainThread(JSContext* cx) { 106 AutoRealm ar(cx, firstScript()); 107 for (auto* snapshot : snapshots_) { 108 if (!snapshot->compiler_->finishCompile(cx)) { 109 cx->recoverFromOutOfMemory(); 110 } 111 } 112 } 113 114 void js::AttachFinishedBaselineCompilations(JSContext* cx, 115 AutoLockHelperThreadState& lock) { 116 JSRuntime* rt = cx->runtime(); 117 118 while (true) { 119 GlobalHelperThreadState::BaselineCompileTaskVector& finished = 120 HelperThreadState().baselineFinishedList(lock); 121 122 // Find a finished task for this runtime. 123 bool found = false; 124 for (size_t i = 0; i < finished.length(); i++) { 125 BaselineCompileTask* task = finished[i]; 126 if (task->runtimeFromAnyThread() != rt) { 127 continue; 128 } 129 found = true; 130 131 HelperThreadState().remove(finished, &i); 132 rt->jitRuntime()->numFinishedOffThreadTasksRef(lock)--; 133 { 134 if (!task->failed()) { 135 AutoUnlockHelperThreadState unlock(lock); 136 task->finishOnMainThread(cx); 137 } 138 BaselineCompileTask::FinishOffThreadTask(task); 139 } 140 } 141 if (!found) { 142 break; 143 } 144 } 145 } 146 147 void BaselineSnapshot::trace(JSTracer* trc) { 148 TraceOffthreadGCPtr(trc, script_, "baseline-snapshot-script"); 149 TraceOffthreadGCPtr(trc, globalLexical_, "baseline-snapshot-lexical"); 150 TraceOffthreadGCPtr(trc, globalThis_, "baseline-snapshot-this"); 151 if (callObjectTemplate_) { 152 TraceOffthreadGCPtr(trc, callObjectTemplate_, 153 "baseline-snapshot-call-object-template"); 154 } 155 if (namedLambdaTemplate_) { 156 TraceOffthreadGCPtr(trc, namedLambdaTemplate_, 157 "baseline-snapshot-named-lambda-template"); 158 } 159 } 160 161 void BaselineCompileTask::trace(JSTracer* trc) { 162 if (!realm_->runtime()->runtimeMatches(trc->runtime())) { 163 return; 164 } 165 for (auto* snapshot : snapshots_) { 166 snapshot->trace(trc); 167 } 168 }