Example #1
0
bool
GeneratorObject::suspend(JSContext *cx, HandleObject obj, AbstractFramePtr frame, jsbytecode *pc,
                         Value *vp, unsigned nvalues)
{
    MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD);

    Rooted<GeneratorObject*> genObj(cx, &obj->as<GeneratorObject>());
    MOZ_ASSERT(!genObj->hasExpressionStack());

    if (*pc == JSOP_YIELD && genObj->isClosing() && genObj->is<LegacyGeneratorObject>()) {
        RootedValue val(cx, ObjectValue(*frame.callee()));
        js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, JSDVG_IGNORE_STACK, val, NullPtr());
        return false;
    }

    uint32_t yieldIndex = GET_UINT24(pc);
    genObj->setYieldIndex(yieldIndex);
    genObj->setScopeChain(*frame.scopeChain());

    if (nvalues) {
        ArrayObject *stack = NewDenseCopiedArray(cx, nvalues, vp);
        if (!stack)
            return false;
        genObj->setExpressionStack(*stack);
    }

    return true;
}
Example #2
0
JSObject *
JSAbstractFramePtr::callObject(JSContext *cx)
{
    AbstractFramePtr frame = Valueify(*this);
    JS_ASSERT_IF(frame.isStackFrame(),
                 cx->stack.space().containsSlow(frame.asStackFrame()));

    if (!frame.isFunctionFrame())
        return NULL;

    JSObject *o = GetDebugScopeForFrame(cx, frame);

    /*
     * Given that fp is a function frame and GetDebugScopeForFrame always fills
     * in missing scopes, we can expect to find fp's CallObject on 'o'. Note:
     *  - GetDebugScopeForFrame wraps every ScopeObject (missing or not) with
     *    a DebugScopeObject proxy.
     *  - If fp is an eval-in-function, then fp has no callobj of its own and
     *    JS_GetFrameCallObject will return the innermost function's callobj.
     */
    while (o) {
        ScopeObject &scope = o->asDebugScope().scope();
        if (scope.isCall())
            return o;
        o = o->enclosingScope();
    }
    return NULL;
}
bool
JSAbstractFramePtr::evaluateUCInStackFrame(JSContext *cx,
                                           const jschar *chars, unsigned length,
                                           const char *filename, unsigned lineno,
                                           MutableHandleValue rval)
{
    /* Protect inlined chars from root analysis poisoning. */
    SkipRoot skipChars(cx, &chars);

    if (!CheckDebugMode(cx))
        return false;

    RootedObject scope(cx, scopeChain(cx));
    Rooted<Env*> env(cx, scope);
    if (!env)
        return false;

    AbstractFramePtr frame = Valueify(*this);
    if (!ComputeThis(cx, frame))
        return false;
    RootedValue thisv(cx, frame.thisValue());

    js::AutoCompartment ac(cx, env);
    return EvaluateInEnv(cx, env, thisv, frame, StableCharPtr(chars, length), length,
                         filename, lineno, rval);
}
JSObject *
JSAbstractFramePtr::scopeChain(JSContext *cx)
{
    AbstractFramePtr frame = Valueify(*this);
    RootedObject scopeChain(cx, frame.scopeChain());
    AutoCompartment ac(cx, scopeChain);
    return GetDebugScopeForFrame(cx, frame);
}
Example #5
0
JSObject *
JSAbstractFramePtr::scopeChain(JSContext *cx)
{
    AbstractFramePtr frame = Valueify(*this);
    JS_ASSERT_IF(frame.isStackFrame(),
                 cx->stack.space().containsSlow(frame.asStackFrame()));
    RootedObject scopeChain(cx, frame.scopeChain());
    AutoCompartment ac(cx, scopeChain);
    return GetDebugScopeForFrame(cx, frame);
}
Example #6
0
/* static */ void
ArgumentsObject::MaybeForwardToCallObject(AbstractFramePtr frame, ArgumentsObject* obj,
                                          ArgumentsData* data)
{
    JSScript* script = frame.script();
    if (frame.fun()->needsCallObject() && script->argsObjAliasesFormals()) {
        obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(frame.callObj()));
        for (AliasedFormalIter fi(script); fi; fi++)
            data->args[fi.frameIndex()] = MagicScopeSlotValue(fi.scopeSlot());
    }
}
Example #7
0
/* static */ void
ArgumentsObject::MaybeForwardToCallObject(AbstractFramePtr frame, JSObject *obj,
                                          ArgumentsData *data)
{
    RawScript script = frame.script();
    if (frame.fun()->isHeavyweight() && script->argsObjAliasesFormals()) {
        obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(frame.callObj()));
        for (AliasedFormalIter fi(script); fi; fi++)
            data->args[fi.frameIndex()] = MagicValue(JS_FORWARD_TO_CALL_OBJECT);
    }
}
Example #8
0
// Initialize the decl env Object, call object, and any arguments obj of the current frame.
bool
jit::EnsureHasScopeObjects(JSContext* cx, AbstractFramePtr fp)
{
    if (fp.isFunctionFrame() &&
        fp.fun()->isHeavyweight() &&
        !fp.hasCallObj())
    {
        return fp.initFunctionScopeObjects(cx);
    }
    return true;
}
Example #9
0
FrameIter &
FrameIter::operator++()
{
    switch (data_.state_) {
      case DONE:
        MOZ_ASSUME_UNREACHABLE("Unexpected state");
      case INTERP:
        if (interpFrame()->isDebuggerFrame() && interpFrame()->evalInFramePrev()) {
            AbstractFramePtr eifPrev = interpFrame()->evalInFramePrev();
            MOZ_ASSERT(!eifPrev.isRematerializedFrame());

            // Eval-in-frame can cross contexts and works across saved frame
            // chains.
            ContextOption prevContextOption = data_.contextOption_;
            SavedOption prevSavedOption = data_.savedOption_;
            data_.contextOption_ = ALL_CONTEXTS;
            data_.savedOption_ = GO_THROUGH_SAVED;

            popInterpreterFrame();

            while (isIon() || abstractFramePtr() != eifPrev) {
                if (data_.state_ == JIT) {
#ifdef JS_ION
                    popJitFrame();
#else
                    MOZ_ASSUME_UNREACHABLE("Invalid state");
#endif
                } else {
                    popInterpreterFrame();
                }
            }

            data_.contextOption_ = prevContextOption;
            data_.savedOption_ = prevSavedOption;
            data_.cx_ = data_.activations_->cx();
            break;
        }
        popInterpreterFrame();
        break;
#ifdef JS_ION
      case JIT:
        popJitFrame();
        break;
      case ASMJS:
        popAsmJSFrame();
        break;
#else
    default:
        MOZ_ASSUME_UNREACHABLE("Unexpected state");
#endif
    }
    return *this;
}
Example #10
0
/* static */ void
ArgumentsObject::MaybeForwardToCallObject(AbstractFramePtr frame, ArgumentsObject* obj,
                                          ArgumentsData* data)
{
    JSScript* script = frame.script();
    if (frame.callee()->needsCallObject() && script->argumentsAliasesFormals()) {
        obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(frame.callObj()));
        for (PositionalFormalParameterIter fi(script); fi; fi++) {
            if (fi.closedOver())
                data->args[fi.argumentSlot()] = MagicEnvSlotValue(fi.location().slot());
        }
    }
}
Example #11
0
bool
JSAbstractFramePtr::getThisValue(JSContext *cx, MutableHandleValue thisv)
{
    AbstractFramePtr frame = Valueify(*this);

    RootedObject scopeChain(cx, frame.scopeChain());
    js::AutoCompartment ac(cx, scopeChain);
    if (!ComputeThis(cx, frame))
        return false;

    thisv.set(frame.thisValue());
    return true;
}
Example #12
0
static void
CopyStackFrameArguments(const AbstractFramePtr frame, HeapValue* dst, unsigned totalArgs)
{
    MOZ_ASSERT_IF(frame.isInterpreterFrame(), !frame.asInterpreterFrame()->runningInJit());

    MOZ_ASSERT(Max(frame.numActualArgs(), frame.numFormalArgs()) == totalArgs);

    /* Copy arguments. */
    Value* src = frame.argv();
    Value* end = src + totalArgs;
    while (src != end)
        (dst++)->init(*src++);
}
Example #13
0
JSTrapStatus
js::ScriptDebugPrologue(JSContext *cx, AbstractFramePtr frame)
{
    JS_ASSERT_IF(frame.isStackFrame(), frame.asStackFrame() == cx->fp());

    if (frame.isFramePushedByExecute()) {
        if (JSInterpreterHook hook = cx->runtime->debugHooks.executeHook)
            frame.setHookData(hook(cx, Jsvalify(frame.asStackFrame()), true, 0,
                                   cx->runtime->debugHooks.executeHookData));
    } else {
        if (JSInterpreterHook hook = cx->runtime->debugHooks.callHook)
            frame.setHookData(hook(cx, Jsvalify(frame.asStackFrame()), true, 0,
                                   cx->runtime->debugHooks.callHookData));
    }

    Value rval;
    JSTrapStatus status = Debugger::onEnterFrame(cx, &rval);
    switch (status) {
      case JSTRAP_CONTINUE:
        break;
      case JSTRAP_THROW:
        cx->setPendingException(rval);
        break;
      case JSTRAP_ERROR:
        cx->clearPendingException();
        break;
      case JSTRAP_RETURN:
        frame.setReturnValue(rval);
        break;
      default:
        JS_NOT_REACHED("bad Debugger::onEnterFrame JSTrapStatus value");
    }
    return status;
}
Example #14
0
// Initialize the decl env Object, call object, and any arguments obj of the current frame.
bool
jit::EnsureHasScopeObjects(JSContext* cx, AbstractFramePtr fp)
{
    // Ion does not compile eval scripts.
    MOZ_ASSERT(!fp.isEvalFrame());

    if (fp.isFunctionFrame() &&
        fp.callee()->needsCallObject() &&
        !fp.hasCallObj())
    {
        return fp.initFunctionScopeObjects(cx);
    }
    return true;
}
Example #15
0
bool
js::GeneratorThrowOrClose(JSContext *cx, AbstractFramePtr frame, Handle<GeneratorObject*> genObj,
                          HandleValue arg, uint32_t resumeKind)
{
    if (resumeKind == GeneratorObject::THROW) {
        cx->setPendingException(arg);
        genObj->setRunning();
    } else {
        MOZ_ASSERT(resumeKind == GeneratorObject::CLOSE);

        if (genObj->is<StarGeneratorObject>()) {
            // Store the return value in the frame's CallObject so that we can
            // return it after executing finally blocks (and potentially
            // yielding again).
            MOZ_ASSERT(arg.isObject());
            CallObject &callObj = frame.callObj();
            Shape *shape = callObj.lookup(cx, cx->names().dotGenRVal);
            callObj.setSlot(shape->slot(), arg);
        } else {
            MOZ_ASSERT(arg.isUndefined());
        }

        cx->setPendingException(MagicValue(JS_GENERATOR_CLOSING));
        genObj->setClosing();
    }
    return false;
}
Example #16
0
bool
js::DirectEval(JSContext* cx, HandleValue v, MutableHandleValue vp)
{
    // Direct eval can assume it was called from an interpreted or baseline frame.
    ScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
    AbstractFramePtr caller = iter.abstractFramePtr();

    MOZ_ASSERT(JSOp(*iter.pc()) == JSOP_EVAL ||
               JSOp(*iter.pc()) == JSOP_STRICTEVAL ||
               JSOp(*iter.pc()) == JSOP_SPREADEVAL ||
               JSOp(*iter.pc()) == JSOP_STRICTSPREADEVAL);
    MOZ_ASSERT(caller.compartment() == caller.script()->compartment());

    RootedObject scopeChain(cx, caller.scopeChain());
    return EvalKernel(cx, v, DIRECT_EVAL, caller, scopeChain, iter.pc(), vp);
}
Example #17
0
bool
js::DirectEval(JSContext* cx, const CallArgs& args)
{
    // Direct eval can assume it was called from an interpreted or baseline frame.
    ScriptFrameIter iter(cx);
    AbstractFramePtr caller = iter.abstractFramePtr();

    MOZ_ASSERT(caller.scopeChain()->global().valueIsEval(args.calleev()));
    MOZ_ASSERT(JSOp(*iter.pc()) == JSOP_EVAL ||
               JSOp(*iter.pc()) == JSOP_STRICTEVAL ||
               JSOp(*iter.pc()) == JSOP_SPREADEVAL ||
               JSOp(*iter.pc()) == JSOP_STRICTSPREADEVAL);
    MOZ_ASSERT(caller.compartment() == caller.script()->compartment());

    RootedObject scopeChain(cx, caller.scopeChain());
    return EvalKernel(cx, args, DIRECT_EVAL, caller, scopeChain, iter.pc());
}
void
js::SetReturnValueForClosingGenerator(JSContext* cx, AbstractFramePtr frame)
{
    CallObject& callObj = frame.callObj();

    // Get the generator object stored on the scope chain and close it.
    Shape* shape = callObj.lookup(cx, cx->names().dotGenerator);
    GeneratorObject& genObj = callObj.getSlot(shape->slot()).toObject().as<GeneratorObject>();
    genObj.setClosed();

    // Return value is already set in GeneratorThrowOrClose.
    if (genObj.is<StarGeneratorObject>())
        return;

    // Legacy generator .close() always returns |undefined|.
    MOZ_ASSERT(genObj.is<LegacyGeneratorObject>());
    frame.setReturnValue(UndefinedValue());
}
Example #19
0
bool
js::ScriptDebugEpilogue(JSContext *cx, AbstractFramePtr frame, bool okArg)
{
    JS_ASSERT_IF(frame.isStackFrame(), frame.asStackFrame() == cx->fp());
    JSBool ok = okArg;

    if (void *hookData = frame.maybeHookData()) {
        if (frame.isFramePushedByExecute()) {
            if (JSInterpreterHook hook = cx->runtime->debugHooks.executeHook)
                hook(cx, Jsvalify(frame), IsTopFrameConstructing(cx, frame), false, &ok, hookData);
        } else {
            if (JSInterpreterHook hook = cx->runtime->debugHooks.callHook)
                hook(cx, Jsvalify(frame), IsTopFrameConstructing(cx, frame), false, &ok, hookData);
        }
    }

    return Debugger::onLeaveFrame(cx, ok);
}
bool
js::ScriptDebugEpilogue(JSContext *cx, AbstractFramePtr frame, bool okArg)
{
    JS_ASSERT_IF(frame.isStackFrame(), frame.asStackFrame() == cx->interpreterFrame());

    bool ok = okArg;

    // We don't add hook data for self-hosted scripts, so we don't need to check for them, here.
    if (void *hookData = frame.maybeHookData()) {
        if (frame.isFramePushedByExecute()) {
            if (JSInterpreterHook hook = cx->runtime()->debugHooks.executeHook)
                hook(cx, Jsvalify(frame), IsTopFrameConstructing(cx, frame), false, &ok, hookData);
        } else {
            if (JSInterpreterHook hook = cx->runtime()->debugHooks.callHook)
                hook(cx, Jsvalify(frame), IsTopFrameConstructing(cx, frame), false, &ok, hookData);
        }
    }

    return Debugger::onLeaveFrame(cx, frame, ok);
}
Example #21
0
JSTrapStatus
js::DebugExceptionUnwind(JSContext *cx, AbstractFramePtr frame, jsbytecode *pc)
{
    JS_ASSERT(cx->compartment()->debugMode());

    if (!cx->runtime()->debugHooks.throwHook && cx->compartment()->getDebuggees().empty())
        return JSTRAP_CONTINUE;

    /* Call debugger throw hook if set. */
    RootedValue rval(cx);
    JSTrapStatus status = Debugger::onExceptionUnwind(cx, &rval);
    if (status == JSTRAP_CONTINUE) {
        if (JSThrowHook handler = cx->runtime()->debugHooks.throwHook) {
            RootedScript script(cx, frame.script());
            status = handler(cx, script, pc, rval.address(), cx->runtime()->debugHooks.throwHookData);
        }
    }

    switch (status) {
      case JSTRAP_ERROR:
        cx->clearPendingException();
        break;

      case JSTRAP_RETURN:
        cx->clearPendingException();
        frame.setReturnValue(rval);
        break;

      case JSTRAP_THROW:
        cx->setPendingException(rval);
        break;

      case JSTRAP_CONTINUE:
        break;

      default:
        MOZ_ASSUME_UNREACHABLE("Invalid trap status");
    }

    return status;
}
Example #22
0
static void
CopyStackFrameArguments(const AbstractFramePtr frame, HeapValue *dst, unsigned totalArgs)
{
    JS_ASSERT_IF(frame.isStackFrame(), !frame.asStackFrame()->runningInIon());

    unsigned numActuals = frame.numActualArgs();
    unsigned numFormals = frame.callee()->nargs;
    JS_ASSERT(numActuals <= totalArgs);
    JS_ASSERT(numFormals <= totalArgs);
    JS_ASSERT(Max(numActuals, numFormals) == totalArgs);

    /* Copy formal arguments. */
    Value *src = frame.formals();
    Value *end = src + numFormals;
    while (src != end)
        (dst++)->init(*src++);

    /* Copy actual argument which are not contignous. */
    if (numFormals < numActuals) {
        src = frame.actuals() + numFormals;
        end = src + (numActuals - numFormals);
        while (src != end)
            (dst++)->init(*src++);
    }
}
Example #23
0
void
js::SetReturnValueForClosingGenerator(JSContext *cx, AbstractFramePtr frame)
{
    CallObject &callObj = frame.callObj();

    // Get the generator object stored on the scope chain and close it.
    Shape *shape = callObj.lookup(cx, cx->names().dotGenerator);
    GeneratorObject &genObj = callObj.getSlot(shape->slot()).toObject().as<GeneratorObject>();
    genObj.setClosed();

    Value v;
    if (genObj.is<StarGeneratorObject>()) {
        // The return value is stored in the .genrval slot.
        shape = callObj.lookup(cx, cx->names().dotGenRVal);
        v = callObj.getSlot(shape->slot());
    } else {
        // Legacy generator .close() always returns |undefined|.
        MOZ_ASSERT(genObj.is<LegacyGeneratorObject>());
        v = UndefinedValue();
    }

    frame.setReturnValue(v);
}
Example #24
0
JSTrapStatus
js::ScriptDebugPrologue(JSContext *cx, AbstractFramePtr frame, jsbytecode *pc)
{
    JS_ASSERT_IF(frame.isInterpreterFrame(), frame.asInterpreterFrame() == cx->interpreterFrame());

    if (!frame.script()->selfHosted()) {
        JSAbstractFramePtr jsframe(frame.raw(), pc);
        if (frame.isFramePushedByExecute()) {
            if (JSInterpreterHook hook = cx->runtime()->debugHooks.executeHook)
                frame.setHookData(hook(cx, jsframe, IsTopFrameConstructing(cx, frame),
                                       true, 0, cx->runtime()->debugHooks.executeHookData));
        } else {
            if (JSInterpreterHook hook = cx->runtime()->debugHooks.callHook)
                frame.setHookData(hook(cx, jsframe, IsTopFrameConstructing(cx, frame),
                                       true, 0, cx->runtime()->debugHooks.callHookData));
        }
    }

    RootedValue rval(cx);
    JSTrapStatus status = Debugger::onEnterFrame(cx, frame, &rval);
    switch (status) {
      case JSTRAP_CONTINUE:
        break;
      case JSTRAP_THROW:
        cx->setPendingException(rval);
        break;
      case JSTRAP_ERROR:
        cx->clearPendingException();
        break;
      case JSTRAP_RETURN:
        frame.setReturnValue(rval);
        break;
      default:
        MOZ_ASSUME_UNREACHABLE("bad Debugger::onEnterFrame JSTrapStatus value");
    }
    return status;
}
bool
js::GeneratorThrowOrClose(JSContext* cx, AbstractFramePtr frame, Handle<GeneratorObject*> genObj,
                          HandleValue arg, uint32_t resumeKind)
{
    if (resumeKind == GeneratorObject::THROW) {
        cx->setPendingException(arg);
        genObj->setRunning();
    } else {
        MOZ_ASSERT(resumeKind == GeneratorObject::CLOSE);

        if (genObj->is<StarGeneratorObject>()) {
            MOZ_ASSERT(arg.isObject());
            frame.setReturnValue(arg);
        } else {
            MOZ_ASSERT(arg.isUndefined());
        }

        cx->setPendingException(MagicValue(JS_GENERATOR_CLOSING));
        genObj->setClosing();
    }
    return false;
}
Example #26
0
bool
js::DirectEval(JSContext *cx, const CallArgs &args)
{
    // Direct eval can assume it was called from an interpreted or baseline frame.
    ScriptFrameIter iter(cx);
    AbstractFramePtr caller = iter.abstractFramePtr();

    JS_ASSERT(IsBuiltinEvalForScope(caller.scopeChain(), args.calleev()));
    JS_ASSERT(JSOp(*iter.pc()) == JSOP_EVAL);
    JS_ASSERT_IF(caller.isFunctionFrame(),
                 caller.compartment() == caller.callee()->compartment());

    if (!WarnOnTooManyArgs(cx, args))
        return false;

    RootedObject scopeChain(cx, caller.scopeChain());
    return EvalKernel(cx, args, DIRECT_EVAL, caller, scopeChain, iter.pc());
}
Example #27
0
// Initialize the decl env Object, call object, and any arguments obj of the
// current frame.
bool
jit::EnsureHasEnvironmentObjects(JSContext* cx, AbstractFramePtr fp)
{
    // Ion does not compile eval scripts.
    MOZ_ASSERT(!fp.isEvalFrame());

    if (fp.isFunctionFrame()) {
        // Ion does not handle extra var environments due to parameter
        // expressions yet.
        MOZ_ASSERT(!fp.callee()->needsExtraBodyVarEnvironment());

        if (!fp.hasInitialEnvironment() && fp.callee()->needsFunctionEnvironmentObjects()) {
            if (!fp.initFunctionEnvironmentObjects(cx))
                return false;
        }
    }

    return true;
}
Example #28
0
// Common code implementing direct and indirect eval.
//
// Evaluate call.argv[2], if it is a string, in the context of the given calling
// frame, with the provided scope chain, with the semantics of either a direct
// or indirect eval (see ES5 10.4.2).  If this is an indirect eval, scopeobj
// must be a global object.
//
// On success, store the completion value in call.rval and return true.
static bool
EvalKernel(JSContext* cx, HandleValue v, EvalType evalType, AbstractFramePtr caller,
           HandleObject scopeobj, jsbytecode* pc, MutableHandleValue vp)
{
    MOZ_ASSERT((evalType == INDIRECT_EVAL) == !caller);
    MOZ_ASSERT((evalType == INDIRECT_EVAL) == !pc);
    MOZ_ASSERT_IF(evalType == INDIRECT_EVAL, IsGlobalLexicalScope(scopeobj));
    AssertInnerizedScopeChain(cx, *scopeobj);

    Rooted<GlobalObject*> scopeObjGlobal(cx, &scopeobj->global());
    if (!GlobalObject::isRuntimeCodeGenEnabled(cx, scopeObjGlobal)) {
        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_EVAL);
        return false;
    }

    // ES5 15.1.2.1 step 1.
    if (!v.isString()) {
        vp.set(v);
        return true;
    }
    RootedString str(cx, v.toString());

    // ES5 15.1.2.1 steps 2-8.

    // Per ES5, indirect eval runs in the global scope. (eval is specified this
    // way so that the compiler can make assumptions about what bindings may or
    // may not exist in the current frame if it doesn't see 'eval'.)
    MOZ_ASSERT_IF(evalType != DIRECT_EVAL,
                  cx->global() == &scopeobj->as<ClonedBlockObject>().global());

    RootedLinearString linearStr(cx, str->ensureLinear(cx));
    if (!linearStr)
        return false;

    RootedScript callerScript(cx, caller ? caller.script() : nullptr);
    EvalJSONResult ejr = TryEvalJSON(cx, linearStr, vp);
    if (ejr != EvalJSON_NotJSON)
        return ejr == EvalJSON_Success;

    EvalScriptGuard esg(cx);

    if (evalType == DIRECT_EVAL && caller.isFunctionFrame())
        esg.lookupInEvalCache(linearStr, callerScript, pc);

    if (!esg.foundScript()) {
        RootedScript maybeScript(cx);
        unsigned lineno;
        const char* filename;
        bool mutedErrors;
        uint32_t pcOffset;
        DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno, &pcOffset,
                                             &mutedErrors,
                                             evalType == DIRECT_EVAL
                                             ? CALLED_FROM_JSOP_EVAL
                                             : NOT_CALLED_FROM_JSOP_EVAL);

        const char* introducerFilename = filename;
        if (maybeScript && maybeScript->scriptSource()->introducerFilename())
            introducerFilename = maybeScript->scriptSource()->introducerFilename();

        RootedObject enclosing(cx);
        if (evalType == DIRECT_EVAL)
            enclosing = callerScript->innermostStaticScope(pc);
        else
            enclosing = &cx->global()->lexicalScope().staticBlock();
        Rooted<StaticEvalScope*> staticScope(cx, StaticEvalScope::create(cx, enclosing));
        if (!staticScope)
            return false;

        CompileOptions options(cx);
        options.setIsRunOnce(true)
               .setForEval(true)
               .setNoScriptRval(false)
               .setMutedErrors(mutedErrors)
               .maybeMakeStrictMode(evalType == DIRECT_EVAL && IsStrictEvalPC(pc));

        if (introducerFilename) {
            options.setFileAndLine(filename, 1);
            options.setIntroductionInfo(introducerFilename, "eval", lineno, maybeScript, pcOffset);
        } else {
            options.setFileAndLine("eval", 1);
            options.setIntroductionType("eval");
        }

        AutoStableStringChars linearChars(cx);
        if (!linearChars.initTwoByte(cx, linearStr))
            return false;

        const char16_t* chars = linearChars.twoByteRange().start().get();
        SourceBufferHolder::Ownership ownership = linearChars.maybeGiveOwnershipToCaller()
                                                  ? SourceBufferHolder::GiveOwnership
                                                  : SourceBufferHolder::NoOwnership;
        SourceBufferHolder srcBuf(chars, linearStr->length(), ownership);
        JSScript* compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(),
                                                     scopeobj, staticScope, callerScript,
                                                     options, srcBuf, linearStr);
        if (!compiled)
            return false;

        if (compiled->strict())
            staticScope->setStrict();

        esg.setNewScript(compiled);
    }

    // Look up the newTarget from the frame iterator.
    Value newTargetVal = NullValue();
    return ExecuteKernel(cx, esg.script(), *scopeobj, newTargetVal,
                         NullFramePtr() /* evalInFrame */, vp.address());
}
Example #29
0
// Common code implementing direct and indirect eval.
//
// Evaluate call.argv[2], if it is a string, in the context of the given calling
// frame, with the provided scope chain, with the semantics of either a direct
// or indirect eval (see ES5 10.4.2).  If this is an indirect eval, scopeobj
// must be a global object.
//
// On success, store the completion value in call.rval and return true.
static bool
EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFramePtr caller,
           HandleObject scopeobj, jsbytecode *pc)
{
    JS_ASSERT((evalType == INDIRECT_EVAL) == !caller);
    JS_ASSERT((evalType == INDIRECT_EVAL) == !pc);
    JS_ASSERT_IF(evalType == INDIRECT_EVAL, scopeobj->is<GlobalObject>());
    AssertInnerizedScopeChain(cx, *scopeobj);

    Rooted<GlobalObject*> scopeObjGlobal(cx, &scopeobj->global());
    if (!GlobalObject::isRuntimeCodeGenEnabled(cx, scopeObjGlobal)) {
        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_EVAL);
        return false;
    }

    // ES5 15.1.2.1 step 1.
    if (args.length() < 1) {
        args.rval().setUndefined();
        return true;
    }
    if (!args[0].isString()) {
        args.rval().set(args[0]);
        return true;
    }
    RootedString str(cx, args[0].toString());

    // ES5 15.1.2.1 steps 2-8.

    // Per ES5, indirect eval runs in the global scope. (eval is specified this
    // way so that the compiler can make assumptions about what bindings may or
    // may not exist in the current frame if it doesn't see 'eval'.)
    unsigned staticLevel;
    RootedValue thisv(cx);
    if (evalType == DIRECT_EVAL) {
        JS_ASSERT_IF(caller.isInterpreterFrame(), !caller.asInterpreterFrame()->runningInJit());
        staticLevel = caller.script()->staticLevel() + 1;

        // Direct calls to eval are supposed to see the caller's |this|. If we
        // haven't wrapped that yet, do so now, before we make a copy of it for
        // the eval code to use.
        if (!ComputeThis(cx, caller))
            return false;
        thisv = caller.thisValue();
    } else {
        JS_ASSERT(args.callee().global() == *scopeobj);
        staticLevel = 0;

        // Use the global as 'this', modulo outerization.
        JSObject *thisobj = JSObject::thisObject(cx, scopeobj);
        if (!thisobj)
            return false;
        thisv = ObjectValue(*thisobj);
    }

    Rooted<JSFlatString*> flatStr(cx, str->ensureFlat(cx));
    if (!flatStr)
        return false;

    RootedScript callerScript(cx, caller ? caller.script() : nullptr);
    EvalJSONResult ejr = TryEvalJSON(cx, callerScript, flatStr, args.rval());
    if (ejr != EvalJSON_NotJSON)
        return ejr == EvalJSON_Success;

    EvalScriptGuard esg(cx);

    if (evalType == DIRECT_EVAL && caller.isNonEvalFunctionFrame())
        esg.lookupInEvalCache(flatStr, callerScript, pc);

    if (!esg.foundScript()) {
        RootedScript maybeScript(cx);
        unsigned lineno;
        const char *filename;
        JSPrincipals *originPrincipals;
        uint32_t pcOffset;
        DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno, &pcOffset,
                                             &originPrincipals,
                                             evalType == DIRECT_EVAL
                                             ? CALLED_FROM_JSOP_EVAL
                                             : NOT_CALLED_FROM_JSOP_EVAL);

        const char *introducerFilename = filename;
        if (maybeScript && maybeScript->scriptSource()->introducerFilename())
            introducerFilename = maybeScript->scriptSource()->introducerFilename();

        CompileOptions options(cx);
        options.setFileAndLine(filename, 1)
               .setCompileAndGo(true)
               .setForEval(true)
               .setNoScriptRval(false)
               .setOriginPrincipals(originPrincipals)
               .setIntroductionInfo(introducerFilename, "eval", lineno, maybeScript, pcOffset);

        AutoStableStringChars flatChars(cx);
        if (!flatChars.initTwoByte(cx, flatStr))
            return false;

        const char16_t *chars = flatChars.twoByteRange().start().get();
        SourceBufferHolder::Ownership ownership = flatChars.maybeGiveOwnershipToCaller()
                                                  ? SourceBufferHolder::GiveOwnership
                                                  : SourceBufferHolder::NoOwnership;
        SourceBufferHolder srcBuf(chars, flatStr->length(), ownership);
        JSScript *compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(),
                                                     scopeobj, callerScript, options,
                                                     srcBuf, flatStr, staticLevel);
        if (!compiled)
            return false;

        esg.setNewScript(compiled);
    }

    return ExecuteKernel(cx, esg.script(), *scopeobj, thisv, ExecuteType(evalType),
                         NullFramePtr() /* evalInFrame */, args.rval().address());
}
Example #30
0
void
StackFrame::initExecuteFrame(JSContext *cx, JSScript *script, AbstractFramePtr evalInFramePrev,
                             const Value &thisv, JSObject &scopeChain, ExecuteType type)
{
    /*
     * See encoding of ExecuteType. When GLOBAL isn't set, we are executing a
     * script in the context of another frame and the frame type is determined
     * by the context.
     */
    flags_ = type | HAS_SCOPECHAIN;

    JSObject *callee = nullptr;
    if (!(flags_ & (GLOBAL))) {
        if (evalInFramePrev) {
            JS_ASSERT(evalInFramePrev.isFunctionFrame() || evalInFramePrev.isGlobalFrame());
            if (evalInFramePrev.isFunctionFrame()) {
                callee = evalInFramePrev.callee();
                flags_ |= FUNCTION;
            } else {
                flags_ |= GLOBAL;
            }
        } else {
            ScriptFrameIter iter(cx);
            JS_ASSERT(iter.isFunctionFrame() || iter.isGlobalFrame());
            if (iter.isFunctionFrame()) {
                callee = iter.callee();
                flags_ |= FUNCTION;
            } else {
                flags_ |= GLOBAL;
            }
        }
    }

    Value *dstvp = (Value *)this - 2;
    dstvp[1] = thisv;

    if (isFunctionFrame()) {
        dstvp[0] = ObjectValue(*callee);
        exec.fun = &callee->as<JSFunction>();
        u.evalScript = script;
    } else {
        JS_ASSERT(isGlobalFrame());
        dstvp[0] = NullValue();
        exec.script = script;
#ifdef DEBUG
        u.evalScript = (JSScript *)0xbad;
#endif
    }

    scopeChain_ = &scopeChain;
    prev_ = nullptr;
    prevpc_ = nullptr;
    prevsp_ = nullptr;

    JS_ASSERT_IF(evalInFramePrev, isDebuggerFrame());
    evalInFramePrev_ = evalInFramePrev;

#ifdef DEBUG
    Debug_SetValueRangeToCrashOnTouch(&rval_, 1);
    hookData_ = (void *)0xbad;
#endif
}