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; }
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); }
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); }
/* 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()); } }
/* 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); } }
// 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; }
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; }
/* 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()); } } }
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; }
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++); }
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; }
// 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; }
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; }
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); }
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()); }
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); }
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; }
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++); } }
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); }
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; }
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()); }
// 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; }
// 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()); }
// 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()); }
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 }