Пример #1
0
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);
}
Пример #2
0
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;
}