bool DictionaryHelper::get(const Dictionary& dictionary, const StringView& key, Member<EventTarget>& value) { v8::Local<v8::Value> v8Value; if (!dictionary.get(key, v8Value)) return false; value = nullptr; // We need to handle a DOMWindow specially, because a DOMWindow wrapper // exists on a prototype chain of v8Value. if (v8Value->IsObject()) { v8::Local<v8::Object> wrapper = v8::Local<v8::Object>::Cast(v8Value); v8::Local<v8::Object> window = V8Window::findInstanceInPrototypeChain(wrapper, dictionary.isolate()); if (!window.IsEmpty()) { value = toWrapperTypeInfo(window)->toEventTarget(window); return true; } } if (V8DOMWrapper::isWrapper(dictionary.isolate(), v8Value)) { v8::Local<v8::Object> wrapper = v8::Local<v8::Object>::Cast(v8Value); value = toWrapperTypeInfo(wrapper)->toEventTarget(wrapper); } return true; }
void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t classId) override { // If we have already found any wrapper that has a pending activity, // we don't need to check other wrappers. if (m_pendingActivityFound) return; if (classId != WrapperTypeInfo::NodeClassId && classId != WrapperTypeInfo::ObjectClassId) return; const v8::Persistent<v8::Object>& wrapper = v8::Persistent<v8::Object>::Cast(*value); const WrapperTypeInfo* type = toWrapperTypeInfo(wrapper); // The ExecutionContext check is heavy, so it should be done at the last. if (type != npObjectTypeInfo() && toScriptWrappable(wrapper)->hasPendingActivity() // TODO(haraken): Currently we don't have a way to get a creation // context from a wrapper. We should implement the way and enable // the following condition. // // This condition affects only compositor workers, where one isolate // is shared by multiple workers. If we don't have the condition, // a worker object for a compositor worker doesn't get collected // until all compositor workers in the same isolate lose pending // activities. In other words, not having the condition delays // destruction of a worker object of a compositor worker. // /* && toExecutionContext(wrapper->creationContext()) == m_executionContext */ ) m_pendingActivityFound = true; }
static void messageHandlerInMainThread(v8::Handle<v8::Message> message, v8::Handle<v8::Value> data) { ASSERT(isMainThread()); // It's possible that messageHandlerInMainThread() is invoked while we're initializing a window. // In that half-baked situation, we don't have a valid context nor a valid world, // so just return immediately. if (DOMWrapperWorld::windowIsBeingInitialized()) return; v8::Isolate* isolate = v8::Isolate::GetCurrent(); // If called during context initialization, there will be no entered window. LocalDOMWindow* enteredWindow = enteredDOMWindow(isolate); if (!enteredWindow) return; String errorMessage = toCoreString(message->Get()); v8::Handle<v8::StackTrace> stackTrace = message->GetStackTrace(); RefPtr<ScriptCallStack> callStack = nullptr; int scriptId = message->GetScriptOrigin().ScriptID()->Value(); // Currently stack trace is only collected when inspector is open. if (!stackTrace.IsEmpty() && stackTrace->GetFrameCount() > 0) { callStack = createScriptCallStack(stackTrace, ScriptCallStack::maxCallStackSizeToCapture, isolate); bool success = false; int topScriptId = callStack->at(0).scriptId().toInt(&success); if (success && topScriptId == scriptId) scriptId = 0; } else { Vector<ScriptCallFrame> callFrames; callStack = ScriptCallStack::create(callFrames); } v8::Handle<v8::Value> resourceName = message->GetScriptOrigin().ResourceName(); bool shouldUseDocumentURL = resourceName.IsEmpty() || !resourceName->IsString(); String resource = shouldUseDocumentURL ? enteredWindow->document()->url() : toCoreString(resourceName.As<v8::String>()); ScriptState* scriptState = ScriptState::current(isolate); RefPtr<ErrorEvent> event = ErrorEvent::create(errorMessage, resource, message->GetLineNumber(), message->GetStartColumn() + 1, &scriptState->world()); if (V8DOMWrapper::isDOMWrapper(data)) { v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(data); const WrapperTypeInfo* type = toWrapperTypeInfo(obj); if (V8DOMException::wrapperTypeInfo.isSubclass(type)) { DOMException* exception = V8DOMException::toNative(obj); if (exception && !exception->messageForConsole().isEmpty()) event->setUnsanitizedMessage("Uncaught " + exception->toStringForConsole()); } } // This method might be called while we're creating a new context. In this case, we // avoid storing the exception object, as we can't create a wrapper during context creation. // FIXME: Can we even get here during initialization now that we bail out when GetEntered returns an empty handle? LocalFrame* frame = enteredWindow->document()->frame(); if (frame && frame->script().existingWindowProxy(scriptState->world())) { V8ErrorHandler::storeExceptionOnErrorEventWrapper(event.get(), data, scriptState->context()->Global(), isolate); } enteredWindow->document()->reportException(event.release(), scriptId, callStack); }
void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t classId) override { if (classId != WrapperTypeInfo::NodeClassId && classId != WrapperTypeInfo::ObjectClassId) return; const v8::Persistent<v8::Object>& wrapper = v8::Persistent<v8::Object>::Cast(*value); if (m_visitor) toWrapperTypeInfo(wrapper)->trace(m_visitor, toScriptWrappable(wrapper)); }
virtual void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t classId) override { if (classId != WrapperTypeInfo::NodeClassId && classId != WrapperTypeInfo::ObjectClassId) return; // Casting to a Handle is safe here, since the Persistent doesn't get GCd // during tracing. ASSERT((*reinterpret_cast<v8::Handle<v8::Value>*>(value))->IsObject()); v8::Handle<v8::Object>* wrapper = reinterpret_cast<v8::Handle<v8::Object>*>(value); ASSERT(V8DOMWrapper::isDOMWrapper(*wrapper)); if (m_visitor) toWrapperTypeInfo(*wrapper)->trace(m_visitor, toScriptWrappableBase(*wrapper)); }
static String extractMessageForConsole(v8::Isolate* isolate, v8::Local<v8::Value> data) { if (V8DOMWrapper::isWrapper(isolate, data)) { v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(data); const WrapperTypeInfo* type = toWrapperTypeInfo(obj); if (V8DOMException::wrapperTypeInfo.isSubclass(type)) { DOMException* exception = V8DOMException::toImpl(obj); if (exception && !exception->messageForConsole().isEmpty()) return exception->toStringForConsole(); } } return emptyString(); }
void V8DevToolsHost::showContextMenuAtPointMethodCustom( const v8::FunctionCallbackInfo<v8::Value>& info) { if (info.Length() < 3) return; ExceptionState exceptionState(ExceptionState::ExecutionContext, "showContextMenuAtPoint", "DevToolsHost", info.Holder(), info.GetIsolate()); v8::Isolate* isolate = info.GetIsolate(); float x = toRestrictedFloat(isolate, info[0], exceptionState); if (exceptionState.hadException()) return; float y = toRestrictedFloat(isolate, info[1], exceptionState); if (exceptionState.hadException()) return; v8::Local<v8::Value> array = v8::Local<v8::Value>::Cast(info[2]); if (!array->IsArray()) return; ContextMenu menu; if (!populateContextMenuItems(isolate, v8::Local<v8::Array>::Cast(array), menu)) return; Document* document = nullptr; if (info.Length() >= 4 && v8::Local<v8::Value>::Cast(info[3])->IsObject()) { v8::Local<v8::Object> documentWrapper = v8::Local<v8::Object>::Cast(info[3]); if (!V8HTMLDocument::wrapperTypeInfo.equals( toWrapperTypeInfo(documentWrapper))) return; document = V8HTMLDocument::toImpl(documentWrapper); } else { v8::Local<v8::Object> windowWrapper = V8Window::findInstanceInPrototypeChain( isolate->GetEnteredContext()->Global(), isolate); if (windowWrapper.IsEmpty()) return; DOMWindow* window = V8Window::toImpl(windowWrapper); document = window ? toLocalDOMWindow(window)->document() : nullptr; } if (!document || !document->frame()) return; DevToolsHost* devtoolsHost = V8DevToolsHost::toImpl(info.Holder()); Vector<ContextMenuItem> items = menu.items(); devtoolsHost->showContextMenu(document->frame(), x, y, items); }
bool Dictionary::get(const String& key, RefPtr<EventTarget>& value) const { v8::Local<v8::Value> v8Value; if (!getKey(key, v8Value)) return false; value = 0; // We need to handle a DOMWindow specially, because a DOMWindow wrapper // exists on a prototype chain of v8Value. if (v8Value->IsObject()) { v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value); v8::Handle<v8::Object> window = wrapper->FindInstanceInPrototypeChain(V8Window::domTemplate(m_isolate, worldTypeInMainThread(m_isolate))); if (!window.IsEmpty()) { value = toWrapperTypeInfo(window)->toEventTarget(window); return true; } } if (V8DOMWrapper::isDOMWrapper(v8Value)) { v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(v8Value); value = toWrapperTypeInfo(wrapper)->toEventTarget(wrapper); } return true; }
bool V8DOMWrapper::hasInternalFieldsSet(v8::Local<v8::Value> value) { if (value.IsEmpty() || !value->IsObject()) return false; v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(value); if (object->InternalFieldCount() < v8DefaultWrapperInternalFieldCount) return false; const ScriptWrappable* untrustedScriptWrappable = toScriptWrappable(object); const WrapperTypeInfo* untrustedWrapperTypeInfo = toWrapperTypeInfo(object); return untrustedScriptWrappable && untrustedWrapperTypeInfo && untrustedWrapperTypeInfo->ginEmbedder == gin::kEmbedderBlink; }
bool V8DOMWrapper::isWrapper(v8::Isolate* isolate, v8::Local<v8::Value> value) { if (value.IsEmpty() || !value->IsObject()) return false; v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(value); if (object->InternalFieldCount() < v8DefaultWrapperInternalFieldCount) return false; const WrapperTypeInfo* untrustedWrapperTypeInfo = toWrapperTypeInfo(object); V8PerIsolateData* perIsolateData = V8PerIsolateData::from(isolate); if (!(untrustedWrapperTypeInfo && perIsolateData)) return false; return perIsolateData->hasInstance(untrustedWrapperTypeInfo, object); }
virtual void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t classId) override { // A minor DOM GC can collect only Nodes. if (classId != WrapperTypeInfo::NodeClassId) return; // To make minor GC cycle time bounded, we limit the number of wrappers handled // by each minor GC cycle to 10000. This value was selected so that the minor // GC cycle time is bounded to 20 ms in a case where the new space size // is 16 MB and it is full of wrappers (which is almost the worst case). // Practically speaking, as far as I crawled real web applications, // the number of wrappers handled by each minor GC cycle is at most 3000. // So this limit is mainly for pathological micro benchmarks. const unsigned wrappersHandledByEachMinorGC = 10000; if (m_nodesInNewSpace.size() >= wrappersHandledByEachMinorGC) return; // Casting to a Handle is safe here, since the Persistent doesn't get GCd // during the GC prologue. ASSERT((*reinterpret_cast<v8::Handle<v8::Value>*>(value))->IsObject()); v8::Handle<v8::Object>* wrapper = reinterpret_cast<v8::Handle<v8::Object>*>(value); ASSERT(V8DOMWrapper::isDOMWrapper(*wrapper)); ASSERT(V8Node::hasInstance(*wrapper, m_isolate)); Node* node = V8Node::toImpl(*wrapper); // A minor DOM GC can handle only node wrappers in the main world. // Note that node->wrapper().IsEmpty() returns true for nodes that // do not have wrappers in the main world. if (node->containsWrapper()) { const WrapperTypeInfo* type = toWrapperTypeInfo(*wrapper); ActiveDOMObject* activeDOMObject = type->toActiveDOMObject(*wrapper); if (activeDOMObject && activeDOMObject->hasPendingActivity()) return; // FIXME: Remove the special handling for image elements. // The same special handling is in V8GCController::opaqueRootForGC(). // Maybe should image elements be active DOM nodes? // See https://code.google.com/p/chromium/issues/detail?id=164882 if (isHTMLImageElement(*node) && toHTMLImageElement(*node).hasPendingActivity()) return; // FIXME: Remove the special handling for SVG elements. // We currently can't collect SVG Elements from minor gc, as we have // strong references from SVG property tear-offs keeping context SVG element alive. if (node->isSVGElement()) return; m_nodesInNewSpace.append(node); node->markV8CollectableDuringMinorGC(); } }
void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t classId) override { if (classId != WrapperTypeInfo::NodeClassId && classId != WrapperTypeInfo::ObjectClassId) { return; } // MinorGC does not collect objects because it may be expensive to // update references during minorGC if (classId == WrapperTypeInfo::ObjectClassId) { v8::Persistent<v8::Object>::Cast(*value).MarkActive(); return; } v8::Local<v8::Object> wrapper = v8::Local<v8::Object>::New(m_isolate, v8::Persistent<v8::Object>::Cast(*value)); ASSERT(V8DOMWrapper::hasInternalFieldsSet(wrapper)); const WrapperTypeInfo* type = toWrapperTypeInfo(wrapper); if (type != npObjectTypeInfo() && toScriptWrappable(wrapper)->hasPendingActivity()) { v8::Persistent<v8::Object>::Cast(*value).MarkActive(); return; } if (classId == WrapperTypeInfo::NodeClassId) { ASSERT(V8Node::hasInstance(wrapper, m_isolate)); Node* node = V8Node::toImpl(wrapper); if (node->hasEventListeners()) { v8::Persistent<v8::Object>::Cast(*value).MarkActive(); return; } // FIXME: Remove the special handling for image elements. // The same special handling is in V8GCController::opaqueRootForGC(). // Maybe should image elements be active DOM nodes? // See https://code.google.com/p/chromium/issues/detail?id=164882 if (isHTMLImageElement(*node) && toHTMLImageElement(*node).hasPendingActivity()) { v8::Persistent<v8::Object>::Cast(*value).MarkActive(); return; } // FIXME: Remove the special handling for SVG elements. // We currently can't collect SVG Elements from minor gc, as we have // strong references from SVG property tear-offs keeping context SVG element alive. if (node->isSVGElement()) { v8::Persistent<v8::Object>::Cast(*value).MarkActive(); return; } } }
ArrayBuffer* V8ArrayBuffer::toNative(v8::Handle<v8::Object> object) { ASSERT(object->IsArrayBuffer()); v8::Local<v8::ArrayBuffer> v8buffer = object.As<v8::ArrayBuffer>(); if (v8buffer->IsExternal()) { RELEASE_ASSERT(toWrapperTypeInfo(object)->ginEmbedder == gin::kEmbedderBlink); return reinterpret_cast<ArrayBuffer*>(blink::toScriptWrappableBase(object)); } v8::ArrayBuffer::Contents v8Contents = v8buffer->Externalize(); ArrayBufferContents contents(v8Contents.Data(), v8Contents.ByteLength(), V8ArrayBufferDeallocationObserver::instanceTemplate()); RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(contents); V8DOMWrapper::associateObjectWithWrapper<V8ArrayBuffer>(buffer.release(), &wrapperTypeInfo, object, v8::Isolate::GetCurrent()); return reinterpret_cast<ArrayBuffer*>(blink::toScriptWrappableBase(object)); }
TestArrayBuffer* V8ArrayBuffer::toImpl(v8::Local<v8::Object> object) { ASSERT(object->IsArrayBuffer()); v8::Local<v8::ArrayBuffer> v8buffer = object.As<v8::ArrayBuffer>(); if (v8buffer->IsExternal()) { const WrapperTypeInfo* wrapperTypeInfo = toWrapperTypeInfo(object); RELEASE_ASSERT(wrapperTypeInfo); RELEASE_ASSERT(wrapperTypeInfo->ginEmbedder == gin::kEmbedderBlink); return toScriptWrappable(object)->toImpl<TestArrayBuffer>(); } // Transfer the ownership of the allocated memory to an ArrayBuffer without // copying. v8::ArrayBuffer::Contents v8Contents = v8buffer->Externalize(); WTF::ArrayBufferContents contents(v8Contents.Data(), v8Contents.ByteLength(), WTF::ArrayBufferContents::NotShared); TestArrayBuffer* buffer = TestArrayBuffer::create(contents); v8::Local<v8::Object> associatedWrapper = buffer->associateWithWrapper(v8::Isolate::GetCurrent(), buffer->wrapperTypeInfo(), object); ASSERT_UNUSED(associatedWrapper, associatedWrapper == object); return buffer; }
void V8InspectorFrontendHost::showContextMenuMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info) { if (info.Length() < 2) return; v8::Local<v8::Object> eventWrapper = v8::Local<v8::Object>::Cast(info[0]); if (!V8MouseEvent::wrapperTypeInfo.equals(toWrapperTypeInfo(eventWrapper))) return; Event* event = V8Event::toNative(eventWrapper); if (!info[1]->IsArray()) return; v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(info[1]); ContextMenu menu; if (!populateContextMenuItems(array, menu, info.GetIsolate())) return; InspectorFrontendHost* frontendHost = V8InspectorFrontendHost::toNative(info.Holder()); Vector<ContextMenuItem> items = menu.items(); frontendHost->showContextMenu(event, items); }
static bool getRangeImpl(NPObject* object, WebRange* webRange, v8::Isolate* isolate) { if (!object) return false; V8NPObject* v8NPObject = npObjectToV8NPObject(object); if (!v8NPObject) return false; v8::HandleScope handleScope(isolate); v8::Local<v8::Object> v8Object = v8::Local<v8::Object>::New(isolate, v8NPObject->v8Object); if (v8Object.IsEmpty()) return false; if (!V8Range::wrapperTypeInfo.equals(toWrapperTypeInfo(v8Object))) return false; Range* native = V8Range::hasInstance(v8Object, isolate) ? V8Range::toImpl(v8Object) : 0; if (!native) return false; *webRange = WebRange(native); return true; }
v8::Handle<v8::Value> V8InspectorFrontendHost::showContextMenuMethodCustom(const v8::Arguments& args) { if (args.Length() < 2) return v8::Undefined(); v8::Local<v8::Object> eventWrapper = v8::Local<v8::Object>::Cast(args[0]); if (!V8MouseEvent::info.equals(toWrapperTypeInfo(eventWrapper))) return v8::Undefined(); Event* event = V8Event::toNative(eventWrapper); if (!args[1]->IsArray()) return v8::Undefined(); v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(args[1]); ContextMenu menu; populateContextMenuItems(array, menu); InspectorFrontendHost* frontendHost = V8InspectorFrontendHost::toNative(args.Holder()); Vector<ContextMenuItem> items = menu.items(); frontendHost->showContextMenu(event, items); return v8::Undefined(); }
virtual void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t classId) override { if (classId != WrapperTypeInfo::NodeClassId && classId != WrapperTypeInfo::ObjectClassId) return; // Casting to a Handle is safe here, since the Persistent doesn't get GCd // during the GC prologue. ASSERT((*reinterpret_cast<v8::Handle<v8::Value>*>(value))->IsObject()); v8::Handle<v8::Object>* wrapper = reinterpret_cast<v8::Handle<v8::Object>*>(value); ASSERT(V8DOMWrapper::isDOMWrapper(*wrapper)); if (value->IsIndependent()) return; const WrapperTypeInfo* type = toWrapperTypeInfo(*wrapper); ActiveDOMObject* activeDOMObject = type->toActiveDOMObject(*wrapper); if (activeDOMObject && activeDOMObject->hasPendingActivity()) { m_isolate->SetObjectGroupId(*value, liveRootId()); ++m_domObjectsWithPendingActivity; } if (classId == WrapperTypeInfo::NodeClassId) { ASSERT(V8Node::hasInstance(*wrapper, m_isolate)); Node* node = V8Node::toImpl(*wrapper); if (node->hasEventListeners()) addReferencesForNodeWithEventListeners(m_isolate, node, v8::Persistent<v8::Object>::Cast(*value)); Node* root = V8GCController::opaqueRootForGC(m_isolate, node); m_isolate->SetObjectGroupId(*value, v8::UniqueId(reinterpret_cast<intptr_t>(root))); if (m_constructRetainedObjectInfos) m_groupsWhichNeedRetainerInfo.append(root); } else if (classId == WrapperTypeInfo::ObjectClassId) { type->visitDOMWrapper(m_isolate, toScriptWrappableBase(*wrapper), v8::Persistent<v8::Object>::Cast(*value)); } else { ASSERT_NOT_REACHED(); } }
void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t classId) override { if (classId != WrapperTypeInfo::NodeClassId && classId != WrapperTypeInfo::ObjectClassId) return; v8::Local<v8::Object> wrapper = v8::Local<v8::Object>::New(m_isolate, v8::Persistent<v8::Object>::Cast(*value)); ASSERT(V8DOMWrapper::hasInternalFieldsSet(wrapper)); const WrapperTypeInfo* type = toWrapperTypeInfo(wrapper); if (type != npObjectTypeInfo() && toScriptWrappable(wrapper)->hasPendingActivity()) { // If you hit this assert, you'll need to add a [DependentiLifetime] // extended attribute to the DOM interface. A DOM interface that // overrides hasPendingActivity must be marked as [DependentiLifetime]. RELEASE_ASSERT(!value->IsIndependent()); m_isolate->SetObjectGroupId(*value, liveRootId()); ++m_domObjectsWithPendingActivity; } if (value->IsIndependent()) return; if (classId == WrapperTypeInfo::NodeClassId) { ASSERT(V8Node::hasInstance(wrapper, m_isolate)); Node* node = V8Node::toImpl(wrapper); if (node->hasEventListeners()) addReferencesForNodeWithEventListeners(m_isolate, node, v8::Persistent<v8::Object>::Cast(*value)); Node* root = V8GCController::opaqueRootForGC(m_isolate, node); m_isolate->SetObjectGroupId(*value, v8::UniqueId(reinterpret_cast<intptr_t>(root))); if (m_constructRetainedObjectInfos) m_groupsWhichNeedRetainerInfo.append(root); } else if (classId == WrapperTypeInfo::ObjectClassId) { type->visitDOMWrapper(m_isolate, toScriptWrappable(wrapper), v8::Persistent<v8::Object>::Cast(*value)); } else { ASSERT_NOT_REACHED(); } }
WrapperTypeInfo* V8DOMWrapper::domWrapperType(v8::Handle<v8::Object> object) { ASSERT(V8DOMWrapper::maybeDOMWrapper(object)); return toWrapperTypeInfo(object); }