JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { ExecState* exec = toJS(ctx); JSLockHolder locker(exec); if (!object) return 0; JSObject* jsObject = toJS(object); ConstructData constructData; ConstructType constructType = jsObject->methodTable()->getConstructData(jsObject, constructData); if (constructType == ConstructType::None) return 0; MarkedArgumentBuffer argList; for (size_t i = 0; i < argumentCount; i++) argList.append(toJS(exec, arguments[i])); JSObjectRef result = toRef(profiledConstruct(exec, ProfilingReason::API, jsObject, constructType, constructData, argList)); if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) result = 0; return result; }
JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); JSObject* jsObject = toJS(object); ConstructData constructData; ConstructType constructType = jsObject->methodTable()->getConstructData(jsObject, constructData); if (constructType == ConstructTypeNone) return 0; MarkedArgumentBuffer argList; for (size_t i = 0; i < argumentCount; i++) argList.append(toJS(exec, arguments[i])); JSObjectRef result = toRef(construct(exec, jsObject, constructType, constructData, argList)); if (exec->hadException()) { if (exception) *exception = toRef(exec, exec->exception()); exec->clearException(); result = 0; } return result; }
JSValue iteratorNext(ExecState* exec, JSValue iterator, JSValue value) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSValue nextFunction = iterator.get(exec, vm.propertyNames->next); RETURN_IF_EXCEPTION(scope, JSValue()); CallData nextFunctionCallData; CallType nextFunctionCallType = getCallData(nextFunction, nextFunctionCallData); if (nextFunctionCallType == CallType::None) return throwTypeError(exec, scope); MarkedArgumentBuffer nextFunctionArguments; if (!value.isEmpty()) nextFunctionArguments.append(value); JSValue result = call(exec, nextFunction, nextFunctionCallType, nextFunctionCallData, iterator, nextFunctionArguments); RETURN_IF_EXCEPTION(scope, JSValue()); if (!result.isObject()) return throwTypeError(exec, scope, ASCIILiteral("Iterator result interface is not an object.")); return result; }
JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { ExecState* exec = toJS(ctx); VM& vm = exec->vm(); JSLockHolder locker(vm); auto scope = DECLARE_CATCH_SCOPE(vm); if (!object) return 0; JSObject* jsObject = toJS(object); JSObject* jsThisObject = toJS(thisObject); if (!jsThisObject) jsThisObject = exec->globalThisValue(); MarkedArgumentBuffer argList; for (size_t i = 0; i < argumentCount; i++) argList.append(toJS(exec, arguments[i])); if (UNLIKELY(argList.hasOverflowed())) { auto throwScope = DECLARE_THROW_SCOPE(vm); throwOutOfMemoryError(exec, throwScope); handleExceptionIfNeeded(scope, exec, exception); return 0; } CallData callData; CallType callType = jsObject->methodTable(vm)->getCallData(jsObject, callData); if (callType == CallType::None) return 0; JSValueRef result = toRef(exec, profiledCall(exec, ProfilingReason::API, jsObject, callType, callData, jsThisObject, argList)); if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow) result = 0; return result; }
JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { if (!ctx) { ASSERT_NOT_REACHED(); return 0; } ExecState* exec = toJS(ctx); JSLockHolder locker(exec); JSObject* result; if (argumentCount) { MarkedArgumentBuffer argList; for (size_t i = 0; i < argumentCount; ++i) argList.append(toJS(exec, arguments[i])); result = constructArray(exec, static_cast<ArrayAllocationProfile*>(0), argList); } else result = constructEmptyArray(exec, 0); if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) result = 0; return toRef(result); }
JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { ExecState* exec = toJS(ctx); JSLockHolder locker(exec); if (!object) return 0; JSObject* jsObject = toJS(object); JSObject* jsThisObject = toJS(thisObject); if (!jsThisObject) jsThisObject = exec->globalThisValue(); MarkedArgumentBuffer argList; for (size_t i = 0; i < argumentCount; i++) argList.append(toJS(exec, arguments[i])); CallData callData; CallType callType = jsObject->methodTable()->getCallData(jsObject, callData); if (callType == CallTypeNone) return 0; JSValueRef result = toRef(exec, call(exec, jsObject, callType, callData, jsThisObject, argList)); if (exec->hadException()) { JSValue exceptionValue = exec->exception(); if (exception) *exception = toRef(exec, exceptionValue); exec->clearException(); #if ENABLE(REMOTE_INSPECTOR) exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue); #endif result = 0; } return result; }
void ScheduledAction::executeFunctionInContext(JSGlobalObject* globalObject, JSValue thisValue) { ASSERT(m_function); JSLock lock(SilenceAssertionsOnly); CallData callData; CallType callType = m_function.get().getCallData(callData); if (callType == CallTypeNone) return; ExecState* exec = globalObject->globalExec(); MarkedArgumentBuffer args; size_t size = m_args.size(); for (size_t i = 0; i < size; ++i) args.append(m_args[i]); globalObject->globalData()->timeoutChecker.start(); JSC::call(exec, m_function, callType, callData, thisValue, args); globalObject->globalData()->timeoutChecker.stop(); if (exec->hadException()) reportCurrentException(exec); }
JSValue JSWebGLRenderingContext::getAttachedShaders(ExecState* exec) { if (exec->argumentCount() < 1) return throwSyntaxError(exec); ExceptionCode ec = 0; WebGLRenderingContext* context = static_cast<WebGLRenderingContext*>(impl()); if (exec->argumentCount() > 0 && !exec->argument(0).isUndefinedOrNull() && !exec->argument(0).inherits(&JSWebGLProgram::s_info)) return throwTypeError(exec); WebGLProgram* program = toWebGLProgram(exec->argument(0)); if (exec->hadException()) return jsNull(); Vector<RefPtr<WebGLShader> > shaders; bool succeed = context->getAttachedShaders(program, shaders, ec); if (ec) { setDOMException(exec, ec); return jsNull(); } if (!succeed) return jsNull(); MarkedArgumentBuffer list; for (size_t ii = 0; ii < shaders.size(); ++ii) list.append(toJS(exec, globalObject(), shaders[ii].get())); return constructArray(exec, globalObject(), list); }
JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); JSObject* result; if (argumentCount) { MarkedArgumentBuffer argList; for (size_t i = 0; i < argumentCount; ++i) argList.append(toJS(exec, arguments[i])); result = constructArray(exec, argList); } else result = constructEmptyArray(exec); if (exec->hadException()) { if (exception) *exception = toRef(exec, exec->exception()); exec->clearException(); result = 0; } return toRef(result); }
// ECMA 8.6.2.2 void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) { ASSERT(value); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); if (propertyName == exec->propertyNames().underscoreProto) { // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla. if (!value.isObject() && !value.isNull()) return; JSValue nextPrototypeValue = value; while (nextPrototypeValue && nextPrototypeValue.isObject()) { JSObject* nextPrototype = asObject(nextPrototypeValue)->unwrappedObject(); if (nextPrototype == this) { throwError(exec, GeneralError, "cyclic __proto__ value"); return; } nextPrototypeValue = nextPrototype->prototype(); } setPrototype(value); return; } // Check if there are any setters or getters in the prototype chain JSValue prototype; for (JSObject* obj = this; !obj->structure()->hasGetterSetterProperties(); obj = asObject(prototype)) { prototype = obj->prototype(); if (prototype.isNull()) { putDirectInternal(exec->globalData(), propertyName, value, 0, true, slot); return; } } unsigned attributes; JSCell* specificValue; if ((m_structure->get(propertyName, attributes, specificValue) != WTF::notFound) && attributes & ReadOnly) return; for (JSObject* obj = this; ; obj = asObject(prototype)) { if (JSValue gs = obj->getDirect(propertyName)) { if (gs.isGetterSetter()) { JSObject* setterFunc = asGetterSetter(gs)->setter(); if (!setterFunc) { throwSetterError(exec); return; } CallData callData; CallType callType = setterFunc->getCallData(callData); MarkedArgumentBuffer args; args.append(value); call(exec, setterFunc, callType, callData, this, args); return; } // If there's an existing property on the object or one of its // prototypes it should be replaced, so break here. break; } prototype = obj->prototype(); if (prototype.isNull()) break; } putDirectInternal(exec->globalData(), propertyName, value, 0, true, slot); return; }
JSValue RegExpObject::matchGlobal(ExecState* exec, JSGlobalObject* globalObject, JSString* string) { RegExp* regExp = this->regExp(); ASSERT(regExp->global()); VM* vm = &globalObject->vm(); setLastIndex(exec, 0); if (exec->hadException()) return jsUndefined(); String s = string->value(exec); RegExpConstructor* regExpConstructor = globalObject->regExpConstructor(); MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, s, 0); // return array of matches MarkedArgumentBuffer list; // We defend ourselves from crazy. const size_t maximumReasonableMatchSize = 1000000000; if (regExp->unicode()) { unsigned stringLength = s.length(); while (result) { if (list.size() > maximumReasonableMatchSize) { throwOutOfMemoryError(exec); return jsUndefined(); } size_t end = result.end; size_t length = end - result.start; list.append(jsSubstring(exec, s, result.start, length)); if (!length) end = advanceStringUnicode(s, stringLength, end); result = regExpConstructor->performMatch(*vm, regExp, string, s, end); } } else { while (result) { if (list.size() > maximumReasonableMatchSize) { throwOutOfMemoryError(exec); return jsUndefined(); } size_t end = result.end; size_t length = end - result.start; list.append(jsSubstring(exec, s, result.start, length)); if (!length) ++end; result = regExpConstructor->performMatch(*vm, regExp, string, s, end); } } if (list.isEmpty()) { // if there are no matches at all, it's important to return // Null instead of an empty array, because this matches // other browsers and because Null is a false value. return jsNull(); } return constructArray(exec, static_cast<ArrayAllocationProfile*>(0), list); }
void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event) { ASSERT(scriptExecutionContext); if (!scriptExecutionContext || scriptExecutionContext->isJSExecutionTerminated()) return; JSLock lock(SilenceAssertionsOnly); JSObject* jsFunction = this->jsFunction(scriptExecutionContext); if (!jsFunction) return; JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, m_isolatedWorld.get()); if (!globalObject) return; if (scriptExecutionContext->isDocument()) { JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject); Frame* frame = window->impl()->frame(); if (!frame) return; // The window must still be active in its frame. See <https://bugs.webkit.org/show_bug.cgi?id=21921>. // FIXME: A better fix for this may be to change DOMWindow::frame() to not return a frame the detached window used to be in. if (frame->domWindow() != window->impl()) return; // FIXME: Is this check needed for other contexts? ScriptController* script = frame->script(); if (!script->canExecuteScripts(AboutToExecuteScript) || script->isPaused()) return; } ExecState* exec = globalObject->globalExec(); JSValue handleEventFunction = jsFunction->get(exec, Identifier(exec, "handleEvent")); CallData callData; CallType callType = handleEventFunction.getCallData(callData); if (callType == CallTypeNone) { handleEventFunction = JSValue(); callType = jsFunction->getCallData(callData); } if (callType != CallTypeNone) { ref(); MarkedArgumentBuffer args; args.append(toJS(exec, globalObject, event)); Event* savedEvent = globalObject->currentEvent(); globalObject->setCurrentEvent(event); JSGlobalData* globalData = globalObject->globalData(); DynamicGlobalObjectScope globalObjectScope(exec, globalData->dynamicGlobalObject ? globalData->dynamicGlobalObject : globalObject); globalData->timeoutChecker.start(); JSValue retval = handleEventFunction ? JSC::call(exec, handleEventFunction, callType, callData, jsFunction, args) : JSC::call(exec, jsFunction, callType, callData, toJS(exec, globalObject, event->currentTarget()), args); globalData->timeoutChecker.stop(); globalObject->setCurrentEvent(savedEvent); if (exec->hadException()) #if PLATFORM(APOLLO) reportApolloException(globalObject); #else reportCurrentException(exec); #endif else { if (!retval.isUndefinedOrNull() && event->storesResultAsString())
void JSLazyEventListener::parseCode(ScriptExecutionContext* executionContext) const { ASSERT(executionContext); ASSERT(executionContext->isDocument()); if (!executionContext) return; if (m_parsed) return; Frame* frame = static_cast<Document*>(executionContext)->frame(); if (!frame) return; ScriptController* scriptController = frame->script(); if (!scriptController->isEnabled()) return; JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(executionContext); if (!globalObject) return; // Ensure that 'node' has a JavaScript wrapper to mark the event listener we're creating. if (m_originalNode) { JSLock lock(SilenceAssertionsOnly); // FIXME: Should pass the global object associated with the node toJS(globalObject->globalExec(), globalObject, m_originalNode); } if (executionContext->isDocument()) { JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject); Frame* frame = window->impl()->frame(); if (!frame) return; // FIXME: Is this check needed for non-Document contexts? ScriptController* script = frame->script(); if (!script->isEnabled() || script->isPaused()) return; } m_parsed = true; ExecState* exec = globalObject->globalExec(); MarkedArgumentBuffer args; args.append(jsNontrivialString(exec, m_eventParameterName)); args.append(jsString(exec, m_code)); m_jsFunction = constructFunction(exec, args, Identifier(exec, m_functionName), m_sourceURL, m_lineNumber); // FIXME: is globalExec ok? JSFunction* listenerAsFunction = static_cast<JSFunction*>(m_jsFunction); if (exec->hadException()) { exec->clearException(); // failed to parse, so let's just make this listener a no-op m_jsFunction = 0; } else if (m_originalNode) { // Add the event's home element to the scope // (and the document, and the form - see JSHTMLElement::eventHandlerScope) ScopeChain scope = listenerAsFunction->scope(); JSValue thisObj = toJS(exec, globalObject, m_originalNode); if (thisObj.isObject()) { static_cast<JSNode*>(asObject(thisObj))->pushEventHandlerScope(exec, scope); listenerAsFunction->setScope(scope); } } // Since we only parse once, there's no need to keep data used for parsing around anymore. m_functionName = String(); m_code = String(); m_eventParameterName = String(); m_sourceURL = String(); }
JSObject* JSLazyEventListener::initializeJSFunction(ScriptExecutionContext* executionContext) const { ASSERT(is<Document>(executionContext)); if (!executionContext) return nullptr; ASSERT(!m_code.isNull()); ASSERT(!m_eventParameterName.isNull()); if (m_code.isNull() || m_eventParameterName.isNull()) return nullptr; Document& document = downcast<Document>(*executionContext); if (!document.frame()) return nullptr; if (!document.contentSecurityPolicy()->allowInlineEventHandlers(m_sourceURL, m_sourcePosition.m_line)) return nullptr; ScriptController& script = document.frame()->script(); if (!script.canExecuteScripts(AboutToExecuteScript) || script.isPaused()) return nullptr; JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(executionContext, isolatedWorld()); if (!globalObject) return nullptr; VM& vm = globalObject->vm(); JSLockHolder lock(vm); auto scope = DECLARE_CATCH_SCOPE(vm); ExecState* exec = globalObject->globalExec(); MarkedArgumentBuffer args; args.append(jsNontrivialString(exec, m_eventParameterName)); args.append(jsStringWithCache(exec, m_code)); // We want all errors to refer back to the line on which our attribute was // declared, regardless of any newlines in our JavaScript source text. int overrideLineNumber = m_sourcePosition.m_line.oneBasedInt(); JSObject* jsFunction = constructFunctionSkippingEvalEnabledCheck( exec, exec->lexicalGlobalObject(), args, Identifier::fromString(exec, m_functionName), m_sourceURL, m_sourcePosition, overrideLineNumber); if (UNLIKELY(scope.exception())) { reportCurrentException(exec); scope.clearException(); return nullptr; } JSFunction* listenerAsFunction = jsCast<JSFunction*>(jsFunction); if (m_originalNode) { if (!wrapper()) { // Ensure that 'node' has a JavaScript wrapper to mark the event listener we're creating. // FIXME: Should pass the global object associated with the node setWrapper(vm, asObject(toJS(exec, globalObject, *m_originalNode))); } // Add the event's home element to the scope // (and the document, and the form - see JSHTMLElement::eventHandlerScope) listenerAsFunction->setScope(vm, jsCast<JSNode*>(wrapper())->pushEventHandlerScope(exec, listenerAsFunction->scope())); } return jsFunction; }
void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event) { ASSERT(scriptExecutionContext); if (!scriptExecutionContext || scriptExecutionContext->isJSExecutionForbidden()) return; JSLock lock(SilenceAssertionsOnly); JSObject* jsFunction = this->jsFunction(scriptExecutionContext); if (!jsFunction) return; JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, m_isolatedWorld.get()); if (!globalObject) return; if (scriptExecutionContext->isDocument()) { JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject); Frame* frame = window->impl()->frame(); if (!frame) return; // The window must still be active in its frame. See <https://bugs.webkit.org/show_bug.cgi?id=21921>. // FIXME: A better fix for this may be to change DOMWindow::frame() to not return a frame the detached window used to be in. if (frame->domWindow() != window->impl()) return; // FIXME: Is this check needed for other contexts? ScriptController* script = frame->script(); if (!script->canExecuteScripts(AboutToExecuteScript) || script->isPaused()) return; } ExecState* exec = globalObject->globalExec(); JSValue handleEventFunction = jsFunction; CallData callData; CallType callType = getCallData(handleEventFunction, callData); // If jsFunction is not actually a function, see if it implements the EventListener interface and use that if (callType == CallTypeNone) { handleEventFunction = jsFunction->get(exec, Identifier(exec, "handleEvent")); callType = getCallData(handleEventFunction, callData); } if (callType != CallTypeNone) { RefPtr<JSEventListener> protect(this); MarkedArgumentBuffer args; args.append(toJS(exec, globalObject, event)); Event* savedEvent = globalObject->currentEvent(); globalObject->setCurrentEvent(event); JSGlobalData& globalData = globalObject->globalData(); DynamicGlobalObjectScope globalObjectScope(globalData, globalData.dynamicGlobalObject ? globalData.dynamicGlobalObject : globalObject); globalData.timeoutChecker.start(); JSValue thisValue = handleEventFunction == jsFunction ? toJS(exec, globalObject, event->currentTarget()) : jsFunction; JSValue retval = scriptExecutionContext->isDocument() ? JSMainThreadExecState::call(exec, handleEventFunction, callType, callData, thisValue, args) : JSC::call(exec, handleEventFunction, callType, callData, thisValue, args); globalData.timeoutChecker.stop(); globalObject->setCurrentEvent(savedEvent); #if ENABLE(WORKERS) if (scriptExecutionContext->isWorkerContext()) { bool terminatorCausedException = (exec->hadException() && isTerminatedExecutionException(exec->exception())); if (terminatorCausedException || globalData.terminator.shouldTerminate()) static_cast<WorkerContext*>(scriptExecutionContext)->script()->forbidExecution(); } #endif if (exec->hadException()) { event->target()->uncaughtExceptionInEventHandler(); reportCurrentException(exec); } else { if (!retval.isUndefinedOrNull() && event->storesResultAsString()) event->storeResult(ustringToString(retval.toString(exec)->value(exec))); if (m_isAttribute) { if (retval.isFalse()) event->preventDefault(); } } } }
void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event) { ASSERT(scriptExecutionContext); if (!scriptExecutionContext || scriptExecutionContext->isJSExecutionForbidden()) return; VM& vm = scriptExecutionContext->vm(); JSLockHolder lock(vm); auto scope = DECLARE_CATCH_SCOPE(vm); // See https://dom.spec.whatwg.org/#dispatching-events spec on calling handleEvent. // "If this throws an exception, report the exception." It should not propagate the // exception. JSObject* jsFunction = this->jsFunction(scriptExecutionContext); if (!jsFunction) return; JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, *m_isolatedWorld); if (!globalObject) return; if (scriptExecutionContext->isDocument()) { JSDOMWindow* window = jsCast<JSDOMWindow*>(globalObject); if (!window->wrapped().isCurrentlyDisplayedInFrame()) return; if (wasCreatedFromMarkup() && !scriptExecutionContext->contentSecurityPolicy()->allowInlineEventHandlers(sourceURL(), sourcePosition().m_line)) return; // FIXME: Is this check needed for other contexts? ScriptController& script = window->wrapped().frame()->script(); if (!script.canExecuteScripts(AboutToExecuteScript) || script.isPaused()) return; } ExecState* exec = globalObject->globalExec(); JSValue handleEventFunction = jsFunction; CallData callData; CallType callType = getCallData(handleEventFunction, callData); // If jsFunction is not actually a function, see if it implements the EventListener interface and use that if (callType == CallType::None) { handleEventFunction = jsFunction->get(exec, Identifier::fromString(exec, "handleEvent")); if (UNLIKELY(scope.exception())) { auto* exception = scope.exception(); scope.clearException(); event->target()->uncaughtExceptionInEventHandler(); reportException(exec, exception); return; } callType = getCallData(handleEventFunction, callData); } if (callType != CallType::None) { Ref<JSEventListener> protectedThis(*this); MarkedArgumentBuffer args; args.append(toJS(exec, globalObject, event)); Event* savedEvent = globalObject->currentEvent(); globalObject->setCurrentEvent(event); VMEntryScope entryScope(vm, vm.entryScope ? vm.entryScope->globalObject() : globalObject); InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(scriptExecutionContext, callType, callData); JSValue thisValue = handleEventFunction == jsFunction ? toJS(exec, globalObject, event->currentTarget()) : jsFunction; NakedPtr<JSC::Exception> exception; JSValue retval = scriptExecutionContext->isDocument() ? JSMainThreadExecState::profiledCall(exec, JSC::ProfilingReason::Other, handleEventFunction, callType, callData, thisValue, args, exception) : JSC::profiledCall(exec, JSC::ProfilingReason::Other, handleEventFunction, callType, callData, thisValue, args, exception); InspectorInstrumentation::didCallFunction(cookie, scriptExecutionContext); globalObject->setCurrentEvent(savedEvent); if (is<WorkerGlobalScope>(*scriptExecutionContext)) { auto scriptController = downcast<WorkerGlobalScope>(*scriptExecutionContext).script(); bool terminatorCausedException = (scope.exception() && isTerminatedExecutionException(scope.exception())); if (terminatorCausedException || scriptController->isTerminatingExecution()) scriptController->forbidExecution(); } if (exception) { event->target()->uncaughtExceptionInEventHandler(); reportException(exec, exception); } else { if (!retval.isUndefinedOrNull() && is<BeforeUnloadEvent>(*event)) downcast<BeforeUnloadEvent>(*event).setReturnValue(retval.toWTFString(exec)); if (m_isAttribute) { if (retval.isFalse()) event->preventDefault(); } } } }
JSObject* JSLazyEventListener::initializeJSFunction(ScriptExecutionContext* executionContext) const { ASSERT(executionContext); ASSERT(executionContext->isDocument()); if (!executionContext) return 0; Frame* frame = static_cast<Document*>(executionContext)->frame(); if (!frame) return 0; ScriptController* scriptController = frame->script(); if (!scriptController->canExecuteScripts(AboutToExecuteScript)) return 0; JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(executionContext, isolatedWorld()); if (!globalObject) return 0; if (executionContext->isDocument()) { JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject); Frame* frame = window->impl()->frame(); if (!frame) return 0; // FIXME: Is this check needed for non-Document contexts? ScriptController* script = frame->script(); if (!script->canExecuteScripts(AboutToExecuteScript) || script->isPaused()) return 0; } ExecState* exec = globalObject->globalExec(); MarkedArgumentBuffer args; args.append(jsNontrivialString(exec, stringToUString(m_eventParameterName))); args.append(jsString(exec, m_code)); JSObject* jsFunction = constructFunction(exec, args, Identifier(exec, stringToUString(m_functionName)), stringToUString(m_sourceURL), m_lineNumber); // FIXME: is globalExec ok? if (exec->hadException()) { exec->clearException(); return 0; } JSFunction* listenerAsFunction = static_cast<JSFunction*>(jsFunction); if (m_originalNode) { if (!wrapper()) { // Ensure that 'node' has a JavaScript wrapper to mark the event listener we're creating. JSLock lock(SilenceAssertionsOnly); // FIXME: Should pass the global object associated with the node setWrapper(asObject(toJS(globalObject->globalExec(), globalObject, m_originalNode))); } // Add the event's home element to the scope // (and the document, and the form - see JSHTMLElement::eventHandlerScope) ScopeChain scope = listenerAsFunction->scope(); static_cast<JSNode*>(wrapper())->pushEventHandlerScope(exec, scope); listenerAsFunction->setScope(scope); } // Since we only parse once, there's no need to keep data used for parsing around anymore. m_functionName = String(); m_code = String(); m_eventParameterName = String(); m_sourceURL = String(); return jsFunction; }
JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { JSString* sourceVal = thisValue.toThisJSString(exec); const UString& source = sourceVal->value(); JSValue pattern = args.at(0); JSValue replacement = args.at(1); UString replacementString; CallData callData; CallType callType = replacement.getCallData(callData); if (callType == CallTypeNone) replacementString = replacement.toString(exec); if (pattern.isObject(&RegExpObject::info)) { RegExp* reg = asRegExpObject(pattern)->regExp(); bool global = reg->global(); RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); int lastIndex = 0; int startPosition = 0; Vector<UString::Range, 16> sourceRanges; Vector<UString, 16> replacements; // This is either a loop (if global is set) or a one-way (if not). if (global && callType == CallTypeJS) { // reg->numSubpatterns() + 1 for pattern args, + 2 for match start and sourceValue int argCount = reg->numSubpatterns() + 1 + 2; JSFunction* func = asFunction(replacement); CachedCall cachedCall(exec, func, argCount, exec->exceptionSlot()); if (exec->hadException()) return jsNull(); while (true) { int matchIndex; int matchLen; int* ovector; regExpConstructor->performMatch(reg, source, startPosition, matchIndex, matchLen, &ovector); if (matchIndex < 0) break; sourceRanges.append(UString::Range(lastIndex, matchIndex - lastIndex)); int completeMatchStart = ovector[0]; unsigned i = 0; for (; i < reg->numSubpatterns() + 1; ++i) { int matchStart = ovector[i * 2]; int matchLen = ovector[i * 2 + 1] - matchStart; if (matchStart < 0) cachedCall.setArgument(i, jsUndefined()); else cachedCall.setArgument(i, jsSubstring(exec, source, matchStart, matchLen)); } cachedCall.setArgument(i++, jsNumber(exec, completeMatchStart)); cachedCall.setArgument(i++, sourceVal); cachedCall.setThis(exec->globalThisValue()); replacements.append(cachedCall.call().toString(cachedCall.newCallFrame())); if (exec->hadException()) break; lastIndex = matchIndex + matchLen; startPosition = lastIndex; // special case of empty match if (matchLen == 0) { startPosition++; if (startPosition > source.size()) break; } } } else { do { int matchIndex; int matchLen; int* ovector; regExpConstructor->performMatch(reg, source, startPosition, matchIndex, matchLen, &ovector); if (matchIndex < 0) break; sourceRanges.append(UString::Range(lastIndex, matchIndex - lastIndex)); if (callType != CallTypeNone) { int completeMatchStart = ovector[0]; MarkedArgumentBuffer args; for (unsigned i = 0; i < reg->numSubpatterns() + 1; ++i) { int matchStart = ovector[i * 2]; int matchLen = ovector[i * 2 + 1] - matchStart; if (matchStart < 0) args.append(jsUndefined()); else args.append(jsSubstring(exec, source, matchStart, matchLen)); } args.append(jsNumber(exec, completeMatchStart)); args.append(sourceVal); replacements.append(call(exec, replacement, callType, callData, exec->globalThisValue(), args).toString(exec)); if (exec->hadException()) break; } else replacements.append(substituteBackreferences(replacementString, source, ovector, reg)); lastIndex = matchIndex + matchLen; startPosition = lastIndex; // special case of empty match if (matchLen == 0) { startPosition++; if (startPosition > source.size()) break; } } while (global); } if (!lastIndex && replacements.isEmpty()) return sourceVal; if (lastIndex < source.size()) sourceRanges.append(UString::Range(lastIndex, source.size() - lastIndex)); return jsString(exec, source.spliceSubstringsWithSeparators(sourceRanges.data(), sourceRanges.size(), replacements.data(), replacements.size())); } // Not a regular expression, so treat the pattern as a string. UString patternString = pattern.toString(exec); int matchPos = source.find(patternString); if (matchPos == -1) return sourceVal; int matchLen = patternString.size(); if (callType != CallTypeNone) { MarkedArgumentBuffer args; args.append(jsSubstring(exec, source, matchPos, matchLen)); args.append(jsNumber(exec, matchPos)); args.append(sourceVal); replacementString = call(exec, replacement, callType, callData, exec->globalThisValue(), args).toString(exec); } int ovector[2] = { matchPos, matchPos + matchLen }; return jsString(exec, source.replaceRange(matchPos, matchLen, substituteBackreferences(replacementString, source, ovector, 0))); }
void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event) { ASSERT(scriptExecutionContext); if (!scriptExecutionContext || scriptExecutionContext->isJSExecutionForbidden()) return; JSLockHolder lock(scriptExecutionContext->vm()); JSObject* jsFunction = this->jsFunction(scriptExecutionContext); if (!jsFunction) return; JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, *m_isolatedWorld); if (!globalObject) return; if (scriptExecutionContext->isDocument()) { JSDOMWindow* window = jsCast<JSDOMWindow*>(globalObject); if (!window->impl().isCurrentlyDisplayedInFrame()) return; // FIXME: Is this check needed for other contexts? ScriptController& script = window->impl().frame()->script(); if (!script.canExecuteScripts(AboutToExecuteScript) || script.isPaused()) return; } ExecState* exec = globalObject->globalExec(); JSValue handleEventFunction = jsFunction; CallData callData; CallType callType = getCallData(handleEventFunction, callData); // If jsFunction is not actually a function, see if it implements the EventListener interface and use that if (callType == CallTypeNone) { handleEventFunction = jsFunction->get(exec, Identifier::fromString(exec, "handleEvent")); callType = getCallData(handleEventFunction, callData); } if (callType != CallTypeNone) { Ref<JSEventListener> protect(*this); MarkedArgumentBuffer args; args.append(toJS(exec, globalObject, event)); Event* savedEvent = globalObject->currentEvent(); globalObject->setCurrentEvent(event); VM& vm = globalObject->vm(); VMEntryScope entryScope(vm, vm.entryScope ? vm.entryScope->globalObject() : globalObject); InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(scriptExecutionContext, callType, callData); JSValue thisValue = handleEventFunction == jsFunction ? toJS(exec, globalObject, event->currentTarget()) : jsFunction; NakedPtr<Exception> exception; JSValue retval = scriptExecutionContext->isDocument() ? JSMainThreadExecState::call(exec, handleEventFunction, callType, callData, thisValue, args, exception) : JSC::call(exec, handleEventFunction, callType, callData, thisValue, args, exception); InspectorInstrumentation::didCallFunction(cookie, scriptExecutionContext); globalObject->setCurrentEvent(savedEvent); if (is<WorkerGlobalScope>(*scriptExecutionContext)) { bool terminatorCausedException = (exec->hadException() && isTerminatedExecutionException(exec->exception())); if (terminatorCausedException || (vm.watchdog && vm.watchdog->didFire())) downcast<WorkerGlobalScope>(*scriptExecutionContext).script()->forbidExecution(); } if (exception) { event->target()->uncaughtExceptionInEventHandler(); reportException(exec, exception); } else { if (!retval.isUndefinedOrNull() && is<BeforeUnloadEvent>(*event)) downcast<BeforeUnloadEvent>(*event).setReturnValue(retval.toString(exec)->value(exec)); if (m_isAttribute) { if (retval.isFalse()) event->preventDefault(); } } } }
static JSValue performPromiseAll(ExecState* exec, JSValue iterator, JSValue C, JSPromiseDeferred* deferred) { JSObject* thisObject = asObject(C); VM& vm = exec->vm(); // 6. Let 'values' be the result of calling ArrayCreate(0). JSArray* values = constructEmptyArray(exec, nullptr, thisObject->globalObject()); // 7. Let 'countdownHolder' be Record { [[Countdown]]: 0 }. NumberObject* countdownHolder = constructNumber(exec, thisObject->globalObject(), JSValue(0)); // 8. Let 'index' be 0. unsigned index = 0; // 9. Repeat. do { // i. Let 'next' be the result of calling IteratorStep(iterator). JSValue next = iteratorStep(exec, iterator); if (exec->hadException()) return jsUndefined(); // iii. If 'next' is false, if (next.isFalse()) { // a. If 'index' is 0, if (!index) { // a. Let 'resolveResult' be the result of calling the [[Call]] internal method // of deferred.[[Resolve]] with undefined as thisArgument and a List containing // values as argumentsList. performDeferredResolve(exec, deferred, values); // b. ReturnIfAbrupt(resolveResult). if (exec->hadException()) return jsUndefined(); } // b. Return deferred.[[Promise]]. return deferred->promise(); } // iv. Let 'nextValue' be the result of calling IteratorValue(next). // v. RejectIfAbrupt(nextValue, deferred). JSValue nextValue = iteratorValue(exec, next); if (exec->hadException()) return jsUndefined(); values->push(exec, jsUndefined()); // vi. Let 'nextPromise' be the result of calling Invoke(C, "resolve", (nextValue)). JSValue resolveFunction = C.get(exec, vm.propertyNames->resolve); if (exec->hadException()) return jsUndefined(); CallData resolveFunctionCallData; CallType resolveFunctionCallType = getCallData(resolveFunction, resolveFunctionCallData); if (resolveFunctionCallType == CallTypeNone) { throwTypeError(exec); return jsUndefined(); } MarkedArgumentBuffer resolveFunctionArguments; resolveFunctionArguments.append(nextValue); JSValue nextPromise = call(exec, resolveFunction, resolveFunctionCallType, resolveFunctionCallData, C, resolveFunctionArguments); // vii. RejectIfAbrupt(nextPromise, deferred). if (exec->hadException()) return jsUndefined(); // viii. Let 'countdownFunction' be a new built-in function object as defined in Promise.all Countdown Functions. JSFunction* countdownFunction = createPromiseAllCountdownFunction(vm, thisObject->globalObject()); // ix. Set the [[Index]] internal slot of 'countdownFunction' to 'index'. countdownFunction->putDirect(vm, vm.propertyNames->indexPrivateName, JSValue(index)); // x. Set the [[Values]] internal slot of 'countdownFunction' to 'values'. countdownFunction->putDirect(vm, vm.propertyNames->valuesPrivateName, values); // xi. Set the [[Deferred]] internal slot of 'countdownFunction' to 'deferred'. countdownFunction->putDirect(vm, vm.propertyNames->deferredPrivateName, deferred); // xii. Set the [[CountdownHolder]] internal slot of 'countdownFunction' to 'countdownHolder'. countdownFunction->putDirect(vm, vm.propertyNames->countdownHolderPrivateName, countdownHolder); // xiii. Let 'result' be the result of calling Invoke(nextPromise, "then", (countdownFunction, deferred.[[Reject]])). JSValue thenFunction = nextPromise.get(exec, vm.propertyNames->then); if (exec->hadException()) return jsUndefined(); CallData thenFunctionCallData; CallType thenFunctionCallType = getCallData(thenFunction, thenFunctionCallData); if (thenFunctionCallType == CallTypeNone) { throwTypeError(exec); return jsUndefined(); } MarkedArgumentBuffer thenFunctionArguments; thenFunctionArguments.append(countdownFunction); thenFunctionArguments.append(deferred->reject()); call(exec, thenFunction, thenFunctionCallType, thenFunctionCallData, nextPromise, thenFunctionArguments); // xiv. RejectIfAbrupt(result, deferred). if (exec->hadException()) return jsUndefined(); // xv. Set index to index + 1. index++; // xvi. Set countdownHolder.[[Countdown]] to countdownHolder.[[Countdown]] + 1. uint32_t newCountdownValue = countdownHolder->internalValue().asUInt32() + 1; countdownHolder->setInternalValue(vm, JSValue(newCountdownValue)); } while (true); ASSERT_NOT_REACHED(); return jsUndefined(); }
static void performPromiseRaceLoop(ExecState* exec, JSValue iterator, JSPromiseDeferred* deferred, JSValue C) { // 6. Repeat do { // i. Let 'next' be the result of calling IteratorStep(iterator). JSValue next = iteratorStep(exec, iterator); // ii. RejectIfAbrupt(next, deferred). if (exec->hadException()) return; // iii. If 'next' is false, return deferred.[[Promise]]. if (next.isFalse()) return; // iv. Let 'nextValue' be the result of calling IteratorValue(next). // v. RejectIfAbrupt(nextValue, deferred). JSValue nextValue = iteratorValue(exec, next); if (exec->hadException()) return; // vi. Let 'nextPromise' be the result of calling Invoke(C, "resolve", (nextValue)). JSValue resolveFunction = C.get(exec, exec->vm().propertyNames->resolve); if (exec->hadException()) return; CallData resolveFunctionCallData; CallType resolveFunctionCallType = getCallData(resolveFunction, resolveFunctionCallData); if (resolveFunctionCallType == CallTypeNone) { throwTypeError(exec); return; } MarkedArgumentBuffer resolveFunctionArguments; resolveFunctionArguments.append(nextValue); JSValue nextPromise = call(exec, resolveFunction, resolveFunctionCallType, resolveFunctionCallData, C, resolveFunctionArguments); // vii. RejectIfAbrupt(nextPromise, deferred). if (exec->hadException()) return; // viii. Let 'result' be the result of calling Invoke(nextPromise, "then", (deferred.[[Resolve]], deferred.[[Reject]])). JSValue thenFunction = nextPromise.get(exec, exec->vm().propertyNames->then); if (exec->hadException()) return; CallData thenFunctionCallData; CallType thenFunctionCallType = getCallData(thenFunction, thenFunctionCallData); if (thenFunctionCallType == CallTypeNone) { throwTypeError(exec); return; } MarkedArgumentBuffer thenFunctionArguments; thenFunctionArguments.append(deferred->resolve()); thenFunctionArguments.append(deferred->reject()); call(exec, thenFunction, thenFunctionCallType, thenFunctionCallData, nextPromise, thenFunctionArguments); // ix. RejectIfAbrupt(result, deferred). if (exec->hadException()) return; } while (true); }
void JSEventListener::handleEvent(Event* event, bool isWindowEvent) { JSLock lock(SilenceAssertionsOnly); JSObject* jsFunction = this->jsFunction(); if (!jsFunction) return; JSDOMGlobalObject* globalObject = m_globalObject; // Null check as clearGlobalObject() can clear this and we still get called back by // xmlhttprequest objects. See http://bugs.webkit.org/show_bug.cgi?id=13275 // FIXME: Is this check still necessary? Requests are supposed to be stopped before clearGlobalObject() is called. ASSERT(globalObject); if (!globalObject) return; ScriptExecutionContext* scriptExecutionContext = globalObject->scriptExecutionContext(); if (!scriptExecutionContext) return; if (scriptExecutionContext->isDocument()) { JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject); Frame* frame = window->impl()->frame(); if (!frame) return; // The window must still be active in its frame. See <https://bugs.webkit.org/show_bug.cgi?id=21921>. // FIXME: A better fix for this may be to change DOMWindow::frame() to not return a frame the detached window used to be in. if (frame->domWindow() != window->impl()) return; // FIXME: Is this check needed for other contexts? ScriptController* script = frame->script(); if (!script->isEnabled() || script->isPaused()) return; } ExecState* exec = globalObject->globalExec(); JSValue handleEventFunction = jsFunction->get(exec, Identifier(exec, "handleEvent")); CallData callData; CallType callType = handleEventFunction.getCallData(callData); if (callType == CallTypeNone) { handleEventFunction = JSValue(); callType = jsFunction->getCallData(callData); } if (callType != CallTypeNone) { ref(); MarkedArgumentBuffer args; args.append(toJS(exec, globalObject, event)); Event* savedEvent = globalObject->currentEvent(); globalObject->setCurrentEvent(event); // If this event handler is the first JavaScript to execute, then the // dynamic global object should be set to the global object of the // window in which the event occurred. JSGlobalData* globalData = globalObject->globalData(); DynamicGlobalObjectScope globalObjectScope(exec, globalData->dynamicGlobalObject ? globalData->dynamicGlobalObject : globalObject); JSValue retval; if (handleEventFunction) { globalObject->globalData()->timeoutChecker.start(); retval = call(exec, handleEventFunction, callType, callData, jsFunction, args); } else { JSValue thisValue; if (isWindowEvent) thisValue = globalObject->toThisObject(exec); else thisValue = toJS(exec, globalObject, event->currentTarget()); globalObject->globalData()->timeoutChecker.start(); retval = call(exec, jsFunction, callType, callData, thisValue, args); } globalObject->globalData()->timeoutChecker.stop(); globalObject->setCurrentEvent(savedEvent); if (exec->hadException()) reportCurrentException(exec); else { if (!retval.isUndefinedOrNull() && event->storesResultAsString()) event->storeResult(retval.toString(exec)); if (m_isAttribute) { bool retvalbool; if (retval.getBoolean(retvalbool) && !retvalbool) event->preventDefault(); } } if (scriptExecutionContext->isDocument()) Document::updateStyleForAllDocuments(); deref(); } }
static EncodedJSValue JSC_HOST_CALL promiseResolutionHandlerFunction(ExecState* exec) { JSValue x = exec->argument(0); VM& vm = exec->vm(); JSObject* F = exec->callee(); // 1. Let 'promise' be the value of F's [[Promise]] internal slot JSPromise* promise = jsCast<JSPromise*>(F->get(exec, vm.propertyNames->promisePrivateName)); // 2. Let 'fulfillmentHandler' be the value of F's [[FulfillmentHandler]] internal slot. JSValue fulfillmentHandler = F->get(exec, vm.propertyNames->fulfillmentHandlerPrivateName); // 3. Let 'rejectionHandler' be the value of F's [[RejectionHandler]] internal slot. JSValue rejectionHandler = F->get(exec, vm.propertyNames->rejectionHandlerPrivateName); // 4. If SameValue(x, promise) is true, if (sameValue(exec, x, promise)) { // i. Let 'selfResolutionError' be a newly-created TypeError object. JSObject* selfResolutionError = createTypeError(exec, ASCIILiteral("Resolve a promise with itself")); // ii. Return the result of calling the [[Call]] internal method of rejectionHandler with // undefined as thisArgument and a List containing selfResolutionError as argumentsList. CallData rejectCallData; CallType rejectCallType = getCallData(rejectionHandler, rejectCallData); ASSERT(rejectCallType != CallTypeNone); MarkedArgumentBuffer rejectArguments; rejectArguments.append(selfResolutionError); return JSValue::encode(call(exec, rejectionHandler, rejectCallType, rejectCallData, jsUndefined(), rejectArguments)); } // 5. Let 'C' be the value of promise's [[PromiseConstructor]] internal slot. JSValue C = promise->constructor(); // 6. Let 'deferred' be the result of calling GetDeferred(C) JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C); // 7. ReturnIfAbrupt(deferred). if (exec->hadException()) return JSValue::encode(jsUndefined()); JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); // 8. Let 'updateResult' be the result of calling UpdateDeferredFromPotentialThenable(x, deferred). ThenableStatus updateResult = updateDeferredFromPotentialThenable(exec, x, deferred); // 9. ReturnIfAbrupt(updateResult). if (exec->hadException()) return JSValue::encode(jsUndefined()); // 10. If 'updateResult' is not "not a thenable", return the result of calling // Invoke(deferred.[[Promise]], "then", (fulfillmentHandler, rejectionHandler)). // NOTE: Invoke does not seem to be defined anywhere, so I am guessing here. if (updateResult != NotAThenable) { JSObject* deferredPromise = deferred->promise(); JSValue thenValue = deferredPromise->get(exec, exec->vm().propertyNames->then); if (exec->hadException()) return JSValue::encode(jsUndefined()); CallData thenCallData; CallType thenCallType = getCallData(thenValue, thenCallData); if (thenCallType == CallTypeNone) return JSValue::encode(throwTypeError(exec)); MarkedArgumentBuffer arguments; arguments.append(fulfillmentHandler); arguments.append(rejectionHandler); return JSValue::encode(call(exec, thenValue, thenCallType, thenCallData, deferredPromise, arguments)); } // 11. Return the result of calling the [[Call]] internal method of fulfillmentHandler // with undefined as thisArgument and a List containing x as argumentsList. CallData fulfillmentHandlerCallData; CallType fulfillmentHandlerCallType = getCallData(fulfillmentHandler, fulfillmentHandlerCallData); ASSERT(fulfillmentHandlerCallType != CallTypeNone); MarkedArgumentBuffer fulfillmentHandlerArguments; fulfillmentHandlerArguments.append(x); return JSValue::encode(call(exec, fulfillmentHandler, fulfillmentHandlerCallType, fulfillmentHandlerCallData, jsUndefined(), fulfillmentHandlerArguments)); }
static EncodedJSValue JSC_HOST_CALL constructMap(ExecState* exec) { JSValue prototype = JSValue(); JSValue newTarget = exec->newTarget(); if (newTarget != exec->callee()) prototype = newTarget.get(exec, exec->propertyNames().prototype); JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject(); Structure* mapStructure = Structure::createSubclassStructure(exec->vm(), globalObject->mapStructure(), prototype); JSMap* map = JSMap::create(exec, mapStructure); JSValue iterable = exec->argument(0); if (iterable.isUndefinedOrNull()) return JSValue::encode(map); JSValue adderFunction = map->JSObject::get(exec, exec->propertyNames().set); if (exec->hadException()) return JSValue::encode(jsUndefined()); CallData adderFunctionCallData; CallType adderFunctionCallType = getCallData(adderFunction, adderFunctionCallData); if (adderFunctionCallType == CallTypeNone) return JSValue::encode(throwTypeError(exec)); JSValue iteratorFunction = iterable.get(exec, exec->propertyNames().iteratorSymbol); if (exec->hadException()) return JSValue::encode(jsUndefined()); CallData iteratorFunctionCallData; CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData); if (iteratorFunctionCallType == CallTypeNone) return JSValue::encode(throwTypeError(exec)); ArgList iteratorFunctionArguments; JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments); if (exec->hadException()) return JSValue::encode(jsUndefined()); if (!iterator.isObject()) return JSValue::encode(throwTypeError(exec)); while (true) { JSValue next = iteratorStep(exec, iterator); if (exec->hadException()) return JSValue::encode(jsUndefined()); if (next.isFalse()) return JSValue::encode(map); JSValue nextItem = iteratorValue(exec, next); if (exec->hadException()) return JSValue::encode(jsUndefined()); if (!nextItem.isObject()) { throwTypeError(exec); iteratorClose(exec, iterator); return JSValue::encode(jsUndefined()); } JSValue key = nextItem.get(exec, 0); if (exec->hadException()) { iteratorClose(exec, iterator); return JSValue::encode(jsUndefined()); } JSValue value = nextItem.get(exec, 1); if (exec->hadException()) { iteratorClose(exec, iterator); return JSValue::encode(jsUndefined()); } MarkedArgumentBuffer arguments; arguments.append(key); arguments.append(value); call(exec, adderFunction, adderFunctionCallType, adderFunctionCallData, map, arguments); if (exec->hadException()) { iteratorClose(exec, iterator); return JSValue::encode(jsUndefined()); } } RELEASE_ASSERT_NOT_REACHED(); return JSValue::encode(map); }
void JSErrorHandler::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event) { if (!is<ErrorEvent>(*event)) return JSEventListener::handleEvent(scriptExecutionContext, event); ASSERT(scriptExecutionContext); if (!scriptExecutionContext) return; ErrorEvent& errorEvent = downcast<ErrorEvent>(*event); JSLockHolder lock(scriptExecutionContext->vm()); JSObject* jsFunction = this->jsFunction(scriptExecutionContext); if (!jsFunction) return; JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, isolatedWorld()); if (!globalObject) return; ExecState* exec = globalObject->globalExec(); CallData callData; CallType callType = jsFunction->methodTable()->getCallData(jsFunction, callData); if (callType != CallTypeNone) { Ref<JSErrorHandler> protectedctor(*this); Event* savedEvent = globalObject->currentEvent(); globalObject->setCurrentEvent(event); MarkedArgumentBuffer args; args.append(jsStringWithCache(exec, errorEvent.message())); args.append(jsStringWithCache(exec, errorEvent.filename())); args.append(jsNumber(errorEvent.lineno())); args.append(jsNumber(errorEvent.colno())); VM& vm = globalObject->vm(); VMEntryScope entryScope(vm, vm.entryScope ? vm.entryScope->globalObject() : globalObject); InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(scriptExecutionContext, callType, callData); NakedPtr<Exception> exception; JSValue returnValue = scriptExecutionContext->isDocument() ? JSMainThreadExecState::profiledCall(exec, JSC::ProfilingReason::Other, jsFunction, callType, callData, globalObject, args, exception) : JSC::profiledCall(exec, JSC::ProfilingReason::Other, jsFunction, callType, callData, globalObject, args, exception); InspectorInstrumentation::didCallFunction(cookie, scriptExecutionContext); globalObject->setCurrentEvent(savedEvent); if (exception) reportException(exec, exception); else { if (returnValue.isTrue()) event->preventDefault(); } } }
static void getListFromVariantArgs(ExecState* exec, const NPVariant* args, unsigned argCount, RootObject* rootObject, MarkedArgumentBuffer& aList) { for (unsigned i = 0; i < argCount; ++i) aList.append(convertNPVariantToValue(exec, &args[i], rootObject)); }
AJValue LiteralParser::parse(ParserState initialState) { ParserState state = initialState; MarkedArgumentBuffer objectStack; AJValue lastValue; Vector<ParserState, 16> stateStack; Vector<Identifier, 16> identifierStack; while (1) { switch(state) { startParseArray: case StartParseArray: { AJArray* array = constructEmptyArray(m_exec); objectStack.append(array); // fallthrough } doParseArrayStartExpression: case DoParseArrayStartExpression: { TokenType lastToken = m_lexer.currentToken().type; if (m_lexer.next() == TokRBracket) { if (lastToken == TokComma) return AJValue(); m_lexer.next(); lastValue = objectStack.last(); objectStack.removeLast(); break; } stateStack.append(DoParseArrayEndExpression); goto startParseExpression; } case DoParseArrayEndExpression: { asArray(objectStack.last())->push(m_exec, lastValue); if (m_lexer.currentToken().type == TokComma) goto doParseArrayStartExpression; if (m_lexer.currentToken().type != TokRBracket) return AJValue(); m_lexer.next(); lastValue = objectStack.last(); objectStack.removeLast(); break; } startParseObject: case StartParseObject: { AJObject* object = constructEmptyObject(m_exec); objectStack.append(object); TokenType type = m_lexer.next(); if (type == TokString) { Lexer::LiteralParserToken identifierToken = m_lexer.currentToken(); // Check for colon if (m_lexer.next() != TokColon) return AJValue(); m_lexer.next(); identifierStack.append(Identifier(m_exec, identifierToken.stringToken)); stateStack.append(DoParseObjectEndExpression); goto startParseExpression; } else if (type != TokRBrace) return AJValue(); m_lexer.next(); lastValue = objectStack.last(); objectStack.removeLast(); break; } doParseObjectStartExpression: case DoParseObjectStartExpression: { TokenType type = m_lexer.next(); if (type != TokString) return AJValue(); Lexer::LiteralParserToken identifierToken = m_lexer.currentToken(); // Check for colon if (m_lexer.next() != TokColon) return AJValue(); m_lexer.next(); identifierStack.append(Identifier(m_exec, identifierToken.stringToken)); stateStack.append(DoParseObjectEndExpression); goto startParseExpression; } case DoParseObjectEndExpression: { asObject(objectStack.last())->putDirect(identifierStack.last(), lastValue); identifierStack.removeLast(); if (m_lexer.currentToken().type == TokComma) goto doParseObjectStartExpression; if (m_lexer.currentToken().type != TokRBrace) return AJValue(); m_lexer.next(); lastValue = objectStack.last(); objectStack.removeLast(); break; } startParseExpression: case StartParseExpression: { switch (m_lexer.currentToken().type) { case TokLBracket: goto startParseArray; case TokLBrace: goto startParseObject; case TokString: { Lexer::LiteralParserToken stringToken = m_lexer.currentToken(); m_lexer.next(); lastValue = jsString(m_exec, stringToken.stringToken); break; } case TokNumber: { Lexer::LiteralParserToken numberToken = m_lexer.currentToken(); m_lexer.next(); lastValue = jsNumber(m_exec, numberToken.numberToken); break; } case TokNull: m_lexer.next(); lastValue = jsNull(); break; case TokTrue: m_lexer.next(); lastValue = jsBoolean(true); break; case TokFalse: m_lexer.next(); lastValue = jsBoolean(false); break; default: // Error return AJValue(); } break; } case StartParseStatement: { switch (m_lexer.currentToken().type) { case TokLBracket: case TokNumber: case TokString: goto startParseExpression; case TokLParen: { m_lexer.next(); stateStack.append(StartParseStatementEndStatement); goto startParseExpression; } default: return AJValue(); } } case StartParseStatementEndStatement: { ASSERT(stateStack.isEmpty()); if (m_lexer.currentToken().type != TokRParen) return AJValue(); if (m_lexer.next() == TokEnd) return lastValue; return AJValue(); } default: ASSERT_NOT_REACHED(); } if (stateStack.isEmpty()) return lastValue; state = stateStack.last(); stateStack.removeLast(); continue; } }
// FIXME: This should use the IDLUnion JSConverter. JSValue convertToJSValue(ExecState& state, JSDOMGlobalObject& globalObject, const WebGLAny& any) { return WTF::switchOn(any, [] (std::nullptr_t) { return jsNull(); }, [] (bool value) { return jsBoolean(value); }, [] (int value) { return jsNumber(value); }, [] (unsigned value) { return jsNumber(value); }, [] (long long value) { return jsNumber(value); }, [] (float value) { return jsNumber(value); }, [&] (const String& value) { return jsStringWithCache(&state, value); }, [&] (const Vector<bool>& values) { MarkedArgumentBuffer list; for (auto& value : values) list.append(jsBoolean(value)); RELEASE_ASSERT(!list.hasOverflowed()); return constructArray(&state, 0, &globalObject, list); }, [&] (const Vector<int>& values) { MarkedArgumentBuffer list; for (auto& value : values) list.append(jsNumber(value)); RELEASE_ASSERT(!list.hasOverflowed()); return constructArray(&state, 0, &globalObject, list); }, [&] (const RefPtr<Float32Array>& array) { return toJS(&state, &globalObject, array.get()); }, [&] (const RefPtr<Int32Array>& array) { return toJS(&state, &globalObject, array.get()); }, [&] (const RefPtr<Uint8Array>& array) { return toJS(&state, &globalObject, array.get()); }, [&] (const RefPtr<Uint32Array>& array) { return toJS(&state, &globalObject, array.get()); }, [&] (const RefPtr<WebGLBuffer>& buffer) { return toJS(&state, &globalObject, buffer.get()); }, [&] (const RefPtr<WebGLFramebuffer>& buffer) { return toJS(&state, &globalObject, buffer.get()); }, [&] (const RefPtr<WebGLProgram>& program) { return toJS(&state, &globalObject, program.get()); }, [&] (const RefPtr<WebGLRenderbuffer>& buffer) { return toJS(&state, &globalObject, buffer.get()); }, [&] (const RefPtr<WebGLTexture>& texture) { return toJS(&state, &globalObject, texture.get()); }, [&] (const RefPtr<WebGLVertexArrayObjectOES>& array) { return toJS(&state, &globalObject, array.get()); } #if ENABLE(WEBGL2) , [&] (const RefPtr<WebGLVertexArrayObject>& array) { return toJS(&state, &globalObject, array.get()); } #endif ); }