Bug 936056. Be consistent about the thisobj we pass to getters. r=jorendorff

This commit is contained in:
Boris Zbarsky 2013-12-02 19:08:07 -05:00
parent 0a5214b4b6
commit cca591c20a
5 changed files with 94 additions and 8 deletions

View File

@ -16,6 +16,7 @@ support-files =
[test_bug788369.html]
[test_bug852846.html]
[test_bug862092.html]
[test_barewordGetsWindow.html]
[test_cloneAndImportNode.html]
[test_defineProperty.html]
[test_enums.html]

View File

@ -0,0 +1,60 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=936056
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 936056</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Bug 936056 **/
SimpleTest.waitForExplicitFinish();
window.onload = function() {
var desc = Object.getOwnPropertyDescriptor(frames[0], "document");
if (!desc || !desc.get) {
todo(false, "This test does nothing so far, but will once Window is on WebIDL bindings");
SimpleTest.finish();
return;
}
get = desc.get;
ok(get, "Couldn't find document getter");
Object.defineProperty(frames[0], "foo", { get: get });
var barewordFunc = frames[0].eval("(function (count) { var doc; for (var i = 0; i < count; ++i) doc = foo; return doc.documentElement; })");
var qualifiedFunc = frames[0].eval("(function (count) { var doc; for (var i = 0; i < count; ++i) doc = window.document; return doc.documentElement; })");
document.querySelector("iframe").onload = function () {
// interp
is(barewordFunc(1).textContent, "OLD", "Bareword should see own inner 1");
is(qualifiedFunc(1).textContent, "NEW",
"Qualified should see current inner 1");
// baseline
is(barewordFunc(100).textContent, "OLD", "Bareword should see own inner 2");
is(qualifiedFunc(100).textContent, "NEW",
"Qualified should see current inner 2");
// ion
is(barewordFunc(10000).textContent, "OLD", "Bareword should see own inner 3");
is(qualifiedFunc(10000).textContent, "NEW",
"Qualified should see current inner 2");
SimpleTest.finish();
}
frames[0].location = "data:text/plain,NEW";
}
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=936056">Mozilla Bug 936056</a>
<p id="display"></p>
<div id="content" style="display: none">
<iframe src="data:text/plain,OLD"></iframe>
</div>
<pre id="test">
</pre>
</body>
</html>

View File

@ -611,8 +611,19 @@ IsCacheableGetPropCallNative(JSObject *obj, JSObject *holder, Shape *shape)
if (!shape->hasGetterValue() || !shape->getterValue().isObject())
return false;
return shape->getterValue().toObject().is<JSFunction>() &&
shape->getterValue().toObject().as<JSFunction>().isNative();
if (!shape->getterValue().toObject().is<JSFunction>())
return false;
JSFunction& getter = shape->getterValue().toObject().as<JSFunction>();
if (!getter.isNative())
return false;
// Check for a DOM method; those are OK with both inner and outer objects.
if (getter.jitInfo())
return true;
// For non-DOM methods, don't cache if obj has an outerObject hook.
return !obj->getClass()->ext.outerObject;
}
static bool

View File

@ -1496,6 +1496,11 @@ struct JSJitInfo {
AliasEverything
};
bool isDOMJitInfo() const
{
return type != OpType_None;
}
union {
JSJitGetterOp getter;
JSJitSetterOp setter;
@ -1504,6 +1509,9 @@ struct JSJitInfo {
uint32_t protoID;
uint32_t depth;
// type not being OpType_None means this is a DOM method. If you
// change that, come up with a different way of implementing
// isDOMJitInfo().
OpType type;
bool isInfallible; /* Is op fallible? False in setters. */
bool isMovable; /* Is op movable? To be movable the op must not

View File

@ -501,13 +501,19 @@ js::Invoke(JSContext *cx, const Value &thisv, const Value &fval, unsigned argc,
/*
* We must call the thisObject hook in case we are not called from the
* interpreter, where a prior bytecode has computed an appropriate
* |this| already.
* |this| already. But don't do that if fval is a DOM function.
*/
RootedObject thisObj(cx, &args.thisv().toObject());
JSObject *thisp = JSObject::thisObject(cx, thisObj);
if (!thisp)
return false;
args.setThis(ObjectValue(*thisp));
if (!fval.isObject() || !fval.toObject().is<JSFunction>() ||
!fval.toObject().as<JSFunction>().isNative() ||
!fval.toObject().as<JSFunction>().jitInfo() ||
!fval.toObject().as<JSFunction>().jitInfo()->isDOMJitInfo())
{
RootedObject thisObj(cx, &args.thisv().toObject());
JSObject *thisp = JSObject::thisObject(cx, thisObj);
if (!thisp)
return false;
args.setThis(ObjectValue(*thisp));
}
}
if (!Invoke(cx, args))