void StackVisitor::readInlinedFrame(CallFrame* callFrame, CodeOrigin* codeOrigin) { ASSERT(codeOrigin); int frameOffset = inlinedFrameOffset(codeOrigin); bool isInlined = !!frameOffset; if (isInlined) { InlineCallFrame* inlineCallFrame = codeOrigin->inlineCallFrame; m_frame.m_callFrame = callFrame; m_frame.m_inlineCallFrame = inlineCallFrame; m_frame.m_argumentCountIncludingThis = inlineCallFrame->arguments.size(); m_frame.m_codeBlock = inlineCallFrame->baselineCodeBlock(); m_frame.m_bytecodeOffset = codeOrigin->bytecodeIndex; JSFunction* callee = inlineCallFrame->calleeForCallFrame(callFrame); m_frame.m_scope = callee->scope(); m_frame.m_callee = callee; ASSERT(m_frame.scope()); ASSERT(m_frame.callee()); // The callerFrame just needs to be non-null to indicate that we // haven't reached the last frame yet. Setting it to the root // frame (i.e. the callFrame that this inlined frame is called from) // would work just fine. m_frame.m_callerFrame = callFrame; return; } readNonInlinedFrame(callFrame, codeOrigin); }
CallFrame* CallFrame::trueCallerFrameSlow() { // this -> The callee; this is either an inlined callee in which case it already has // a pointer to the true caller. Otherwise it contains current PC in the machine // caller. // // machineCaller -> The caller according to the machine, which may be zero or // more frames above the true caller due to inlining. // // trueCaller -> The real caller. // Am I an inline call frame? If so, we're done. if (isInlineCallFrame()) return callerFrame(); // I am a machine call frame, so the question is: is my caller a machine call frame // that has inlines or a machine call frame that doesn't? CallFrame* machineCaller = callerFrame()->removeHostCallFrameFlag(); if (!machineCaller) return 0; ASSERT(!machineCaller->isInlineCallFrame()); if (!machineCaller->codeBlock() || !machineCaller->codeBlock()->hasCodeOrigins()) return machineCaller; // No inlining, so machineCaller == trueCaller // Figure out where the caller frame would have gone relative to the machine // caller, and rematerialize it. Do so for the entire inline stack. CodeOrigin codeOrigin = machineCaller->codeBlock()->codeOriginForReturn(returnPC()); for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; inlineCallFrame;) { InlineCallFrame* nextInlineCallFrame = inlineCallFrame = inlineCallFrame->caller.inlineCallFrame; CallFrame* inlinedCaller = machineCaller + inlineCallFrame->stackOffset; JSObject* callee = machineCaller->registers()[inlineCallFrame->calleeVR].function(); JSCell* calleeAsFunctionCell = getJSFunction(callee); ASSERT(calleeAsFunctionCell); JSFunction* calleeAsFunction = asFunction(calleeAsFunctionCell); // Fill in the inlinedCaller inlinedCaller->setCodeBlock(machineCaller->codeBlock()); inlinedCaller->setScopeChain(calleeAsFunction->scope()); if (nextInlineCallFrame) inlinedCaller->setCallerFrame(machineCaller + nextInlineCallFrame->stackOffset); else inlinedCaller->setCallerFrame(machineCaller); inlinedCaller->setInlineCallFrame(inlineCallFrame); inlinedCaller->setArgumentCountIncludingThis(inlineCallFrame->numArgumentsIncludingThis); inlinedCaller->setCallee(callee); inlineCallFrame = nextInlineCallFrame; } return machineCaller + codeOrigin.inlineCallFrame->stackOffset; }
void Debugger::recompileAllJSFunctions(JSGlobalData* globalData) { // If JavaScript is running, it's not safe to recompile, since we'll end // up throwing away code that is live on the stack. ASSERT(!globalData->dynamicGlobalObject); if (globalData->dynamicGlobalObject) return; typedef HashSet<FunctionExecutable*> FunctionExecutableSet; typedef HashMap<SourceProvider*, ExecState*> SourceProviderMap; FunctionExecutableSet functionExecutables; SourceProviderMap sourceProviders; LiveObjectIterator it = globalData->heap.primaryHeapBegin(); LiveObjectIterator heapEnd = globalData->heap.primaryHeapEnd(); for ( ; it != heapEnd; ++it) { if (!(*it)->inherits(&JSFunction::info)) continue; JSFunction* function = asFunction(*it); if (function->executable()->isHostFunction()) continue; FunctionExecutable* executable = function->jsExecutable(); // Check if the function is already in the set - if so, // we've already retranslated it, nothing to do here. if (!functionExecutables.add(executable).second) continue; ExecState* exec = function->scope().globalObject()->JSGlobalObject::globalExec(); executable->recompile(exec); if (function->scope().globalObject()->debugger() == this) sourceProviders.add(executable->source().provider(), exec); } // Call sourceParsed() after reparsing all functions because it will execute // JavaScript in the inspector. SourceProviderMap::const_iterator end = sourceProviders.end(); for (SourceProviderMap::const_iterator iter = sourceProviders.begin(); iter != end; ++iter) sourceParsed(iter->second, SourceCode(iter->first), -1, UString()); }
void JavaScriptDebugServer::recompileAllJSFunctions(Timer<JavaScriptDebugServer>*) { JSLock lock(false); JSGlobalData* globalData = JSDOMWindow::commonJSGlobalData(); // If JavaScript is running, it's not safe to recompile, since we'll end // up throwing away code that is live on the stack. ASSERT(!globalData->dynamicGlobalObject); if (globalData->dynamicGlobalObject) return; Vector<ProtectedPtr<JSFunction> > functions; Heap::iterator heapEnd = globalData->heap.primaryHeapEnd(); for (Heap::iterator it = globalData->heap.primaryHeapBegin(); it != heapEnd; ++it) { if ((*it)->isObject(&JSFunction::info)) functions.append(static_cast<JSFunction*>(*it)); } typedef HashMap<RefPtr<FunctionBodyNode>, RefPtr<FunctionBodyNode> > FunctionBodyMap; typedef HashMap<SourceProvider*, ExecState*> SourceProviderMap; FunctionBodyMap functionBodies; SourceProviderMap sourceProviders; size_t size = functions.size(); for (size_t i = 0; i < size; ++i) { JSFunction* function = functions[i]; FunctionBodyNode* oldBody = function->body(); pair<FunctionBodyMap::iterator, bool> result = functionBodies.add(oldBody, 0); if (!result.second) { function->setBody(result.first->second.get()); continue; } ExecState* exec = function->scope().globalObject()->JSGlobalObject::globalExec(); const SourceCode& sourceCode = oldBody->source(); RefPtr<FunctionBodyNode> newBody = globalData->parser->parse<FunctionBodyNode>(exec, 0, sourceCode); ASSERT(newBody); newBody->finishParsing(oldBody->copyParameters(), oldBody->parameterCount()); result.first->second = newBody; function->setBody(newBody.release()); if (hasListeners()) sourceProviders.add(sourceCode.provider(), exec); } // Call sourceParsed() after reparsing all functions because it will execute // JavaScript in the inspector. SourceProviderMap::const_iterator end = sourceProviders.end(); for (SourceProviderMap::const_iterator iter = sourceProviders.begin(); iter != end; ++iter) sourceParsed((*iter).second, SourceCode((*iter).first), -1, 0); }
CallType JSFunction::getCallData(JSCell* cell, CallData& callData) { JSFunction* thisObject = jsCast<JSFunction*>(cell); if (thisObject->isHostFunction()) { callData.native.function = thisObject->nativeFunction(); return CallTypeHost; } callData.js.functionExecutable = thisObject->jsExecutable(); callData.js.scope = thisObject->scope(); return CallTypeJS; }
// ECMA 13.2.2 [[Construct]] ConstructType JSFunction::getConstructData(JSCell* cell, ConstructData& constructData) { JSFunction* thisObject = jsCast<JSFunction*>(cell); if (thisObject->isHostFunction()) { constructData.native.function = thisObject->nativeConstructor(); return ConstructTypeHost; } constructData.js.functionExecutable = thisObject->jsExecutable(); constructData.js.scope = thisObject->scope(); return ConstructTypeJS; }
void JSLazyEventListener::parseCode() const { if (m_parsed) return; if (m_globalObject->scriptExecutionContext()->isDocument()) { JSDOMWindow* window = static_cast<JSDOMWindow*>(m_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 = m_globalObject->globalExec(); MarkedArgumentBuffer args; UString sourceURL(m_globalObject->scriptExecutionContext()->url().string()); args.append(jsNontrivialString(exec, m_eventParameterName)); args.append(jsString(exec, m_code)); // FIXME: Passing the document's URL to construct is not always correct, since this event listener might // have been added with setAttribute from a script, and we should pass String() in that case. m_jsFunction = constructFunction(exec, args, Identifier(exec, m_functionName), 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, 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(); }
void JSLazyEventListener::parseCode() const { if (m_parsed) return; m_parsed = true; Frame* frame = window()->impl()->frame(); if (frame && frame->script()->isEnabled()) { ExecState* exec = window()->globalExec(); JSLock lock(false); ArgList args; UString sourceURL(frame->loader()->url().string()); args.append(eventParameterName()); args.append(jsString(exec, m_code)); // FIXME: Passing the document's URL to construct is not always correct, since this event listener might // have been added with setAttribute from a script, and we should pass String() in that case. m_listener = constructFunction(exec, args, Identifier(exec, m_functionName), sourceURL, m_lineNumber); // FIXME: is globalExec ok? JSFunction* listenerAsFunction = static_cast<JSFunction*>(m_listener.get()); if (exec->hadException()) { exec->clearException(); // failed to parse, so let's just make this listener a no-op m_listener = 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, m_originalNode); if (thisObj->isObject()) { static_cast<JSEventTargetNode*>(thisObj)->pushEventHandlerScope(exec, scope); listenerAsFunction->setScope(scope); } } } // no more need to keep the unparsed code around m_functionName = String(); m_code = String(); if (m_listener) { JSDOMWindow::ListenersMap& listeners = isHTMLEventListener() ? window()->jsHTMLEventListeners() : window()->jsEventListeners(); listeners.set(m_listener, const_cast<JSLazyEventListener*>(this)); } }
JSCell* DFG_OPERATION operationNewFunctionExpression(ExecState* exec, JSCell* functionExecutableAsCell) { ASSERT(functionExecutableAsCell->inherits(&FunctionExecutable::s_info)); FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(functionExecutableAsCell); JSFunction *function = functionExecutable->make(exec, exec->scopeChain()); if (!functionExecutable->name().isNull()) { JSStaticScopeObject* functionScopeObject = JSStaticScopeObject::create( exec, functionExecutable->name(), function, ReadOnly | DontDelete); function->setScope(exec->globalData(), function->scope()->push(functionScopeObject)); } return function; }
inline void* linkFor(ExecState* execCallee, ReturnAddressPtr returnAddress, CodeSpecializationKind kind) { ExecState* exec = execCallee->callerFrame(); JSGlobalData* globalData = &exec->globalData(); JSValue calleeAsValue = execCallee->calleeAsValue(); JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue); if (!calleeAsFunctionCell) return handleHostCall(execCallee, calleeAsValue, kind); JSFunction* callee = asFunction(calleeAsFunctionCell); ExecutableBase* executable = callee->executable(); MacroAssemblerCodePtr codePtr; CodeBlock* codeBlock = 0; if (executable->isHostFunction()) codePtr = executable->generatedJITCodeFor(kind).addressForCall(); else { execCallee->setScopeChain(callee->scope()); FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); JSObject* error = functionExecutable->compileFor(execCallee, callee->scope(), kind); if (error) { globalData->exception = createStackOverflowError(exec); return 0; } codeBlock = &functionExecutable->generatedBytecodeFor(kind); if (execCallee->argumentCountIncludingThis() == static_cast<size_t>(codeBlock->m_numParameters)) codePtr = functionExecutable->generatedJITCodeFor(kind).addressForCall(); else codePtr = functionExecutable->generatedJITCodeWithArityCheckFor(kind); } CallLinkInfo& callLinkInfo = exec->codeBlock()->getCallLinkInfo(returnAddress); if (!callLinkInfo.seenOnce()) callLinkInfo.setSeen(); else dfgLinkFor(execCallee, callLinkInfo, codeBlock, callee, codePtr, kind); return codePtr.executableAddress(); }
JSCell* DFG_OPERATION operationCreateThis(ExecState* exec, JSCell* prototype) { JSFunction* constructor = asFunction(exec->callee()); #if !ASSERT_DISABLED ConstructData constructData; ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS); #endif JSGlobalData& globalData = exec->globalData(); Structure* structure; if (prototype->isObject()) structure = asObject(prototype)->inheritorID(globalData); else structure = constructor->scope()->globalObject->emptyObjectStructure(); return constructEmptyObject(exec, structure); }
inline void* virtualFor(ExecState* execCallee, CodeSpecializationKind kind) { ExecState* exec = execCallee->callerFrame(); JSValue calleeAsValue = execCallee->calleeAsValue(); JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue); if (UNLIKELY(!calleeAsFunctionCell)) return handleHostCall(execCallee, calleeAsValue, kind); JSFunction* function = asFunction(calleeAsFunctionCell); execCallee->setScopeChain(function->scopeUnchecked()); ExecutableBase* executable = function->executable(); if (UNLIKELY(!executable->hasJITCodeFor(kind))) { FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); JSObject* error = functionExecutable->compileFor(execCallee, function->scope(), kind); if (error) { exec->globalData().exception = error; return 0; } } return executable->generatedJITCodeWithArityCheckFor(kind).executableAddress(); }
inline char* linkFor(ExecState* execCallee, CodeSpecializationKind kind) { ExecState* exec = execCallee->callerFrame(); VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); JSValue calleeAsValue = execCallee->calleeAsValue(); JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue); if (!calleeAsFunctionCell) return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind)); JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell); execCallee->setScope(callee->scopeUnchecked()); ExecutableBase* executable = callee->executable(); MacroAssemblerCodePtr codePtr; CodeBlock* codeBlock = 0; if (executable->isHostFunction()) codePtr = executable->generatedJITCodeFor(kind)->addressForCall(); else { FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); JSObject* error = functionExecutable->prepareForExecution(execCallee, callee->scope(), kind); if (error) { vm->throwException(exec, createStackOverflowError(exec)); return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress()); } codeBlock = functionExecutable->codeBlockFor(kind); if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters())) codePtr = functionExecutable->generatedJITCodeWithArityCheckFor(kind); else codePtr = functionExecutable->generatedJITCodeFor(kind)->addressForCall(); } CallLinkInfo& callLinkInfo = exec->codeBlock()->getCallLinkInfo(execCallee->returnPC()); if (!callLinkInfo.seenOnce()) callLinkInfo.setSeen(); else linkFor(execCallee, callLinkInfo, codeBlock, callee, codePtr, kind); return reinterpret_cast<char*>(codePtr.executableAddress()); }
inline char* virtualForWithFunction(ExecState* execCallee, CodeSpecializationKind kind, JSCell*& calleeAsFunctionCell) { ExecState* exec = execCallee->callerFrame(); VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); JSValue calleeAsValue = execCallee->calleeAsValue(); calleeAsFunctionCell = getJSFunction(calleeAsValue); if (UNLIKELY(!calleeAsFunctionCell)) return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind)); JSFunction* function = jsCast<JSFunction*>(calleeAsFunctionCell); execCallee->setScope(function->scopeUnchecked()); ExecutableBase* executable = function->executable(); if (UNLIKELY(!executable->hasJITCodeFor(kind))) { FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); JSObject* error = functionExecutable->prepareForExecution(execCallee, function->scope(), kind); if (error) { exec->vm().throwException(execCallee, error); return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress()); } } return reinterpret_cast<char*>(executable->generatedJITCodeWithArityCheckFor(kind).executableAddress()); }
CallFrame* CallFrame::trueCallFrame(AbstractPC pc) { // Am I an inline call frame? If so, we're done. if (isInlineCallFrame()) return this; // If I don't have a code block, then I'm not DFG code, so I'm the true call frame. CodeBlock* machineCodeBlock = codeBlock(); if (!machineCodeBlock) return this; // If the code block does not have any code origins, then there was no inlining, so // I'm done. if (!machineCodeBlock->hasCodeOrigins()) return this; // At this point the PC must be due either to the DFG, or it must be unset. ASSERT(pc.hasJITReturnAddress() || !pc); // Try to determine the CodeOrigin. If we don't have a pc set then the only way // that this makes sense is if the CodeOrigin index was set in the call frame. // FIXME: Note that you will see "Not currently in inlined code" comments below. // Currently, we do not record code origins for code that is not inlined, because // the only thing that we use code origins for is determining the inline stack. // But in the future, we'll want to use this same functionality (having a code // origin mapping for any calls out of JIT code) to determine the PC at any point // in the stack even if not in inlined code. When that happens, the code below // will have to change the way it detects the presence of inlining: it will always // get a code origin, but sometimes, that code origin will not have an inline call // frame. In that case, this method should bail and return this. CodeOrigin codeOrigin; if (pc.isSet()) { ReturnAddressPtr currentReturnPC = pc.jitReturnAddress(); bool hasCodeOrigin = machineCodeBlock->codeOriginForReturn(currentReturnPC, codeOrigin); ASSERT_UNUSED(hasCodeOrigin, hasCodeOrigin); } else { unsigned index = codeOriginIndexForDFG(); codeOrigin = machineCodeBlock->codeOrigin(index); } if (!codeOrigin.inlineCallFrame) return this; // Not currently in inlined code. for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; inlineCallFrame;) { InlineCallFrame* nextInlineCallFrame = inlineCallFrame->caller.inlineCallFrame; CallFrame* inlinedCaller = this + inlineCallFrame->stackOffset; JSFunction* calleeAsFunction = inlineCallFrame->callee.get(); // Fill in the inlinedCaller inlinedCaller->setCodeBlock(machineCodeBlock); inlinedCaller->setScopeChain(calleeAsFunction->scope()); if (nextInlineCallFrame) inlinedCaller->setCallerFrame(this + nextInlineCallFrame->stackOffset); else inlinedCaller->setCallerFrame(this); inlinedCaller->setInlineCallFrame(inlineCallFrame); inlinedCaller->setArgumentCountIncludingThis(inlineCallFrame->arguments.size()); inlinedCaller->setCallee(calleeAsFunction); inlineCallFrame = nextInlineCallFrame; } return this + codeOrigin.inlineCallFrame->stackOffset; }
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; }
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(executionContext); ASSERT(executionContext->isDocument()); if (!executionContext) return 0; Document* document = static_cast<Document*>(executionContext); if (!document->frame()) return 0; if (!document->contentSecurityPolicy()->allowInlineEventHandlers()) return 0; ScriptController* script = document->frame()->script(); if (!script->canExecuteScripts(AboutToExecuteScript) || script->isPaused()) return 0; JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(executionContext, isolatedWorld()); if (!globalObject) return 0; ExecState* exec = globalObject->globalExec(); MarkedArgumentBuffer args; args.append(jsNontrivialString(exec, stringToUString(m_eventParameterName))); args.append(jsString(exec, m_code)); JSObject* jsFunction = constructFunctionSkippingEvalEnabledCheck(exec, exec->lexicalGlobalObject(), args, Identifier(exec, stringToUString(m_functionName)), stringToUString(m_sourceURL), m_position); // FIXME: is globalExec ok? if (exec->hadException()) { reportCurrentException(exec); exec->clearException(); return 0; } 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. JSLock lock(SilenceAssertionsOnly); // FIXME: Should pass the global object associated with the node setWrapper(exec->globalData(), 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(exec->globalData(), jsCast<JSNode*>(wrapper())->pushEventHandlerScope(exec, listenerAsFunction->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; }
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; }