/* static */ void V8Runtime::bootstrap(Local<Context> context) { Isolate* isolate = context->GetIsolate(); EventEmitter::initTemplate(context); Local<Object> kroll = Object::New(isolate); krollGlobalObject.Reset(isolate, kroll); Local<Array> mc = Array::New(isolate); moduleContexts.Reset(isolate, mc); KrollBindings::initFunctions(kroll, context); SetMethod(isolate, kroll, "log", krollLog); // Move this into the EventEmitter::initTemplate call? Local<FunctionTemplate> eect = Local<FunctionTemplate>::New(isolate, EventEmitter::constructorTemplate); { v8::TryCatch tryCatch(isolate); Local<Function> eventEmitterConstructor; MaybeLocal<Function> maybeEventEmitterConstructor = eect->GetFunction(context); if (!maybeEventEmitterConstructor.ToLocal(&eventEmitterConstructor)) { titanium::V8Util::fatalException(isolate, tryCatch); return; } kroll->Set(NEW_SYMBOL(isolate, "EventEmitter"), eventEmitterConstructor); } kroll->Set(NEW_SYMBOL(isolate, "runtime"), STRING_NEW(isolate, "v8")); kroll->Set(NEW_SYMBOL(isolate, "DBG"), v8::Boolean::New(isolate, V8Runtime::DBG)); kroll->Set(NEW_SYMBOL(isolate, "moduleContexts"), mc); LOG_TIMER(TAG, "Executing kroll.js"); TryCatch tryCatch(isolate); Local<Value> result = V8Util::executeString(isolate, KrollBindings::getMainSource(isolate), STRING_NEW(isolate, "ti:/kroll.js")); if (tryCatch.HasCaught()) { V8Util::reportException(isolate, tryCatch, true); } if (!result->IsFunction()) { LOGF(TAG, "kroll.js result is not a function"); V8Util::reportException(isolate, tryCatch, true); } // Add a reference to the global object Local<Object> global = context->Global(); // Expose the global object as a property on itself // (Allows you to set stuff on `global` from anywhere in JavaScript.) global->Set(NEW_SYMBOL(isolate, "global"), global); Local<Function> mainFunction = result.As<Function>(); Local<Value> args[] = { kroll }; mainFunction->Call(context, global, 1, args); if (tryCatch.HasCaught()) { V8Util::reportException(isolate, tryCatch, true); LOGE(TAG, "Caught exception while bootstrapping Kroll"); } }
// https://html.spec.whatwg.org/multipage/scripting.html#upgrades bool ScriptCustomElementDefinition::runConstructor(Element* element) { if (!m_scriptState->contextIsValid()) return false; ScriptState::Scope scope(m_scriptState.get()); v8::Isolate* isolate = m_scriptState->isolate(); // Step 5 says to rethrow the exception; but there is no one to // catch it. The side effect is to report the error. v8::TryCatch tryCatch(isolate); tryCatch.SetVerbose(true); Element* result = runConstructor(); // To report exception thrown from runConstructor() if (tryCatch.HasCaught()) return false; // To report InvalidStateError Exception, when the constructor returns some // different object if (result != element) { const String& message = "custom element constructors must call super() first and must " "not return a different object"; v8::Local<v8::Value> exception = V8ThrowException::createDOMException( m_scriptState->isolate(), InvalidStateError, message); dispatchErrorEvent(isolate, exception, constructor()); return false; } return true; }
void InjectedScript::getProperties(ErrorString* errorString, v8::Local<v8::Object> object, const String16& groupName, bool ownProperties, bool accessorPropertiesOnly, bool generatePreview, std::unique_ptr<Array<PropertyDescriptor>>* properties, Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) { v8::HandleScope handles(m_context->isolate()); V8FunctionCall function(m_context->inspector(), m_context->context(), v8Value(), "getProperties"); function.appendArgument(object); function.appendArgument(groupName); function.appendArgument(ownProperties); function.appendArgument(accessorPropertiesOnly); function.appendArgument(generatePreview); v8::TryCatch tryCatch(m_context->isolate()); v8::Local<v8::Value> resultValue = function.callWithoutExceptionHandling(); if (tryCatch.HasCaught()) { *exceptionDetails = createExceptionDetails(tryCatch.Message()); // FIXME: make properties optional *properties = Array<PropertyDescriptor>::create(); return; } std::unique_ptr<protocol::Value> protocolValue = toProtocolValue(m_context->context(), resultValue); if (hasInternalError(errorString, !protocolValue)) return; protocol::ErrorSupport errors(errorString); std::unique_ptr<Array<PropertyDescriptor>> result = Array<PropertyDescriptor>::parse(protocolValue.get(), &errors); if (!hasInternalError(errorString, errors.hasErrors())) *properties = std::move(result); }
Vector<String> Dictionary::getPropertyNames( ExceptionState& exceptionState) const { if (m_dictionaryObject.IsEmpty()) return Vector<String>(); v8::TryCatch tryCatch(isolate()); v8::Local<v8::Array> propertyNames; if (!m_dictionaryObject->GetPropertyNames(v8Context()) .ToLocal(&propertyNames)) { exceptionState.rethrowV8Exception(tryCatch.Exception()); return Vector<String>(); } Vector<String> names; for (uint32_t i = 0; i < propertyNames->Length(); ++i) { v8::Local<v8::String> key; if (!getStringValueInArray(v8Context(), propertyNames, i).ToLocal(&key)) { exceptionState.rethrowV8Exception(tryCatch.Exception()); return Vector<String>(); } V8StringResource<> stringKey(key); if (!stringKey.prepare(isolate(), exceptionState)) return Vector<String>(); names.push_back(stringKey); } return names; }
bool V0CustomElementConstructorBuilder::validateOptions(const AtomicString& type, QualifiedName& tagName, ExceptionState& exceptionState) { ASSERT(m_prototype.IsEmpty()); v8::TryCatch tryCatch(m_scriptState->isolate()); if (!m_scriptState->perContextData()) { // FIXME: This should generate an InvalidContext exception at a later point. V0CustomElementException::throwException(V0CustomElementException::ContextDestroyedCheckingPrototype, type, exceptionState); tryCatch.ReThrow(); return false; } if (m_options.hasPrototype()) { ASSERT(m_options.prototype().isObject()); m_prototype = m_options.prototype().v8Value().As<v8::Object>(); } else { m_prototype = v8::Object::New(m_scriptState->isolate()); v8::Local<v8::Object> basePrototype = m_scriptState->perContextData()->prototypeForType(&V8HTMLElement::wrapperTypeInfo); if (!basePrototype.IsEmpty()) { if (!v8CallBoolean(m_prototype->SetPrototype(m_scriptState->context(), basePrototype))) return false; } } AtomicString namespaceURI = HTMLNames::xhtmlNamespaceURI; if (hasValidPrototypeChainFor(&V8SVGElement::wrapperTypeInfo)) namespaceURI = SVGNames::svgNamespaceURI; ASSERT(!tryCatch.HasCaught()); AtomicString localName; if (m_options.hasExtends()) { localName = AtomicString(m_options.extends().lower()); if (!Document::isValidName(localName)) { V0CustomElementException::throwException(V0CustomElementException::ExtendsIsInvalidName, type, exceptionState); tryCatch.ReThrow(); return false; } if (V0CustomElement::isValidName(localName)) { V0CustomElementException::throwException(V0CustomElementException::ExtendsIsCustomElementName, type, exceptionState); tryCatch.ReThrow(); return false; } } else { if (namespaceURI == SVGNames::svgNamespaceURI) { V0CustomElementException::throwException(V0CustomElementException::ExtendsIsInvalidName, type, exceptionState); tryCatch.ReThrow(); return false; } localName = type; } ASSERT(!tryCatch.HasCaught()); tagName = QualifiedName(nullAtom, localName, namespaceURI); return true; }
static void dispatchErrorEvent(v8::Isolate* isolate, v8::Local<v8::Value> exception, v8::Local<v8::Object> constructor) { v8::TryCatch tryCatch(isolate); tryCatch.SetVerbose(true); V8ScriptRunner::throwException( isolate, exception, constructor.As<v8::Function>()->GetScriptOrigin()); }
v8::Local<v8::Value> V8ErrorHandler::callListenerFunction( ScriptState* scriptState, v8::Local<v8::Value> jsEvent, Event* event) { ASSERT(!jsEvent.IsEmpty()); if (!event->hasInterface(EventNames::ErrorEvent)) return V8EventListener::callListenerFunction(scriptState, jsEvent, event); ErrorEvent* errorEvent = static_cast<ErrorEvent*>(event); if (errorEvent->world() && errorEvent->world() != &world()) return v8::Null(isolate()); v8::Local<v8::Object> listener = getListenerObject(scriptState->getExecutionContext()); if (listener.IsEmpty() || !listener->IsFunction()) return v8::Null(isolate()); v8::Local<v8::Function> callFunction = v8::Local<v8::Function>::Cast(listener); v8::Local<v8::Object> thisValue = scriptState->context()->Global(); v8::Local<v8::Object> eventObject; if (!jsEvent->ToObject(scriptState->context()).ToLocal(&eventObject)) return v8::Null(isolate()); auto privateError = V8PrivateProperty::getErrorEventError(isolate()); v8::Local<v8::Value> error = privateError.getOrUndefined(scriptState->context(), eventObject); if (error->IsUndefined()) error = v8::Null(isolate()); v8::Local<v8::Value> parameters[5] = { v8String(isolate(), errorEvent->message()), v8String(isolate(), errorEvent->filename()), v8::Integer::New(isolate(), errorEvent->lineno()), v8::Integer::New(isolate(), errorEvent->colno()), error}; v8::TryCatch tryCatch(isolate()); tryCatch.SetVerbose(true); v8::MaybeLocal<v8::Value> result; if (scriptState->getExecutionContext()->isWorkerGlobalScope()) { result = V8ScriptRunner::callFunction( callFunction, scriptState->getExecutionContext(), thisValue, WTF_ARRAY_LENGTH(parameters), parameters, isolate()); } else { result = V8ScriptRunner::callFunction( callFunction, scriptState->getExecutionContext(), thisValue, WTF_ARRAY_LENGTH(parameters), parameters, isolate()); } v8::Local<v8::Value> returnValue; if (!result.ToLocal(&returnValue)) return v8::Null(isolate()); return returnValue; }
int V8Regex::match(const String16& string, int startFrom, int* matchLength) const { if (matchLength) *matchLength = 0; if (m_regex.IsEmpty() || string.isEmpty()) return -1; // v8 strings are limited to int. if (string.length() > INT_MAX) return -1; v8::Isolate* isolate = m_debugger->isolate(); v8::HandleScope handleScope(isolate); v8::Local<v8::Context> context = m_debugger->regexContext(); v8::MicrotasksScope microtasks(isolate, v8::MicrotasksScope::kDoNotRunMicrotasks); v8::TryCatch tryCatch(isolate); v8::Local<v8::RegExp> regex = m_regex.Get(isolate); v8::Local<v8::Value> exec; if (!regex->Get(context, toV8StringInternalized(isolate, "exec")).ToLocal(&exec)) return -1; v8::Local<v8::Value> argv[] = { toV8String(isolate, string.substring(startFrom)) }; v8::Local<v8::Value> returnValue; if (!exec.As<v8::Function>()->Call(context, regex, WTF_ARRAY_LENGTH(argv), argv).ToLocal(&returnValue)) return -1; // RegExp#exec returns null if there's no match, otherwise it returns an // Array of strings with the first being the whole match string and others // being subgroups. The Array also has some random properties tacked on like // "index" which is the offset of the match. // // https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/exec ASSERT(!returnValue.IsEmpty()); if (!returnValue->IsArray()) return -1; v8::Local<v8::Array> result = returnValue.As<v8::Array>(); v8::Local<v8::Value> matchOffset; if (!result->Get(context, toV8StringInternalized(isolate, "index")).ToLocal(&matchOffset)) return -1; if (matchLength) { v8::Local<v8::Value> match; if (!result->Get(context, 0).ToLocal(&match)) return -1; *matchLength = match.As<v8::String>()->Length(); } return matchOffset.As<v8::Int32>()->Value() + startFrom; }
bool ScriptCustomElementDefinitionBuilder::valueForName( const v8::Local<v8::Object>& object, const String& name, v8::Local<v8::Value>& value) const { v8::Isolate* isolate = m_scriptState->isolate(); v8::Local<v8::Context> context = m_scriptState->context(); v8::Local<v8::String> nameString = v8String(isolate, name); v8::TryCatch tryCatch(isolate); if (!v8Call(object->Get(context, nameString), value, tryCatch)) { m_exceptionState.rethrowV8Exception(tryCatch.Exception()); return false; } return true; }
bool Dictionary::getInternal(const v8::Local<v8::Value>& key, v8::Local<v8::Value>& result) const { if (m_dictionaryObject.IsEmpty()) return false; if (!v8CallBoolean(m_dictionaryObject->Has(v8Context(), key))) return false; // Swallow a possible exception in v8::Object::Get(). // TODO(bashi,yukishiino): Should rethrow the exception. // http://crbug.com/666661 v8::TryCatch tryCatch(isolate()); return m_dictionaryObject->Get(v8Context(), key).ToLocal(&result); }
void V8AbstractEventListener::invokeEventHandler(ScriptState* scriptState, Event* event, v8::Local<v8::Value> jsEvent) { if (!event->canBeDispatchedInWorld(world())) return; v8::Local<v8::Value> returnValue; { // Catch exceptions thrown in the event handler so they do not propagate to javascript code that caused the event to fire. v8::TryCatch tryCatch(isolate()); tryCatch.SetVerbose(true); // Save the old 'event' property so we can restore it later. v8::Local<v8::Value> savedEvent = V8HiddenValue::getHiddenValue(scriptState, scriptState->context()->Global(), V8HiddenValue::event(isolate())); tryCatch.Reset(); // Make the event available in the global object, so LocalDOMWindow can expose it. V8HiddenValue::setHiddenValue(scriptState, scriptState->context()->Global(), V8HiddenValue::event(isolate()), jsEvent); tryCatch.Reset(); returnValue = callListenerFunction(scriptState, jsEvent, event); if (tryCatch.HasCaught()) event->target()->uncaughtExceptionInEventHandler(); if (!tryCatch.CanContinue()) { // Result of TerminateExecution(). if (scriptState->executionContext()->isWorkerGlobalScope()) toWorkerGlobalScope(scriptState->executionContext())->scriptController()->forbidExecution(); return; } tryCatch.Reset(); // Restore the old event. This must be done for all exit paths through this method. if (savedEvent.IsEmpty()) V8HiddenValue::setHiddenValue(scriptState, scriptState->context()->Global(), V8HiddenValue::event(isolate()), v8::Undefined(isolate())); else V8HiddenValue::setHiddenValue(scriptState, scriptState->context()->Global(), V8HiddenValue::event(isolate()), savedEvent); tryCatch.Reset(); } if (returnValue.IsEmpty()) return; if (m_isAttribute && !returnValue->IsNull() && !returnValue->IsUndefined() && event->isBeforeUnloadEvent()) { TOSTRING_VOID(V8StringResource<>, stringReturnValue, returnValue); toBeforeUnloadEvent(event)->setReturnValue(stringReturnValue); } if (m_isAttribute && shouldPreventDefault(returnValue)) event->preventDefault(); }
bool Dictionary::hasProperty(const StringView& key, ExceptionState& exceptionState) const { if (m_dictionaryObject.IsEmpty()) return false; v8::TryCatch tryCatch(m_isolate); bool hasKey = false; if (!m_dictionaryObject->Has(v8Context(), v8String(m_isolate, key)) .To(&hasKey)) { exceptionState.rethrowV8Exception(tryCatch.Exception()); return false; } return hasKey; }
AtomicString V8CustomXPathNSResolver::lookupNamespaceURI(const String& prefix) { v8::Isolate* isolate = m_scriptState->isolate(); v8::Local<v8::Function> lookupNamespaceURIFunc; v8::Local<v8::String> lookupNamespaceURIName = v8AtomicString(isolate, "lookupNamespaceURI"); // Check if the resolver has a function property named lookupNamespaceURI. v8::Local<v8::Value> lookupNamespaceURI; if (m_resolver->Get(m_scriptState->context(), lookupNamespaceURIName) .ToLocal(&lookupNamespaceURI) && lookupNamespaceURI->IsFunction()) lookupNamespaceURIFunc = v8::Local<v8::Function>::Cast(lookupNamespaceURI); if (lookupNamespaceURIFunc.IsEmpty() && !m_resolver->IsFunction()) { LocalFrame* frame = toLocalDOMWindow(toDOMWindow(m_scriptState->context()))->frame(); if (frame && frame->host()) frame->console().addMessage(ConsoleMessage::create( JSMessageSource, ErrorMessageLevel, "XPathNSResolver does not have a lookupNamespaceURI method.")); return nullAtom; } // Catch exceptions from calling the namespace resolver. v8::TryCatch tryCatch(isolate); tryCatch.SetVerbose(true); // Print exceptions to console. const int argc = 1; v8::Local<v8::Value> argv[argc] = {v8String(isolate, prefix)}; v8::Local<v8::Function> function = lookupNamespaceURIFunc.IsEmpty() ? v8::Local<v8::Function>::Cast(m_resolver) : lookupNamespaceURIFunc; v8::Local<v8::Value> retval; // Eat exceptions from namespace resolver and return an empty string. This // will most likely cause NamespaceError. if (!V8ScriptRunner::callFunction( function, toExecutionContext(m_scriptState->context()), m_resolver, argc, argv, isolate) .ToLocal(&retval)) return nullAtom; TOSTRING_DEFAULT(V8StringResource<TreatNullAsNullString>, returnString, retval, nullAtom); return returnString; }
v8::Local<v8::Value> ScriptController::executeScriptAndReturnValue(v8::Local<v8::Context> context, const ScriptSourceCode& source, AccessControlStatus accessControlStatus, double* compilationFinishTime) { TRACE_EVENT1("devtools.timeline", "EvaluateScript", "data", InspectorEvaluateScriptEvent::data(frame(), source.url().getString(), source.startPosition())); InspectorInstrumentation::NativeBreakpoint nativeBreakpoint(frame()->document(), "scriptFirstStatement", false); v8::Local<v8::Value> result; { V8CacheOptions v8CacheOptions(V8CacheOptionsDefault); if (frame()->settings()) v8CacheOptions = frame()->settings()->v8CacheOptions(); if (source.resource() && !source.resource()->response().cacheStorageCacheName().isNull()) { switch (frame()->settings()->v8CacheStrategiesForCacheStorage()) { case V8CacheStrategiesForCacheStorage::None: v8CacheOptions = V8CacheOptionsNone; break; case V8CacheStrategiesForCacheStorage::Normal: v8CacheOptions = V8CacheOptionsCode; break; case V8CacheStrategiesForCacheStorage::Default: case V8CacheStrategiesForCacheStorage::Aggressive: v8CacheOptions = V8CacheOptionsAlways; break; } } // Isolate exceptions that occur when compiling and executing // the code. These exceptions should not interfere with // javascript code we might evaluate from C++ when returning // from here. v8::TryCatch tryCatch(isolate()); tryCatch.SetVerbose(true); v8::Local<v8::Script> script; if (!v8Call(V8ScriptRunner::compileScript(source, isolate(), accessControlStatus, v8CacheOptions), script, tryCatch)) return result; if (compilationFinishTime) { *compilationFinishTime = WTF::monotonicallyIncreasingTime(); } if (!v8Call(V8ScriptRunner::runCompiledScript(isolate(), script, frame()->document()), result, tryCatch)) return result; } TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateCounters", TRACE_EVENT_SCOPE_THREAD, "data", InspectorUpdateCountersEvent::data()); return result; }
void V8InjectedScriptHost::evaluateWithExceptionDetailsCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { v8::Isolate* isolate = info.GetIsolate(); if (info.Length() < 1) { isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "One argument expected."))); return; } v8::Local<v8::String> expression = info[0]->ToString(isolate); if (expression.IsEmpty()) { isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "The argument must be a string."))); return; } ASSERT(isolate->InContext()); v8::Local<v8::Object> wrappedResult = v8::Object::New(isolate); if (wrappedResult.IsEmpty()) return; v8::TryCatch tryCatch(isolate); v8::Local<v8::Script> script; v8::Local<v8::Value> result; if (!v8Call(V8ScriptRunner::compileScript(expression, String(), String(), TextPosition(), isolate), script, tryCatch)) { setExceptionAsReturnValue(info, wrappedResult, tryCatch); return; } v8::Local<v8::Symbol> commandLineAPISymbolValue = commandLineAPISymbol(isolate); v8::Local<v8::Object> global = isolate->GetCurrentContext()->Global(); if (info.Length() >= 2 && info[1]->IsObject()) { v8::Local<v8::Object> commandLineAPI = info[1]->ToObject(isolate); global->Set(commandLineAPISymbolValue, commandLineAPI); } if (!v8Call(V8ScriptRunner::runCompiledScript(isolate, script, currentExecutionContext(isolate)), result, tryCatch)) { global->Delete(isolate->GetCurrentContext(), commandLineAPISymbolValue); setExceptionAsReturnValue(info, wrappedResult, tryCatch); return; } global->Delete(isolate->GetCurrentContext(), commandLineAPISymbolValue); wrappedResult->Set(v8::String::NewFromUtf8(isolate, "result"), result); wrappedResult->Set(v8::String::NewFromUtf8(isolate, "exceptionDetails"), v8::Undefined(isolate)); v8SetReturnValue(info, wrappedResult); }
/* static */ void V8Runtime::bootstrap(Local<Context> context) { Isolate* isolate = context->GetIsolate(); EventEmitter::initTemplate(context); Local<Object> global = Object::New(isolate); krollGlobalObject.Reset(isolate, global); Local<Array> mc = Array::New(isolate); moduleContexts.Reset(isolate, mc); KrollBindings::initFunctions(global, context); SetMethod(isolate, global, "log", krollLog); // Move this into the EventEmitter::initTemplate call? Local<FunctionTemplate> eect = Local<FunctionTemplate>::New(isolate, EventEmitter::constructorTemplate); global->Set(NEW_SYMBOL(isolate, "EventEmitter"), eect->GetFunction()); global->Set(NEW_SYMBOL(isolate, "runtime"), STRING_NEW(isolate, "v8")); global->Set(NEW_SYMBOL(isolate, "DBG"), v8::Boolean::New(isolate, V8Runtime::DBG)); global->Set(NEW_SYMBOL(isolate, "moduleContexts"), mc); LOG_TIMER(TAG, "Executing kroll.js"); TryCatch tryCatch(isolate); Local<Value> result = V8Util::executeString(isolate, KrollBindings::getMainSource(isolate), STRING_NEW(isolate, "ti:/kroll.js")); if (tryCatch.HasCaught()) { V8Util::reportException(isolate, tryCatch, true); } if (!result->IsFunction()) { LOGF(TAG, "kroll.js result is not a function"); V8Util::reportException(isolate, tryCatch, true); } Local<Function> mainFunction = result.As<Function>(); Local<Value> args[] = { global }; mainFunction->Call(context, context->Global(), 1, args); if (tryCatch.HasCaught()) { V8Util::reportException(isolate, tryCatch, true); LOGE(TAG, "Caught exception while bootstrapping Kroll"); } }
V8Regex::V8Regex(V8DebuggerImpl* debugger, const String16& pattern, bool caseSensitive, bool multiline) : m_debugger(debugger) { v8::Isolate* isolate = m_debugger->isolate(); v8::HandleScope handleScope(isolate); v8::Local<v8::Context> context = m_debugger->regexContext(); v8::Context::Scope contextScope(context); v8::TryCatch tryCatch(isolate); unsigned flags = v8::RegExp::kNone; if (!caseSensitive) flags |= v8::RegExp::kIgnoreCase; if (multiline) flags |= v8::RegExp::kMultiline; v8::Local<v8::RegExp> regex; if (v8::RegExp::New(context, toV8String(isolate, pattern), static_cast<v8::RegExp::Flags>(flags)).ToLocal(®ex)) m_regex.Reset(isolate, regex); }
void ScriptCustomElementDefinition::runCallback( v8::Local<v8::Function> callback, Element* element, int argc, v8::Local<v8::Value> argv[]) { DCHECK(ScriptState::current(m_scriptState->isolate()) == m_scriptState); v8::Isolate* isolate = m_scriptState->isolate(); // Invoke custom element reactions // https://html.spec.whatwg.org/multipage/scripting.html#invoke-custom-element-reactions // If this throws any exception, then report the exception. v8::TryCatch tryCatch(isolate); tryCatch.SetVerbose(true); ExecutionContext* executionContext = m_scriptState->getExecutionContext(); v8::Local<v8::Value> elementHandle = toV8(element, m_scriptState->context()->Global(), isolate); V8ScriptRunner::callFunction(callback, executionContext, elementHandle, argc, argv, isolate); }
v8::Local<v8::Value> JavaScriptCallFrame::evaluateWithExceptionDetails(v8::Local<v8::Value> expression, v8::Local<v8::Value> scopeExtension) { v8::Local<v8::Object> callFrame = m_callFrame.newLocal(m_isolate); v8::Local<v8::Function> evalFunction = v8::Local<v8::Function>::Cast(callFrame->Get(v8AtomicString(m_isolate, "evaluate"))); v8::Local<v8::Value> argv[] = { expression, scopeExtension }; v8::TryCatch tryCatch(m_isolate); v8::Local<v8::Object> wrappedResult = v8::Object::New(m_isolate); v8::Local<v8::Value> result; if (V8ScriptRunner::callInternalFunction(evalFunction, callFrame, WTF_ARRAY_LENGTH(argv), argv, m_isolate).ToLocal(&result)) { wrappedResult->Set(v8::String::NewFromUtf8(m_isolate, "result"), result); wrappedResult->Set(v8::String::NewFromUtf8(m_isolate, "exceptionDetails"), v8::Undefined(m_isolate)); } else { wrappedResult->Set(v8::String::NewFromUtf8(m_isolate, "result"), tryCatch.Exception()); wrappedResult->Set(v8::String::NewFromUtf8(m_isolate, "exceptionDetails"), createExceptionDetails(m_isolate, tryCatch.Message())); } return wrappedResult; }
HashMap<String, String> Dictionary::getOwnPropertiesAsStringHashMap( ExceptionState& exceptionState) const { if (m_dictionaryObject.IsEmpty()) return HashMap<String, String>(); v8::TryCatch tryCatch(isolate()); v8::Local<v8::Array> propertyNames; if (!m_dictionaryObject->GetOwnPropertyNames(v8Context()) .ToLocal(&propertyNames)) { exceptionState.rethrowV8Exception(tryCatch.Exception()); return HashMap<String, String>(); } HashMap<String, String> ownProperties; for (uint32_t i = 0; i < propertyNames->Length(); ++i) { v8::Local<v8::String> key; if (!getStringValueInArray(v8Context(), propertyNames, i).ToLocal(&key)) { exceptionState.rethrowV8Exception(tryCatch.Exception()); return HashMap<String, String>(); } V8StringResource<> stringKey(key); if (!stringKey.prepare(isolate(), exceptionState)) return HashMap<String, String>(); v8::Local<v8::Value> value; if (!m_dictionaryObject->Get(v8Context(), key).ToLocal(&value)) { exceptionState.rethrowV8Exception(tryCatch.Exception()); return HashMap<String, String>(); } V8StringResource<> stringValue(value); if (!stringValue.prepare(isolate(), exceptionState)) return HashMap<String, String>(); if (!static_cast<const String&>(stringKey).isEmpty()) ownProperties.set(stringKey, stringValue); } return ownProperties; }
void V8InjectedScriptHost::evalCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { v8::Isolate* isolate = info.GetIsolate(); if (info.Length() < 1) { isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "One argument expected."))); return; } v8::Local<v8::String> expression = info[0]->ToString(isolate); if (expression.IsEmpty()) { isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "The argument must be a string."))); return; } ASSERT(isolate->InContext()); v8::TryCatch tryCatch(isolate); v8::Local<v8::Value> result; if (!v8Call(V8ScriptRunner::compileAndRunInternalScript(expression, info.GetIsolate()), result, tryCatch)) { v8SetReturnValue(info, tryCatch.ReThrow()); return; } v8SetReturnValue(info, result); }
HTMLElement* ScriptCustomElementDefinition::createElementSync( Document& document, const QualifiedName& tagName, ExceptionState& exceptionState) { DCHECK(ScriptState::current(m_scriptState->isolate()) == m_scriptState); // Create an element // https://dom.spec.whatwg.org/#concept-create-element // 6. If definition is non-null // 6.1. If the synchronous custom elements flag is set: // 6.1.2. Set result to Construct(C). Rethrow any exceptions. // Create an element and push to the construction stack. // V8HTMLElement::constructorCustom() can only refer to // window.document(), but it is different from the document here // when it is an import document. This is not exactly what the // spec defines, but the public behavior matches to the spec. Element* element = createElementForConstructor(document); { ConstructionStackScope constructionStackScope(this, element); v8::TryCatch tryCatch(m_scriptState->isolate()); element = runConstructor(); if (tryCatch.HasCaught()) { exceptionState.rethrowV8Exception(tryCatch.Exception()); return nullptr; } } // 6.1.3. through 6.1.9. checkConstructorResult(element, document, tagName, exceptionState); if (exceptionState.hadException()) return nullptr; DCHECK_EQ(element->getCustomElementState(), CustomElementState::Custom); return toHTMLElement(element); }
// https://html.spec.whatwg.org/multipage/dom.html#html-element-constructors void V8HTMLConstructor::htmlConstructor( const v8::FunctionCallbackInfo<v8::Value>& info, const WrapperTypeInfo& wrapperTypeInfo, const HTMLElementType elementInterfaceName) { TRACE_EVENT0("blink", "HTMLConstructor"); DCHECK(info.IsConstructCall()); v8::Isolate* isolate = info.GetIsolate(); ScriptState* scriptState = ScriptState::current(isolate); v8::Local<v8::Value> newTarget = info.NewTarget(); if (!scriptState->contextIsValid()) { V8ThrowException::throwError(isolate, "The context has been destroyed"); return; } if (!RuntimeEnabledFeatures::customElementsV1Enabled() || !scriptState->world().isMainWorld()) { V8ThrowException::throwTypeError(isolate, "Illegal constructor"); return; } // 2. If NewTarget is equal to the active function object, then // throw a TypeError and abort these steps. v8::Local<v8::Function> activeFunctionObject = scriptState->perContextData()->constructorForType( &V8HTMLElement::wrapperTypeInfo); if (newTarget == activeFunctionObject) { V8ThrowException::throwTypeError(isolate, "Illegal constructor"); return; } LocalDOMWindow* window = scriptState->domWindow(); CustomElementRegistry* registry = window->customElements(); // 3. Let definition be the entry in registry with constructor equal to // NewTarget. // If there is no such definition, then throw a TypeError and abort these // steps. ScriptCustomElementDefinition* definition = ScriptCustomElementDefinition::forConstructor(scriptState, registry, newTarget); if (!definition) { V8ThrowException::throwTypeError(isolate, "Illegal constructor"); return; } const AtomicString& localName = definition->descriptor().localName(); const AtomicString& name = definition->descriptor().name(); if (localName == name) { // Autonomous custom element // 4.1. If the active function object is not HTMLElement, then throw a // TypeError if (!V8HTMLElement::wrapperTypeInfo.equals(&wrapperTypeInfo)) { V8ThrowException::throwTypeError(isolate, "Illegal constructor: autonomous custom " "elements must extend HTMLElement"); return; } } else { // Customized built-in element // 5. If local name is not valid for interface, throw TypeError if (htmlElementTypeForTag(localName) != elementInterfaceName) { V8ThrowException::throwTypeError(isolate, "Illegal constructor: localName does " "not match the HTML element interface"); return; } } ExceptionState exceptionState(isolate, ExceptionState::ConstructionContext, "HTMLElement"); v8::TryCatch tryCatch(isolate); // 6. Let prototype be Get(NewTarget, "prototype"). Rethrow any exceptions. v8::Local<v8::Value> prototype; v8::Local<v8::String> prototypeString = v8AtomicString(isolate, "prototype"); if (!v8Call(newTarget.As<v8::Object>()->Get(scriptState->context(), prototypeString), prototype)) { return; } // 7. If Type(prototype) is not Object, then: ... if (!prototype->IsObject()) { if (V8PerContextData* perContextData = V8PerContextData::from( newTarget.As<v8::Object>()->CreationContext())) { prototype = perContextData->prototypeForType(&V8HTMLElement::wrapperTypeInfo); } else { V8ThrowException::throwError(isolate, "The context has been destroyed"); return; } } // 8. If definition's construction stack is empty... Element* element; if (definition->constructionStack().isEmpty()) { // This is an element being created with 'new' from script element = definition->createElementForConstructor(*window->document()); } else { element = definition->constructionStack().last(); if (element) { // This is an element being upgraded that has called super definition->constructionStack().last().clear(); } else { // During upgrade an element has invoked the same constructor // before calling 'super' and that invocation has poached the // element. exceptionState.throwDOMException(InvalidStateError, "this instance is already constructed"); return; } } const WrapperTypeInfo* wrapperType = element->wrapperTypeInfo(); v8::Local<v8::Object> wrapper = V8DOMWrapper::associateObjectWithWrapper( isolate, element, wrapperType, info.Holder()); // If the element had a wrapper, we now update and return that // instead. v8SetReturnValue(info, wrapper); // 11. Perform element.[[SetPrototypeOf]](prototype). Rethrow any exceptions. // Note: I don't think this prototype set *can* throw exceptions. wrapper->SetPrototype(scriptState->context(), prototype.As<v8::Object>()) .ToChecked(); }