JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { ExecState* exec = toJS(ctx); exec->globalData().heap->registerThread(); JSLock lock(exec); JSObject* jsObject = toJS(object); JSObject* jsThisObject = toJS(thisObject); if (!jsThisObject) jsThisObject = exec->globalThisValue(); ArgList argList; for (size_t i = 0; i < argumentCount; i++) argList.append(toJS(arguments[i])); CallData callData; CallType callType = jsObject->getCallData(callData); if (callType == CallTypeNone) return 0; JSValueRef result = toRef(call(exec, jsObject, callType, callData, jsThisObject, argList)); if (exec->hadException()) { if (exception) *exception = toRef(exec->exception()); exec->clearException(); result = 0; } return 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; if (!setPrototypeWithCycleCheck(value)) throwError(exec, createError(exec, "cyclic __proto__ 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; }
void JSWorkerContextErrorHandler::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event) { ASSERT(scriptExecutionContext); if (!scriptExecutionContext) return; JSLock lock(SilenceAssertionsOnly); 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->getCallData(callData); if (callType != CallTypeNone) { ref(); Event* savedEvent = globalObject->currentEvent(); globalObject->setCurrentEvent(event); ASSERT(event->isErrorEvent()); ErrorEvent* errorEvent = static_cast<ErrorEvent*>(event); MarkedArgumentBuffer args; args.append(jsString(exec, errorEvent->message())); args.append(jsString(exec, errorEvent->filename())); args.append(jsNumber(exec, errorEvent->lineno())); JSGlobalData* globalData = globalObject->globalData(); DynamicGlobalObjectScope globalObjectScope(exec, globalData->dynamicGlobalObject ? globalData->dynamicGlobalObject : globalObject); JSValue thisValue = globalObject->toThisObject(exec); globalData->timeoutChecker.start(); JSValue returnValue = JSC::call(exec, jsFunction, callType, callData, thisValue, args); globalData->timeoutChecker.stop(); globalObject->setCurrentEvent(savedEvent); if (exec->hadException()) reportCurrentException(exec); else { bool retvalbool; if (returnValue.getBoolean(retvalbool) && !retvalbool) event->preventDefault(); } deref(); } }
bool JSEventListener::reportError(const String& message, const String& url, int lineNumber) { JSLock lock(SilenceAssertionsOnly); JSObject* jsFunction = this->jsFunction(); if (!jsFunction) return false; JSDOMGlobalObject* globalObject = m_globalObject; if (!globalObject) return false; ExecState* exec = globalObject->globalExec(); CallData callData; CallType callType = jsFunction->getCallData(callData); if (callType == CallTypeNone) return false; MarkedArgumentBuffer args; args.append(jsString(exec, message)); args.append(jsString(exec, url)); args.append(jsNumber(exec, lineNumber)); // 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 thisValue = globalObject->toThisObject(exec); globalObject->globalData()->timeoutChecker.start(); JSValue returnValue = call(exec, jsFunction, callType, callData, thisValue, args); globalObject->globalData()->timeoutChecker.stop(); // If an error occurs while handling the script error, it should be bubbled up. if (exec->hadException()) { exec->clearException(); return false; } bool bubbleEvent; return returnValue.getBoolean(bubbleEvent) && !bubbleEvent; }
bool JSEventListener::reportError(ScriptExecutionContext* context, const String& message, const String& url, int lineNumber) { JSLock lock(SilenceAssertionsOnly); JSObject* jsFunction = this->jsFunction(context); if (!jsFunction) return false; JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(context, m_isolatedWorld.get()); ExecState* exec = globalObject->globalExec(); CallData callData; CallType callType = jsFunction->getCallData(callData); if (callType == CallTypeNone) return false; MarkedArgumentBuffer args; args.append(jsString(exec, message)); args.append(jsString(exec, url)); args.append(jsNumber(exec, lineNumber)); JSGlobalData* globalData = globalObject->globalData(); DynamicGlobalObjectScope globalObjectScope(exec, globalData->dynamicGlobalObject ? globalData->dynamicGlobalObject : globalObject); JSValue thisValue = globalObject->toThisObject(exec); globalData->timeoutChecker.start(); JSValue returnValue = JSC::call(exec, jsFunction, callType, callData, thisValue, args); globalData->timeoutChecker.stop(); // If an error occurs while handling the script error, it should be bubbled up. if (exec->hadException()) { exec->clearException(); return false; } bool bubbleEvent; return returnValue.getBoolean(bubbleEvent) && !bubbleEvent; }
void JSAbstractEventListener::handleEvent(Event* event, bool isWindowEvent) { JSObject* listener = listenerObj(); if (!listener) return; JSDOMWindow* window = this->window(); // Null check as clearWindow() can clear this and we still get called back by // xmlhttprequest objects. See http://bugs.webkit.org/show_bug.cgi?id=13275 if (!window) return; Frame* frame = window->impl()->frame(); if (!frame) return; ScriptController* script = frame->script(); if (!script->isEnabled() || script->isPaused()) return; JSLock lock(false); ExecState* exec = window->globalExec(); JSValue* handleEventFunction = listener->get(exec, Identifier(exec, "handleEvent")); CallData callData; CallType callType = handleEventFunction->getCallData(callData); if (callType == CallTypeNone) { handleEventFunction = 0; callType = listener->getCallData(callData); } if (callType != CallTypeNone) { ref(); ArgList args; args.append(toJS(exec, event)); Event* savedEvent = window->currentEvent(); window->setCurrentEvent(event); JSValue* retval; if (handleEventFunction) { window->startTimeoutCheck(); retval = call(exec, handleEventFunction, callType, callData, listener, args); } else { JSValue* thisValue; if (isWindowEvent) thisValue = window->shell(); else thisValue = toJS(exec, event->currentTarget()); window->startTimeoutCheck(); retval = call(exec, listener, callType, callData, thisValue, args); } window->stopTimeoutCheck(); window->setCurrentEvent(savedEvent); if (exec->hadException()) frame->domWindow()->console()->reportCurrentException(exec); else { if (!retval->isUndefinedOrNull() && event->storesResultAsString()) event->storeResult(retval->toString(exec)); if (m_isHTML) { bool retvalbool; if (retval->getBoolean(retvalbool) && !retvalbool) event->preventDefault(); } } Document::updateDocumentsRendering(); deref(); } }
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())
// 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) { JSObject* proto = value->getObject(); // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla. if (!proto && !value->isNull()) return; while (proto) { if (proto == this) { throwError(exec, GeneralError, "cyclic __proto__ value"); return; } proto = proto->prototype() ? proto->prototype()->getObject() : 0; } setPrototype(value); return; } // Check if there are any setters or getters in the prototype chain JSValue* prototype; for (JSObject* obj = this; !obj->structureID()->hasGetterSetterProperties(); obj = asObject(prototype)) { prototype = obj->prototype(); if (prototype->isNull()) { putDirect(propertyName, value, 0, true, slot); return; } } unsigned attributes; if ((m_structureID->get(propertyName, attributes) != 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); ArgList 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; } putDirect(propertyName, value, 0, true, slot); return; }
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(); } }
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->get(exec, Identifier(exec, "handleEvent")); CallData callData; CallType callType = getCallData(handleEventFunction, callData); if (callType == CallTypeNone) { handleEventFunction = JSValue(); callType = jsFunction->getCallData(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 retval; if (handleEventFunction) { retval = scriptExecutionContext->isDocument() ? JSMainThreadExecState::call(exec, handleEventFunction, callType, callData, jsFunction, args) : JSC::call(exec, handleEventFunction, callType, callData, jsFunction, args); } else { JSValue currentTarget = toJS(exec, globalObject, event->currentTarget()); retval = scriptExecutionContext->isDocument() ? JSMainThreadExecState::call(exec, jsFunction, callType, callData, currentTarget, args) : JSC::call(exec, jsFunction, callType, callData, currentTarget, 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))); if (m_isAttribute) { bool retvalbool; if (retval.getBoolean(retvalbool) && !retvalbool) event->preventDefault(); } } } }