Beispiel #1
0
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;
    }
}
Beispiel #3
0
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());
}
Beispiel #4
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);
}
Beispiel #5
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);
    }
}
Beispiel #6
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;
}