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