Esempio n. 1
0
// 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);
    }
}
Esempio n. 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;
}