FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception) { JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); RefPtr<ProgramNode> program = exec->globalData().parser->parse<ProgramNode>(lexicalGlobalObject, debugger, exec, source, 0, JSParseNormal, exception); if (!program) { ASSERT(*exception); return 0; } // Uses of this function that would not result in a single function expression are invalid. StatementNode* exprStatement = program->singleStatement(); ASSERT(exprStatement); ASSERT(exprStatement->isExprStatement()); ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr(); ASSERT(funcExpr); ASSERT(funcExpr->isFuncExprNode()); FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body(); ASSERT(body); return FunctionExecutable::create(exec->globalData(), functionName, body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine()); }
void WebDebugListenerImpl::sourceParsedFunctions(ExecState* execState, intptr_t sourceId, JSC::ParserArenaData<DeclarationStacks::FunctionStack>* funcStack) { if (m_listener && !m_inDebug) { m_inDebug = true; MarkedArgumentBuffer funcList; ArgList empty; Identifier functionName (execState, "functionName"); Identifier firstLine (execState, "firstLine"); Identifier lastLine (execState, "lastLine"); for(size_t i=0, l=funcStack->data.size(); i<l; i++) { FunctionBodyNode *funcBody = funcStack->data[i]; ASSERT(funcBody); if (!funcBody) continue; JSObject* funcObj = JSC::constructEmptyObject(execState); JSC::PutPropertySlot slot; funcObj->put(execState, functionName, jsString( execState, funcBody->ident().ustring() ), slot ); funcObj->put(execState, firstLine, jsNumber ( execState, funcBody->firstLine() ), slot ); funcObj->put(execState, lastLine, jsNumber ( execState, funcBody->lastLine() ), slot); funcList.append(funcObj); } JSObject* functions = JSC::constructArray(execState, funcList); WebScriptProxyVariant* functionsVariant = WebCore::ApolloScriptBridging::getApolloVariantForJSValue(execState, functions); m_listener->m_pVTable->sourceParsedFunctions(m_listener, sourceId, functionsVariant); m_inDebug = false; } }
PassRefPtr<FunctionExecutable> FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, int* errLine, UString* errMsg) { RefPtr<ProgramNode> program = exec->globalData().parser->parse<ProgramNode>(&exec->globalData(), debugger, exec, source, errLine, errMsg); if (!program) return 0; StatementNode* exprStatement = program->singleStatement(); ASSERT(exprStatement); ASSERT(exprStatement->isExprStatement()); if (!exprStatement || !exprStatement->isExprStatement()) return 0; ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr(); ASSERT(funcExpr); ASSERT(funcExpr->isFuncExprNode()); if (!funcExpr || !funcExpr->isFuncExprNode()) return 0; FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body(); ASSERT(body); return FunctionExecutable::create(&exec->globalData(), functionName, body->source(), body->usesArguments(), body->parameters(), body->lineNo(), body->lastLine()); }
void FunctionImp::initialCompile(ExecState* newExec) { FunctionBodyNode* body = this->body.get(); // Reserve various slots needed for the activation object. We do it only once, // --- isCompiled() would return true even if debugging state changed body->reserveSlot(ActivationImp::LengthSlot, false); body->reserveSlot(ActivationImp::TearOffNeeded, false); body->reserveSlot(ActivationImp::ScopeLink, false /* will mark via ScopeChain::mark() */); body->reserveSlot(ActivationImp::FunctionSlot, true); body->reserveSlot(ActivationImp::ArgumentsObjectSlot, true); // Create declarations for parameters, and allocate the symbols. // We always just give them sequential positions, to make passInParameters // simple (though perhaps wasting memory in the trivial case) for (size_t i = 0; i < body->numParams(); ++i) body->addSymbolOverwriteID(i + ActivationImp::NumReservedSlots, body->paramName(i), DontDelete); body->processDecls(newExec); body->compile(FunctionCode, newExec->dynamicInterpreter()->debugger() ? Debug : Release); }
// ECMA 10.1.6 void ActivationImp::setup(ExecState* exec, FunctionImp *function, const List* arguments, LocalStorageEntry* entries) { FunctionBodyNode* body = function->body.get(); size_t total = body->numLocalsAndRegisters(); localStorage = entries; lengthSlot() = total; // we can now link ourselves into the scope, which will also fix up our scopeLink(). exec->pushVariableObjectScope(this); const FunctionBodyNode::SymbolInfo* symInfo = body->getLocalInfo(); // Setup our fields this->arguments = arguments; functionSlot() = function; argumentsObjectSlot() = jsUndefined(); symbolTable = &body->symbolTable(); // Set the mark/don't mark flags and attributes for everything for (size_t p = 0; p < total; ++p) entries[p].attributes = symInfo[p].attr; // Pass in the parameters (ECMA 10.1.3q) #ifdef KJS_VERBOSE fprintf(stderr, "%s---------------------------------------------------\n" "%sprocessing parameters for %s call\n", ind(), ind(), function->functionName().isEmpty() ? "(internal)" : function->functionName().ascii()); #endif size_t numParams = body->numParams(); size_t numPassedIn = min(numParams, static_cast<size_t>(arguments->size())); size_t pos = 0; for (; pos < numPassedIn; ++pos) { size_t symNum = pos + ActivationImp::NumReservedSlots; JSValue* v = arguments->atUnchecked(pos); entries[symNum].val.valueVal = v; #ifdef KJS_VERBOSE fprintf(stderr, "%s setting parameter %s", ind(), body->paramName(pos).ascii()); printInfo(exec, "to", v); #endif } for (; pos < numParams; ++pos) { size_t symNum = pos + ActivationImp::NumReservedSlots; entries[symNum].val.valueVal = jsUndefined(); #ifdef KJS_VERBOSE fprintf(stderr, "%s setting parameter %s to undefined (not passed in)", ind(), body->paramName(pos).ascii()); #endif } #ifdef KJS_VERBOSE fprintf(stderr, "\n%s---------------------------------\n", ind()); fprintf(stderr, "%sBody:\n", ind()); fprintf(stderr, "%s---------------------------------\n", ind()); printInd(body->toString().ascii()); fprintf(stderr, "\n%s---------------------------------\n\n", ind()); #endif // Initialize the rest of the locals to 'undefined' for (size_t pos = numParams + ActivationImp::NumReservedSlots; pos < total; ++pos) entries[pos].val.valueVal = jsUndefined(); // Finally, put in the functions. Note that this relies on above // steps to have completed, since it can trigger a GC. size_t numFuns = body->numFunctionLocals(); size_t* funsData = body->getFunctionLocalInfo(); for (size_t fun = 0; fun < numFuns; ++fun) { size_t id = funsData[fun]; entries[id].val.valueVal = symInfo[id].funcDecl->makeFunctionObject(exec); } }
JSValue* FunctionImp::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args) { assert(thisObj); #ifdef KJS_VERBOSE ++callDepth; #endif Debugger* dbg = exec->dynamicInterpreter()->debugger(); // enter a new execution context FunctionExecState newExec(exec->dynamicInterpreter(), thisObj, body.get(), exec, this); if (exec->hadException()) newExec.setException(exec->exception()); FunctionBodyNode* body = this->body.get(); // The first time we're called, compute the set of local variables, // and compile the body. (note that parameters have been collected // during the AST build) CompileType currentState = body->compileState(); if (currentState == NotCompiled) { initialCompile(&newExec); } else { // Otherwise, we may still need to recompile due to debug... CompileType desiredState = dbg ? Debug : Release; if (desiredState != currentState) body->compile(FunctionCode, desiredState); } size_t stackSize = 0; LocalStorageEntry* stackSpace = 0; // We always allocate on stack initially, and tearoff only after we're done. int regs = body->numLocalsAndRegisters(); stackSize = sizeof(LocalStorageEntry) * regs; stackSpace = (LocalStorageEntry*)exec->dynamicInterpreter()->stackAlloc(stackSize); ActivationImp* activation = static_cast<ActivationImp*>(newExec.activationObject()); activation->setup(&newExec, this, &args, stackSpace); activation->tearOffNeededSlot() = body->tearOffAtEnd(); newExec.initLocalStorage(stackSpace, regs); JSValue* result = Machine::runBlock(&newExec, body->code(), exec); // If we need to tear off now --- either due to static flag above, or // if execution requested it dynamically --- do so now. if (activation->tearOffNeededSlot()) { activation->performTearOff(); } else { // Otherwise, we recycle the activation object; we must clear its // data pointer, though, since that may become dead. // (we also unlink it from the scope chain at this time) activation->scopeLink().deref(); activation->localStorage = 0; exec->dynamicInterpreter()->recycleActivation(activation); } // Now free the stack space.. exec->dynamicInterpreter()->stackFree(stackSize); #ifdef KJS_VERBOSE fprintf(stderr, "%s", ind()); if (exec->exception()) printInfo(exec,"throwing", exec->exception()); else printInfo(exec,"returning", result); --callDepth; #endif return result; }