JSScript* GlobalHelperThreadState::finishParseTask(JSContext* maybecx, JSRuntime* rt, void* token) { ScopedJSDeletePtr<ParseTask> parseTask; // The token is a ParseTask* which should be in the finished list. // Find and remove its entry. { AutoLockHelperThreadState lock; ParseTaskVector& finished = parseFinishedList(); for (size_t i = 0; i < finished.length(); i++) { if (finished[i] == token) { parseTask = finished[i]; remove(finished, &i); break; } } } MOZ_ASSERT(parseTask); if (!maybecx) { LeaveParseTaskZone(rt, parseTask); return nullptr; } JSContext* cx = maybecx; MOZ_ASSERT(cx->compartment()); // Make sure we have all the constructors we need for the prototype // remapping below, since we can't GC while that's happening. Rooted<GlobalObject*> global(cx, &cx->global()->as<GlobalObject>()); if (!EnsureParserCreatedClasses(cx)) { LeaveParseTaskZone(rt, parseTask); return nullptr; } mergeParseTaskCompartment(rt, parseTask, global, cx->compartment()); if (!parseTask->finish(cx)) return nullptr; RootedScript script(rt, parseTask->script); assertSameCompartment(cx, script); // Report any error or warnings generated during the parse, and inform the // debugger about the compiled scripts. for (size_t i = 0; i < parseTask->errors.length(); i++) parseTask->errors[i]->throwError(cx); if (parseTask->overRecursed) ReportOverRecursed(cx); if (cx->isExceptionPending()) return nullptr; if (!script) { // No error was reported, but no script produced. Assume we hit out of // memory. ReportOutOfMemory(cx); return nullptr; } // The Debugger only needs to be told about the topmost script that was compiled. Debugger::onNewScript(cx, script); // Update the compressed source table with the result. This is normally // called by setCompressedSource when compilation occurs on the main thread. if (script->scriptSource()->hasCompressedSource()) script->scriptSource()->updateCompressedSourceSet(rt); return script; }
JSScript * GlobalHelperThreadState::finishParseTask(JSContext *maybecx, JSRuntime *rt, void *token) { ScopedJSDeletePtr<ParseTask> parseTask; // The token is a ParseTask* which should be in the finished list. // Find and remove its entry. { AutoLockHelperThreadState lock; ParseTaskVector &finished = parseFinishedList(); for (size_t i = 0; i < finished.length(); i++) { if (finished[i] == token) { parseTask = finished[i]; remove(finished, &i); break; } } } MOZ_ASSERT(parseTask); if (!maybecx) { LeaveParseTaskZone(rt, parseTask); return nullptr; } JSContext *cx = maybecx; MOZ_ASSERT(cx->compartment()); // Make sure we have all the constructors we need for the prototype // remapping below, since we can't GC while that's happening. Rooted<GlobalObject*> global(cx, &cx->global()->as<GlobalObject>()); if (!GlobalObject::ensureConstructor(cx, global, JSProto_Object) || !GlobalObject::ensureConstructor(cx, global, JSProto_Array) || !GlobalObject::ensureConstructor(cx, global, JSProto_Function) || !GlobalObject::ensureConstructor(cx, global, JSProto_RegExp) || !GlobalObject::ensureConstructor(cx, global, JSProto_Iterator)) { LeaveParseTaskZone(rt, parseTask); return nullptr; } LeaveParseTaskZone(rt, parseTask); // Point the prototypes of any objects in the script's compartment to refer // to the corresponding prototype in the new compartment. This will briefly // create cross compartment pointers, which will be fixed by the // MergeCompartments call below. for (gc::ZoneCellIter iter(parseTask->cx->zone(), gc::FINALIZE_TYPE_OBJECT); !iter.done(); iter.next()) { types::TypeObject *object = iter.get<types::TypeObject>(); TaggedProto proto(object->proto()); if (!proto.isObject()) continue; JSProtoKey key = JS::IdentifyStandardPrototype(proto.toObject()); if (key == JSProto_Null) continue; MOZ_ASSERT(key == JSProto_Object || key == JSProto_Array || key == JSProto_Function || key == JSProto_RegExp || key == JSProto_Iterator); JSObject *newProto = GetBuiltinPrototypePure(global, key); MOZ_ASSERT(newProto); object->setProtoUnchecked(TaggedProto(newProto)); } // Move the parsed script and all its contents into the desired compartment. gc::MergeCompartments(parseTask->cx->compartment(), cx->compartment()); if (!parseTask->finish(cx)) return nullptr; RootedScript script(rt, parseTask->script); assertSameCompartment(cx, script); // Report any error or warnings generated during the parse, and inform the // debugger about the compiled scripts. for (size_t i = 0; i < parseTask->errors.length(); i++) parseTask->errors[i]->throwError(cx); if (parseTask->overRecursed) js_ReportOverRecursed(cx); if (script) { // The Debugger only needs to be told about the topmost script that was compiled. GlobalObject *compileAndGoGlobal = nullptr; if (script->compileAndGo()) compileAndGoGlobal = &script->global(); Debugger::onNewScript(cx, script, compileAndGoGlobal); // Update the compressed source table with the result. This is normally // called by setCompressedSource when compilation occurs on the main thread. if (script->scriptSource()->hasCompressedSource()) script->scriptSource()->updateCompressedSourceSet(rt); } return script; }