--- 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 (!GetEnvironmentName<GetNameMode::TypeOf>(cx, envChain, name, res))
+ if (!GetEnvironmentNameForTypeOf(cx, envChain, name, res))
return false;
} else {
- if (!GetEnvironmentName<GetNameMode::Normal>(cx, envChain, name, res))
+ if (!GetEnvironmentName(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<GetNameMode::TypeOf>(cx, obj, holder, name, prop, vp))
+ if (!FetchName<true>(cx, obj, holder, name, prop, vp))
return false;
} else {
- if (!FetchName<GetNameMode::Normal>(cx, obj, holder, name, prop, vp))
+ if (!FetchName<false>(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,53 +169,44 @@ GetLengthProperty(const Value& lval, Mut
return true;
}
}
}
return false;
}
-enum class GetNameMode
-{
- Normal,
- TypeOf
-};
-
-template <GetNameMode mode>
-inline bool
-FetchName(JSContext* cx, HandleObject receiver, HandleObject holder, HandlePropertyName name,
+template <bool TypeOf> inline bool
+FetchName(JSContext* cx, HandleObject obj, HandleObject obj2, HandlePropertyName name,
Handle<PropertyResult> prop, MutableHandleValue vp)
{
if (!prop) {
- switch (mode) {
- case GetNameMode::Normal:
- return ReportIsNotDefined(cx, name);
- case GetNameMode::TypeOf:
+ if (TypeOf) {
vp.setUndefined();
return true;
}
+ return ReportIsNotDefined(cx, name);
}
/* Take the slow path if shape was not found in a native object. */
- if (!receiver->isNative() || !holder->isNative()) {
+ if (!obj->isNative() || !obj2->isNative()) {
Rooted<jsid> id(cx, NameToId(name));
- if (!GetProperty(cx, receiver, receiver, id, vp))
+ if (!GetProperty(cx, obj, obj, id, vp))
return false;
} else {
RootedShape shape(cx, prop.shape());
- RootedObject normalized(cx, receiver);
+ RootedObject normalized(cx, obj);
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(holder->as<NativeObject>().getSlot(shape->slot()));
+ vp.set(obj2->as<NativeObject>().getSlot(shape->slot()));
} else {
- if (!NativeGetExistingProperty(cx, normalized, holder.as<NativeObject>(), shape, vp))
+ if (!NativeGetExistingProperty(cx, normalized, obj2.as<NativeObject>(), shape, vp))
return false;
}
}
// We do our own explicit checking for |this|
if (name == cx->names().dotThis)
return true;
@@ -233,39 +224,16 @@ 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,49 +190,65 @@ 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)
{
- RootedObject envChain(cx, fp->environmentChain());
- RootedPropertyName name(cx, fp->script()->getName(pc));
+ JSObject* obj = fp->environmentChain();
+ PropertyName* name = 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())
- envChain = &envChain->global().lexicalEnvironment();
+ 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;
/* Kludge to allow (typeof foo == "undefined") tests. */
JSOp op2 = JSOp(pc[JSOP_GETNAME_LENGTH]);
if (op2 == JSOP_TYPEOF)
- return GetEnvironmentName<GetNameMode::TypeOf>(cx, envChain, name, vp);
- return GetEnvironmentName<GetNameMode::Normal>(cx, envChain, name, vp);
+ return FetchName<true>(cx, envRoot, pobjRoot, nameRoot, propRoot, vp);
+
+ return FetchName<false>(cx, envRoot, pobjRoot, nameRoot, propRoot, 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<GetNameMode::Normal>(cx, env, pobj, name, prop, vp);
+ return FetchName<false>(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));
@@ -4293,16 +4309,64 @@ 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,16 +415,24 @@ 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);