зеркало из https://github.com/mozilla/gecko-dev.git
Bug 914314, part 2 - Factor out GetNonexistentProperty. It's nice to separate it from the main path, because everything it does except setting vp to undefined is nonstandard. No change in behavior. r=efaust.
--HG-- extra : rebase_source : 26662847e5fb0a269e54234bab4bbaebc990f558
This commit is contained in:
Родитель
1c93221207
Коммит
514b796363
|
@ -1638,6 +1638,94 @@ Detecting(JSContext *cx, JSScript *script, jsbytecode *pc)
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finish getting the property `obj[id]` after looking at every object on the
|
||||
* prototype chain and not finding any such property.
|
||||
*
|
||||
* Per the spec, this should just set the result to `undefined` and call it a
|
||||
* day. However:
|
||||
*
|
||||
* 1. We add support for the nonstandard JSClass::getProperty hook.
|
||||
*
|
||||
* 2. This function also runs when we're evaluating an expression that's an
|
||||
* Identifier (that is, unqualified name lookups), so we need to figure out
|
||||
* if that's what's happening and throw a ReferenceError if so.
|
||||
*
|
||||
* 3. We also emit an optional warning for this. (It's not super useful on the
|
||||
* web, as there are too many false positives, but anecdotally useful in
|
||||
* Gecko code.)
|
||||
*/
|
||||
static bool
|
||||
GetNonexistentProperty(JSContext *cx, HandleNativeObject obj, HandleId id,
|
||||
HandleObject receiver, MutableHandleValue vp)
|
||||
{
|
||||
vp.setUndefined();
|
||||
|
||||
// Non-standard extension: Call the getProperty class hook. It may set vp;
|
||||
// if it doesn't, fall through to the warning/error checks below.
|
||||
if (JSPropertyOp getProperty = obj->getClass()->getProperty) {
|
||||
if (!CallJSPropertyOp(cx, getProperty, obj, id, vp))
|
||||
return false;
|
||||
|
||||
if (!vp.isUndefined())
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we are doing a name lookup, this is a ReferenceError.
|
||||
jsbytecode *pc = nullptr;
|
||||
RootedScript script(cx, cx->currentScript(&pc));
|
||||
if (!pc)
|
||||
return true;
|
||||
JSOp op = (JSOp) *pc;
|
||||
if (op == JSOP_GETXPROP) {
|
||||
JSAutoByteString printable;
|
||||
if (js_ValueToPrintable(cx, IdToValue(id), &printable))
|
||||
js_ReportIsNotDefined(cx, printable.ptr());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Give a strict warning if foo.bar is evaluated by a script for an object
|
||||
// foo with no property named 'bar'.
|
||||
//
|
||||
// Don't warn if extra warnings not enabled or for random getprop
|
||||
// operations.
|
||||
if (!cx->compartment()->options().extraWarnings(cx) || (op != JSOP_GETPROP && op != JSOP_GETELEM))
|
||||
return true;
|
||||
|
||||
// Don't warn repeatedly for the same script.
|
||||
if (!script || script->warnedAboutUndefinedProp())
|
||||
return true;
|
||||
|
||||
// Don't warn in self-hosted code (where the further presence of
|
||||
// JS::RuntimeOptions::werror() would result in impossible-to-avoid
|
||||
// errors to entirely-innocent client code).
|
||||
if (script->selfHosted())
|
||||
return true;
|
||||
|
||||
// We may just be checking if that object has an iterator.
|
||||
if (JSID_IS_ATOM(id, cx->names().iteratorIntrinsic))
|
||||
return true;
|
||||
|
||||
// Do not warn about tests like (obj[prop] == undefined).
|
||||
pc += js_CodeSpec[op].length;
|
||||
if (Detecting(cx, script, pc))
|
||||
return true;
|
||||
|
||||
unsigned flags = JSREPORT_WARNING | JSREPORT_STRICT;
|
||||
script->setWarnedAboutUndefinedProp();
|
||||
|
||||
// Ok, bad undefined property reference: whine about it.
|
||||
RootedValue val(cx, IdToValue(id));
|
||||
if (!js_ReportValueErrorFlags(cx, flags, JSMSG_UNDEFINED_PROP,
|
||||
JSDVG_IGNORE_STACK, val, js::NullPtr(),
|
||||
nullptr, nullptr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
static MOZ_ALWAYS_INLINE bool
|
||||
NativeGetPropertyInline(JSContext *cx,
|
||||
|
@ -1646,7 +1734,7 @@ NativeGetPropertyInline(JSContext *cx,
|
|||
typename MaybeRooted<jsid, allowGC>::HandleType id,
|
||||
typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
|
||||
{
|
||||
/* This call site is hot -- use the always-inlined LookupPropertyInline(). */
|
||||
// This call site is hot -- use the always-inlined LookupPropertyInline().
|
||||
typename MaybeRooted<JSObject*, allowGC>::RootType obj2(cx);
|
||||
typename MaybeRooted<Shape*, allowGC>::RootType shape(cx);
|
||||
if (!LookupPropertyInline<allowGC>(cx, obj, id, &obj2, &shape))
|
||||
|
@ -1656,75 +1744,11 @@ NativeGetPropertyInline(JSContext *cx,
|
|||
if (!allowGC)
|
||||
return false;
|
||||
|
||||
vp.setUndefined();
|
||||
|
||||
if (JSPropertyOp getProperty = obj->getClass()->getProperty) {
|
||||
if (!CallJSPropertyOp(cx, getProperty,
|
||||
MaybeRooted<JSObject*, allowGC>::toHandle(obj),
|
||||
return GetNonexistentProperty(cx,
|
||||
MaybeRooted<NativeObject*, allowGC>::toHandle(obj),
|
||||
MaybeRooted<jsid, allowGC>::toHandle(id),
|
||||
MaybeRooted<Value, allowGC>::toMutableHandle(vp)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Give a strict warning if foo.bar is evaluated by a script for an
|
||||
* object foo with no property named 'bar'.
|
||||
*/
|
||||
if (vp.isUndefined()) {
|
||||
jsbytecode *pc = nullptr;
|
||||
RootedScript script(cx, cx->currentScript(&pc));
|
||||
if (!pc)
|
||||
return true;
|
||||
JSOp op = (JSOp) *pc;
|
||||
|
||||
if (op == JSOP_GETXPROP) {
|
||||
/* Undefined property during a name lookup, report an error. */
|
||||
JSAutoByteString printable;
|
||||
if (js_ValueToPrintable(cx, IdToValue(id), &printable))
|
||||
js_ReportIsNotDefined(cx, printable.ptr());
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Don't warn if extra warnings not enabled or for random getprop operations. */
|
||||
if (!cx->compartment()->options().extraWarnings(cx) || (op != JSOP_GETPROP && op != JSOP_GETELEM))
|
||||
return true;
|
||||
|
||||
/* Don't warn repeatedly for the same script. */
|
||||
if (!script || script->warnedAboutUndefinedProp())
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Don't warn in self-hosted code (where the further presence of
|
||||
* JS::RuntimeOptions::werror() would result in impossible-to-avoid
|
||||
* errors to entirely-innocent client code).
|
||||
*/
|
||||
if (script->selfHosted())
|
||||
return true;
|
||||
|
||||
/* We may just be checking if that object has an iterator. */
|
||||
if (JSID_IS_ATOM(id, cx->names().iteratorIntrinsic))
|
||||
return true;
|
||||
|
||||
/* Do not warn about tests like (obj[prop] == undefined). */
|
||||
pc += js_CodeSpec[op].length;
|
||||
if (Detecting(cx, script, pc))
|
||||
return true;
|
||||
|
||||
unsigned flags = JSREPORT_WARNING | JSREPORT_STRICT;
|
||||
script->setWarnedAboutUndefinedProp();
|
||||
|
||||
/* Ok, bad undefined property reference: whine about it. */
|
||||
RootedValue val(cx, IdToValue(id));
|
||||
if (!js_ReportValueErrorFlags(cx, flags, JSMSG_UNDEFINED_PROP,
|
||||
JSDVG_IGNORE_STACK, val, js::NullPtr(),
|
||||
nullptr, nullptr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
MaybeRooted<JSObject*, allowGC>::toHandle(receiver),
|
||||
MaybeRooted<Value, allowGC>::toMutableHandle(vp));
|
||||
}
|
||||
|
||||
if (!obj2->isNative()) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче