static void keepAlive(v8::Local<v8::Array>& array, uint32_t index, const v8::Local<T>& value, ScopedPersistent<T>& persistent, ScriptState* scriptState) { if (value.IsEmpty()) return; array->Set(scriptState->context(), index, value).ToChecked(); persistent.set(scriptState->isolate(), value); persistent.setPhantom(); }
void V8CustomElementLifecycleCallbacks::call(const ScopedPersistent<v8::Function>& weakCallback, Element* element) { // FIXME: callbacks while paused should be queued up for execution to // continue then be delivered in order rather than delivered immediately. // Bug 329665 tracks similar behavior for other synchronous events. if (!executionContext() || executionContext()->activeDOMObjectsAreStopped()) return; if (!m_scriptState->contextIsValid()) return; ScriptState::Scope scope(m_scriptState.get()); v8::Isolate* isolate = m_scriptState->isolate(); v8::Local<v8::Context> context = m_scriptState->context(); v8::Local<v8::Function> callback = weakCallback.newLocal(isolate); if (callback.IsEmpty()) return; v8::Local<v8::Value> receiver = toV8(element, context->Global(), isolate); if (receiver.IsEmpty()) return; v8::TryCatch exceptionCatcher; exceptionCatcher.SetVerbose(true); ScriptController::callFunction(executionContext(), callback, receiver, 0, 0, isolate); }
void V8GCController::collectGarbage() { v8::HandleScope handleScope; ScopedPersistent<v8::Context> context; context.adopt(v8::Context::New()); if (context.isEmpty()) return; { v8::Context::Scope scope(context.get()); v8::Local<v8::String> source = v8::String::New("if (gc) gc();"); v8::Local<v8::String> name = v8::String::New("gc"); v8::Handle<v8::Script> script = v8::Script::Compile(source, name); if (!script.IsEmpty()) { V8RecursionScope::MicrotaskSuppression scope; script->Run(); } } context.clear(); }
void V8CustomElementLifecycleCallbacks::call(const ScopedPersistent<v8::Function>& weakCallback, Element* element) { if (!canInvokeCallback()) return; v8::HandleScope handleScope(toIsolate(scriptExecutionContext())); v8::Handle<v8::Context> context = toV8Context(scriptExecutionContext(), m_world.get()); if (context.IsEmpty()) return; v8::Context::Scope scope(context); v8::Isolate* isolate = context->GetIsolate(); v8::Handle<v8::Function> callback = weakCallback.newLocal(isolate); if (callback.IsEmpty()) return; v8::Handle<v8::Object> receiver = toV8(element, context->Global(), isolate).As<v8::Object>(); ASSERT(!receiver.IsEmpty()); v8::TryCatch exceptionCatcher; exceptionCatcher.SetVerbose(true); ScriptController::callFunctionWithInstrumentation(scriptExecutionContext(), callback, receiver, 0, 0, isolate); }
TEST_F(PaintWorkletTest, GarbageCollectionOfCSSPaintDefinition) { PaintWorkletGlobalScope* globalScope = paintWorklet()->workletGlobalScopeProxy(); globalScope->scriptController()->evaluate( ScriptSourceCode("registerPaint('foo', class { paint() { } });")); CSSPaintDefinition* definition = globalScope->findDefinition("foo"); ASSERT(definition); v8::Isolate* isolate = globalScope->scriptController()->getScriptState()->isolate(); ASSERT(isolate); // Set our ScopedPersistent to the paint function, and make weak. ScopedPersistent<v8::Function> handle; { v8::HandleScope handleScope(isolate); handle.set(isolate, definition->paintFunctionForTesting(isolate)); handle.setPhantom(); } ASSERT(!handle.isEmpty()); ASSERT(handle.isWeak()); // Run a GC, persistent shouldn't have been collected yet. ThreadState::current()->collectAllGarbage(); V8GCController::collectAllGarbageForTesting(isolate); ASSERT(!handle.isEmpty()); // Delete the page & associated objects. m_page.reset(); // Run a GC, the persistent should have been collected. ThreadState::current()->collectAllGarbage(); V8GCController::collectAllGarbageForTesting(isolate); ASSERT(handle.isEmpty()); }