Bug 1259877 - Change js::DirectEval to take v/vp rather than a CallArgs to operate on directly. r=efaust
authorJeff Walden <jwalden@mit.edu>
Mon, 21 Mar 2016 14:28:59 -0700
changeset 331011 f0d5faf75aa52770bffb0e39ac786b5c9fc101af
parent 331010 cd77e25dd6009768c862a4969969f37bdb1469d2
child 331012 b9d51ed412a7ccf1ad49e7fb1bb998720e23a7fa
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust
bugs1259877
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1259877 - Change js::DirectEval to take v/vp rather than a CallArgs to operate on directly. r=efaust
js/src/builtin/Eval.cpp
js/src/builtin/Eval.h
js/src/jit/BaselineIC.cpp
js/src/vm/Interpreter.cpp
--- a/js/src/builtin/Eval.cpp
+++ b/js/src/builtin/Eval.cpp
@@ -219,55 +219,51 @@ enum EvalType { DIRECT_EVAL, INDIRECT_EV
 //
 // 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)
+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 (args.length() < 1) {
-        args.rval().setUndefined();
+    if (!v.isString()) {
+        vp.set(v);
         return true;
     }
-    if (!args[0].isString()) {
-        args.rval().set(args[0]);
-        return true;
-    }
-    RootedString str(cx, args[0].toString());
+    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,
-                  args.callee().global() == scopeobj->as<ClonedBlockObject>().global());
+                  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, args.rval());
+    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);
 
@@ -324,17 +320,17 @@ EvalKernel(JSContext* cx, const CallArgs
             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 */, args.rval().address());
+                         NullFramePtr() /* evalInFrame */, vp.address());
 }
 
 bool
 js::DirectEvalStringFromIon(JSContext* cx,
                             HandleObject scopeObj, HandleScript callerScript,
                             HandleValue newTargetValue, HandleString str,
                             jsbytecode* pc, MutableHandleValue vp)
 {
@@ -411,37 +407,41 @@ js::DirectEvalStringFromIon(JSContext* c
     return ExecuteKernel(cx, esg.script(), *scopeObj, newTargetValue,
                          NullFramePtr() /* evalInFrame */, vp.address());
 }
 
 bool
 js::IndirectEval(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
+
     Rooted<GlobalObject*> global(cx, &args.callee().global());
     RootedObject globalLexical(cx, &global->lexicalScope());
-    return EvalKernel(cx, args, INDIRECT_EVAL, NullFramePtr(), globalLexical, nullptr);
+
+    // Note we'll just pass |undefined| here, then return it directly (or throw
+    // if runtime codegen is disabled), if no argument is provided.
+    return EvalKernel(cx, args.get(0), INDIRECT_EVAL, NullFramePtr(), globalLexical, nullptr,
+                      args.rval());
 }
 
 bool
-js::DirectEval(JSContext* cx, const CallArgs& args)
+js::DirectEval(JSContext* cx, HandleValue v, MutableHandleValue vp)
 {
     // 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());
+    return EvalKernel(cx, v, DIRECT_EVAL, caller, scopeChain, iter.pc(), vp);
 }
 
 bool
 js::IsAnyBuiltinEval(JSFunction* fun)
 {
     return fun->maybeNative() == IndirectEval;
 }
 
--- a/js/src/builtin/Eval.h
+++ b/js/src/builtin/Eval.h
@@ -15,21 +15,21 @@ namespace js {
 // The C++ native for 'eval' (ES5 15.1.2.1). The function is named "indirect
 // eval" because "direct eval" calls (as defined by the spec) will emit
 // JSOP_EVAL which in turn calls DirectEval. Thus, even though IndirectEval is
 // the callee function object for *all* calls to eval, it is by construction
 // only ever called in the case indirect eval.
 extern bool
 IndirectEval(JSContext* cx, unsigned argc, Value* vp);
 
-// Performs a direct eval for the given arguments, which must correspond to the
-// currently-executing stack frame, which must be a script frame. On completion
-// the result is returned in args.rval.
+// Performs a direct eval of |v| (a string containing code, or another value
+// that will be vacuously returned), which must correspond to the currently-
+// executing stack frame, which must be a script frame.
 extern bool
-DirectEval(JSContext* cx, const CallArgs& args);
+DirectEval(JSContext* cx, HandleValue v, MutableHandleValue vp);
 
 // Performs a direct eval called from Ion code.
 extern bool
 DirectEvalStringFromIon(JSContext* cx,
                         HandleObject scopeObj, HandleScript callerScript,
                         HandleValue newTargetValue, HandleString str,
                         jsbytecode* pc, MutableHandleValue vp);
 
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -6089,39 +6089,41 @@ DoCallFallback(JSContext* cx, BaselineFr
                            createSingleton, &handled))
     {
         return false;
     }
 
     if (op == JSOP_NEW) {
         if (!ConstructFromStack(cx, callArgs))
             return false;
+        res.set(callArgs.rval());
     } else if ((op == JSOP_EVAL || op == JSOP_STRICTEVAL) &&
                frame->scopeChain()->global().valueIsEval(callee))
     {
-        if (!DirectEval(cx, callArgs))
+        if (!DirectEval(cx, callArgs.get(0), res))
             return false;
     } else {
         MOZ_ASSERT(op == JSOP_CALL ||
                    op == JSOP_CALLITER ||
                    op == JSOP_FUNCALL ||
                    op == JSOP_FUNAPPLY ||
                    op == JSOP_EVAL ||
                    op == JSOP_STRICTEVAL);
         if (op == JSOP_CALLITER && callee.isPrimitive()) {
             MOZ_ASSERT(argc == 0, "thisv must be on top of the stack");
             ReportValueError(cx, JSMSG_NOT_ITERABLE, -1, callArgs.thisv(), nullptr);
             return false;
         }
 
         if (!Invoke(cx, callArgs))
             return false;
-    }
-
-    res.set(callArgs.rval());
+
+        res.set(callArgs.rval());
+    }
+
     TypeScript::Monitor(cx, script, pc, res);
 
     // Check if debug mode toggling made the stub invalid.
     if (stub.invalid())
         return true;
 
     // Attach a new TypeMonitor stub for this value.
     ICTypeMonitor_Fallback* typeMonFbStub = stub->fallbackMonitorStub();
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -2713,24 +2713,26 @@ CASE(JSOP_STRICTSETELEM_SUPER)
 }
 END_CASE(JSOP_SETELEM_SUPER)
 
 CASE(JSOP_EVAL)
 CASE(JSOP_STRICTEVAL)
 {
     static_assert(JSOP_EVAL_LENGTH == JSOP_STRICTEVAL_LENGTH,
                   "eval and stricteval must be the same size");
+
     CallArgs args = CallArgsFromSp(GET_ARGC(REGS.pc), REGS.sp);
     if (REGS.fp()->scopeChain()->global().valueIsEval(args.calleev())) {
-        if (!DirectEval(cx, args))
+        if (!DirectEval(cx, args.get(0), args.rval()))
             goto error;
     } else {
         if (!Invoke(cx, args))
             goto error;
     }
+
     REGS.sp = args.spAfterCall();
     TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]);
 }
 END_CASE(JSOP_EVAL)
 
 CASE(JSOP_SPREADNEW)
 CASE(JSOP_SPREADCALL)
 CASE(JSOP_SPREADSUPERCALL)
@@ -4619,32 +4621,32 @@ js::SpreadCallOperation(JSContext* cx, H
 
         if (!GetElements(cx, aobj, length, args.array()))
             return false;
 
         switch (op) {
           case JSOP_SPREADCALL:
             if (!Invoke(cx, args))
                 return false;
+            res.set(args.rval());
             break;
           case JSOP_SPREADEVAL:
           case JSOP_STRICTSPREADEVAL:
-            if (cx->global()->valueIsEval(args.calleev())) {
-                if (!DirectEval(cx, args))
+            if (cx->global()->valueIsEval(callee)) {
+                if (!DirectEval(cx, args.get(0), res))
                     return false;
             } else {
                 if (!Invoke(cx, args))
                     return false;
+                res.set(args.rval());
             }
             break;
           default:
             MOZ_CRASH("bad spread opcode");
         }
-
-        res.set(args.rval());
     }
 
     TypeScript::Monitor(cx, script, pc, res);
     return true;
 }
 
 bool
 js::OptimizeSpreadCall(JSContext* cx, HandleValue arg, bool* optimized)