Bug 1341061 - Refactor NAME-related runtime functions. (r=arai)
authorShu-yu Guo <shu@rfrn.org>
Fri, 24 Feb 2017 16:51:10 -0800
changeset 373940 3e4be5b2b23d7b0ecac564f464bf4534eecab94c
parent 373939 d309d805ebc966fa402d20ce0a47eb12fec5b704
child 373941 a295d7cb1e9bafe7ee6a1c9716fe7c4e975e086c
push id10863
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 23:02:23 +0000
treeherdermozilla-aurora@0931190cd725 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersarai
bugs1341061
milestone54.0a1
Bug 1341061 - Refactor NAME-related runtime functions. (r=arai)
js/src/jit/BaselineIC.cpp
js/src/jit/IonCaches.cpp
js/src/vm/Interpreter-inl.h
js/src/vm/Interpreter.cpp
js/src/vm/Interpreter.h
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -1278,20 +1278,20 @@ DoGetNameFallback(JSContext* cx, Baselin
                 attached = true;
             }
         }
     }
 
     static_assert(JSOP_GETGNAME_LENGTH == JSOP_GETNAME_LENGTH,
                   "Otherwise our check for JSOP_TYPEOF isn't ok");
     if (JSOp(pc[JSOP_GETGNAME_LENGTH]) == JSOP_TYPEOF) {
-        if (!GetEnvironmentNameForTypeOf(cx, envChain, name, res))
+        if (!GetEnvironmentName<GetNameMode::TypeOf>(cx, envChain, name, res))
             return false;
     } else {
-        if (!GetEnvironmentName(cx, envChain, name, res))
+        if (!GetEnvironmentName<GetNameMode::Normal>(cx, envChain, name, res))
             return false;
     }
 
     TypeScript::Monitor(cx, script, pc, res);
 
     // Check if debug mode toggling made the stub invalid.
     if (stub.invalid())
         return true;
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -3383,20 +3383,20 @@ NameIC::update(JSContext* cx, HandleScri
     RootedObject obj(cx);
     RootedObject holder(cx);
     Rooted<PropertyResult> prop(cx);
     if (!LookupName(cx, name, envChain, &obj, &holder, &prop))
         return false;
 
     // Look first. Don't generate cache entries if the lookup fails.
     if (cache.isTypeOf()) {
-        if (!FetchName<true>(cx, obj, holder, name, prop, vp))
+        if (!FetchName<GetNameMode::TypeOf>(cx, obj, holder, name, prop, vp))
             return false;
     } else {
-        if (!FetchName<false>(cx, obj, holder, name, prop, vp))
+        if (!FetchName<GetNameMode::Normal>(cx, obj, holder, name, prop, vp))
             return false;
     }
 
     if (cache.canAttachStub()) {
         if (IsCacheableNameReadSlot(cx, envChain, obj, holder, prop, pc, cache.outputReg())) {
             if (!cache.attachReadSlot(cx, outerScript, ion, envChain, obj,
                                       holder.as<NativeObject>(), prop))
             {
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -169,44 +169,53 @@ GetLengthProperty(const Value& lval, Mut
                 return true;
             }
         }
     }
 
     return false;
 }
 
-template <bool TypeOf> inline bool
-FetchName(JSContext* cx, HandleObject obj, HandleObject obj2, HandlePropertyName name,
+enum class GetNameMode
+{
+    Normal,
+    TypeOf
+};
+
+template <GetNameMode mode>
+inline bool
+FetchName(JSContext* cx, HandleObject receiver, HandleObject holder, HandlePropertyName name,
           Handle<PropertyResult> prop, MutableHandleValue vp)
 {
     if (!prop) {
-        if (TypeOf) {
+        switch (mode) {
+          case GetNameMode::Normal:
+            return ReportIsNotDefined(cx, name);
+          case GetNameMode::TypeOf:
             vp.setUndefined();
             return true;
         }
-        return ReportIsNotDefined(cx, name);
     }
 
     /* Take the slow path if shape was not found in a native object. */
-    if (!obj->isNative() || !obj2->isNative()) {
+    if (!receiver->isNative() || !holder->isNative()) {
         Rooted<jsid> id(cx, NameToId(name));
-        if (!GetProperty(cx, obj, obj, id, vp))
+        if (!GetProperty(cx, receiver, receiver, id, vp))
             return false;
     } else {
         RootedShape shape(cx, prop.shape());
-        RootedObject normalized(cx, obj);
+        RootedObject normalized(cx, receiver);
         if (normalized->is<WithEnvironmentObject>() && !shape->hasDefaultGetter())
             normalized = &normalized->as<WithEnvironmentObject>().object();
         if (shape->isDataDescriptor() && shape->hasDefaultGetter()) {
             /* Fast path for Object instance properties. */
             MOZ_ASSERT(shape->hasSlot());
-            vp.set(obj2->as<NativeObject>().getSlot(shape->slot()));
+            vp.set(holder->as<NativeObject>().getSlot(shape->slot()));
         } else {
-            if (!NativeGetExistingProperty(cx, normalized, obj2.as<NativeObject>(), shape, vp))
+            if (!NativeGetExistingProperty(cx, normalized, holder.as<NativeObject>(), shape, vp))
                 return false;
         }
     }
 
     // We do our own explicit checking for |this|
     if (name == cx->names().dotThis)
         return true;
 
@@ -224,16 +233,39 @@ FetchNameNoGC(JSObject* pobj, PropertyRe
     Shape* shape = prop.shape();
     if (!shape->isDataDescriptor() || !shape->hasDefaultGetter())
         return false;
 
     vp.set(pobj->as<NativeObject>().getSlot(shape->slot()));
     return !IsUninitializedLexical(vp);
 }
 
+template <js::GetNameMode mode>
+inline bool
+GetEnvironmentName(JSContext* cx, HandleObject envChain, HandlePropertyName name,
+                   MutableHandleValue vp)
+{
+    {
+        PropertyResult prop;
+        JSObject* obj = nullptr;
+        JSObject* pobj = nullptr;
+        if (LookupNameNoGC(cx, name, envChain, &obj, &pobj, &prop)) {
+            if (FetchNameNoGC(pobj, prop, vp))
+                return true;
+        }
+    }
+
+    Rooted<PropertyResult> prop(cx);
+    RootedObject obj(cx), pobj(cx);
+    if (!LookupName(cx, name, envChain, &obj, &pobj, &prop))
+        return false;
+
+    return FetchName<mode>(cx, obj, pobj, name, prop, vp);
+}
+
 inline bool
 GetIntrinsicOperation(JSContext* cx, jsbytecode* pc, MutableHandleValue vp)
 {
     RootedPropertyName name(cx, cx->currentScript()->getName(pc));
     return GlobalObject::getIntrinsicValue(cx, cx->global(), name, vp);
 }
 
 inline bool
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -190,65 +190,49 @@ GetPropertyOperation(JSContext* cx, Inte
     // Copy lval, because it might alias vp.
     RootedValue v(cx, lval);
     return GetProperty(cx, v, name, vp);
 }
 
 static inline bool
 GetNameOperation(JSContext* cx, InterpreterFrame* fp, jsbytecode* pc, MutableHandleValue vp)
 {
-    JSObject* obj = fp->environmentChain();
-    PropertyName* name = fp->script()->getName(pc);
+    RootedObject envChain(cx, fp->environmentChain());
+    RootedPropertyName name(cx, fp->script()->getName(pc));
 
     /*
      * Skip along the env chain to the enclosing global object. This is
      * used for GNAME opcodes where the bytecode emitter has determined a
      * name access must be on the global. It also insulates us from bugs
      * in the emitter: type inference will assume that GNAME opcodes are
      * accessing the global object, and the inferred behavior should match
      * the actual behavior even if the id could be found on the env chain
      * before the global object.
      */
     if (IsGlobalOp(JSOp(*pc)) && !fp->script()->hasNonSyntacticScope())
-        obj = &obj->global().lexicalEnvironment();
-
-    PropertyResult prop;
-    JSObject* env = nullptr;
-    JSObject* pobj = nullptr;
-    if (LookupNameNoGC(cx, name, obj, &env, &pobj, &prop)) {
-        if (FetchNameNoGC(pobj, prop, vp))
-            return true;
-    }
-
-    RootedObject objRoot(cx, obj), envRoot(cx), pobjRoot(cx);
-    RootedPropertyName nameRoot(cx, name);
-    Rooted<PropertyResult> propRoot(cx);
-
-    if (!LookupName(cx, nameRoot, objRoot, &envRoot, &pobjRoot, &propRoot))
-        return false;
+        envChain = &envChain->global().lexicalEnvironment();
 
     /* Kludge to allow (typeof foo == "undefined") tests. */
     JSOp op2 = JSOp(pc[JSOP_GETNAME_LENGTH]);
     if (op2 == JSOP_TYPEOF)
-        return FetchName<true>(cx, envRoot, pobjRoot, nameRoot, propRoot, vp);
-
-    return FetchName<false>(cx, envRoot, pobjRoot, nameRoot, propRoot, vp);
+        return GetEnvironmentName<GetNameMode::TypeOf>(cx, envChain, name, vp);
+    return GetEnvironmentName<GetNameMode::Normal>(cx, envChain, name, vp);
 }
 
 static inline bool
 GetImportOperation(JSContext* cx, InterpreterFrame* fp, jsbytecode* pc, MutableHandleValue vp)
 {
     RootedObject obj(cx, fp->environmentChain()), env(cx), pobj(cx);
     RootedPropertyName name(cx, fp->script()->getName(pc));
     Rooted<PropertyResult> prop(cx);
 
     MOZ_ALWAYS_TRUE(LookupName(cx, name, obj, &env, &pobj, &prop));
     MOZ_ASSERT(env && env->is<ModuleEnvironmentObject>());
     MOZ_ASSERT(env->as<ModuleEnvironmentObject>().hasImportBinding(name));
-    return FetchName<false>(cx, env, pobj, name, prop, vp);
+    return FetchName<GetNameMode::Normal>(cx, env, pobj, name, prop, vp);
 }
 
 static bool
 SetPropertyOperation(JSContext* cx, JSOp op, HandleValue lval, HandleId id, HandleValue rval)
 {
     MOZ_ASSERT(op == JSOP_SETPROP || op == JSOP_STRICTSETPROP);
 
     RootedObject obj(cx, ToObjectFromStack(cx, lval));
@@ -4309,64 +4293,16 @@ js::GetProperty(JSContext* cx, HandleVal
     RootedValue receiver(cx, v);
     RootedObject obj(cx, ToObjectFromStack(cx, v));
     if (!obj)
         return false;
 
     return GetProperty(cx, obj, receiver, name, vp);
 }
 
-bool
-js::GetEnvironmentName(JSContext* cx, HandleObject envChain, HandlePropertyName name,
-                       MutableHandleValue vp)
-{
-    Rooted<PropertyResult> prop(cx);
-    RootedObject obj(cx), pobj(cx);
-    if (!LookupName(cx, name, envChain, &obj, &pobj, &prop))
-        return false;
-
-    if (!prop)
-        return ReportIsNotDefined(cx, name);
-
-    if (!GetProperty(cx, obj, obj, name, vp))
-        return false;
-
-    // We do our own explicit checking for |this|
-    if (name == cx->names().dotThis)
-        return true;
-
-    // See note in FetchName.
-    return CheckUninitializedLexical(cx, name, vp);
-}
-
-/*
- * Alternate form for NAME opcodes followed immediately by a TYPEOF,
- * which do not report an exception on (typeof foo == "undefined") tests.
- */
-bool
-js::GetEnvironmentNameForTypeOf(JSContext* cx, HandleObject envChain, HandlePropertyName name,
-                                MutableHandleValue vp)
-{
-    Rooted<PropertyResult> prop(cx);
-    RootedObject obj(cx), pobj(cx);
-    if (!LookupName(cx, name, envChain, &obj, &pobj, &prop))
-        return false;
-
-    if (!prop) {
-        vp.set(UndefinedValue());
-        return true;
-    }
-
-    if (!GetProperty(cx, obj, obj, name, vp))
-        return false;
-
-    // See note in FetchName.
-    return CheckUninitializedLexical(cx, name, vp);
-}
-
 JSObject*
 js::Lambda(JSContext* cx, HandleFunction fun, HandleObject parent)
 {
     MOZ_ASSERT(!fun->isArrow());
 
     RootedObject clone(cx, CloneFunctionObjectIfNotSingleton(cx, fun, parent));
     if (!clone)
         return nullptr;
--- a/js/src/vm/Interpreter.h
+++ b/js/src/vm/Interpreter.h
@@ -415,24 +415,16 @@ bool
 Throw(JSContext* cx, HandleValue v);
 
 bool
 ThrowingOperation(JSContext* cx, HandleValue v);
 
 bool
 GetProperty(JSContext* cx, HandleValue value, HandlePropertyName name, MutableHandleValue vp);
 
-bool
-GetEnvironmentName(JSContext* cx, HandleObject obj, HandlePropertyName name,
-                   MutableHandleValue vp);
-
-bool
-GetEnvironmentNameForTypeOf(JSContext* cx, HandleObject obj, HandlePropertyName name,
-                            MutableHandleValue vp);
-
 JSObject*
 Lambda(JSContext* cx, HandleFunction fun, HandleObject parent);
 
 JSObject*
 LambdaArrow(JSContext* cx, HandleFunction fun, HandleObject parent, HandleValue newTargetv);
 
 bool
 GetElement(JSContext* cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res);