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); }
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; }