mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Bug 822340. Make the Ion optimization for DOM method calls sound. r=jandem
The static functions just got moved with no changes made to them except for a change from inTypes->unknown() to inTypes->unknownObject() in the first test in TestAreKnownDOMTypes, becase the rest of the method depends on the stronger condition, and it was being ensured accidentally before.
This commit is contained in:
parent
51f20b1833
commit
4d4f84e2ba
11
dom/bindings/crashtests/822340-1.html
Normal file
11
dom/bindings/crashtests/822340-1.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
var xhr = new XMLHttpRequest;
|
||||
function f() {
|
||||
var x = xhr.getResponseHeader;
|
||||
x("abc");
|
||||
}
|
||||
for (var i = 0; i < 20000; ++i) {
|
||||
try { f(); } catch (e) {}
|
||||
}
|
||||
</script>
|
8
dom/bindings/crashtests/822340-2.html
Normal file
8
dom/bindings/crashtests/822340-2.html
Normal file
@ -0,0 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
var l = document.getElementsByTagName("*");
|
||||
var count = 20000;
|
||||
for (var i = 0; i < count; ++i) {
|
||||
l.item(0);
|
||||
}
|
||||
</script>
|
@ -1 +1,3 @@
|
||||
asserts-if(cocoaWidget,0-1) load 769464.html
|
||||
load 822340-1.html
|
||||
load 822340-2.html
|
||||
|
@ -4109,6 +4109,103 @@ IonBuilder::jsop_call(uint32_t argc, bool constructing)
|
||||
return makeCallBarrier(target, argc, constructing, types, barrier);
|
||||
}
|
||||
|
||||
static bool
|
||||
TestShouldDOMCall(JSContext *cx, types::TypeSet *inTypes, HandleFunction func,
|
||||
JSJitInfo::OpType opType)
|
||||
{
|
||||
if (!func->isNative() || !func->jitInfo())
|
||||
return false;
|
||||
// If all the DOM objects flowing through are legal with this
|
||||
// property, we can bake in a call to the bottom half of the DOM
|
||||
// accessor
|
||||
DOMInstanceClassMatchesProto instanceChecker =
|
||||
GetDOMCallbacks(cx->runtime)->instanceClassMatchesProto;
|
||||
|
||||
const JSJitInfo *jinfo = func->jitInfo();
|
||||
if (jinfo->type != opType)
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < inTypes->getObjectCount(); i++) {
|
||||
types::TypeObject *curType = inTypes->getTypeObject(i);
|
||||
|
||||
if (!curType) {
|
||||
JSObject *curObj = inTypes->getSingleObject(i);
|
||||
|
||||
if (!curObj)
|
||||
continue;
|
||||
|
||||
curType = curObj->getType(cx);
|
||||
}
|
||||
|
||||
JSObject *typeProto = curType->proto;
|
||||
RootedObject proto(cx, typeProto);
|
||||
if (!instanceChecker(proto, jinfo->protoID, jinfo->depth))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
TestAreKnownDOMTypes(JSContext *cx, types::TypeSet *inTypes)
|
||||
{
|
||||
if (inTypes->unknownObject())
|
||||
return false;
|
||||
|
||||
// First iterate to make sure they all are DOM objects, then freeze all of
|
||||
// them as such if they are.
|
||||
for (unsigned i = 0; i < inTypes->getObjectCount(); i++) {
|
||||
types::TypeObject *curType = inTypes->getTypeObject(i);
|
||||
|
||||
if (!curType) {
|
||||
JSObject *curObj = inTypes->getSingleObject(i);
|
||||
|
||||
// Skip holes in TypeSets.
|
||||
if (!curObj)
|
||||
continue;
|
||||
|
||||
curType = curObj->getType(cx);
|
||||
}
|
||||
|
||||
if (curType->unknownProperties())
|
||||
return false;
|
||||
|
||||
// Unlike TypeSet::HasObjectFlags, TypeObject::hasAnyFlags doesn't add a
|
||||
// freeze.
|
||||
if (curType->hasAnyFlags(types::OBJECT_FLAG_NON_DOM))
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we didn't check anything, no reason to say yes.
|
||||
if (inTypes->getObjectCount() > 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
FreezeDOMTypes(JSContext *cx, types::StackTypeSet *inTypes)
|
||||
{
|
||||
for (unsigned i = 0; i < inTypes->getObjectCount(); i++) {
|
||||
types::TypeObject *curType = inTypes->getTypeObject(i);
|
||||
|
||||
if (!curType) {
|
||||
JSObject *curObj = inTypes->getSingleObject(i);
|
||||
|
||||
// Skip holes in TypeSets.
|
||||
if (!curObj)
|
||||
continue;
|
||||
|
||||
curType = curObj->getType(cx);
|
||||
}
|
||||
|
||||
// Add freeze by asking the question.
|
||||
DebugOnly<bool> wasntDOM =
|
||||
types::HeapTypeSet::HasObjectFlags(cx, curType, types::OBJECT_FLAG_NON_DOM);
|
||||
JS_ASSERT(!wasntDOM);
|
||||
}
|
||||
}
|
||||
|
||||
MCall *
|
||||
IonBuilder::makeCallHelper(HandleFunction target, uint32_t argc, bool constructing)
|
||||
{
|
||||
@ -4170,9 +4267,20 @@ IonBuilder::makeCallHelper(HandleFunction target, uint32_t argc, bool constructi
|
||||
// Pass |this| and function.
|
||||
call->addArg(0, thisArg);
|
||||
|
||||
if (target && JSOp(*pc) == JSOP_CALL) {
|
||||
// We know we have a single call target. Check whether the "this" types
|
||||
// are DOM types and our function a DOM function, and if so flag the
|
||||
// MCall accordingly.
|
||||
types::StackTypeSet *thisTypes = oracle->getCallArg(script(), argc, 0, pc);
|
||||
if (thisTypes &&
|
||||
TestAreKnownDOMTypes(cx, thisTypes) &&
|
||||
TestShouldDOMCall(cx, thisTypes, target, JSJitInfo::Method))
|
||||
{
|
||||
FreezeDOMTypes(cx, thisTypes);
|
||||
call->setDOMFunction();
|
||||
}
|
||||
}
|
||||
MDefinition *fun = current->pop();
|
||||
if (fun->isDOMFunction())
|
||||
call->setDOMFunction();
|
||||
call->initFunction(fun);
|
||||
|
||||
current->add(call);
|
||||
@ -5950,103 +6058,6 @@ IonBuilder::TestCommonPropFunc(JSContext *cx, types::StackTypeSet *types, Handle
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
TestShouldDOMCall(JSContext *cx, types::TypeSet *inTypes, HandleFunction func,
|
||||
JSJitInfo::OpType opType)
|
||||
{
|
||||
if (!func->isNative() || !func->jitInfo())
|
||||
return false;
|
||||
// If all the DOM objects flowing through are legal with this
|
||||
// property, we can bake in a call to the bottom half of the DOM
|
||||
// accessor
|
||||
DOMInstanceClassMatchesProto instanceChecker =
|
||||
GetDOMCallbacks(cx->runtime)->instanceClassMatchesProto;
|
||||
|
||||
const JSJitInfo *jinfo = func->jitInfo();
|
||||
if (jinfo->type != opType)
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < inTypes->getObjectCount(); i++) {
|
||||
types::TypeObject *curType = inTypes->getTypeObject(i);
|
||||
|
||||
if (!curType) {
|
||||
JSObject *curObj = inTypes->getSingleObject(i);
|
||||
|
||||
if (!curObj)
|
||||
continue;
|
||||
|
||||
curType = curObj->getType(cx);
|
||||
}
|
||||
|
||||
JSObject *typeProto = curType->proto;
|
||||
RootedObject proto(cx, typeProto);
|
||||
if (!instanceChecker(proto, jinfo->protoID, jinfo->depth))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
TestAreKnownDOMTypes(JSContext *cx, types::TypeSet *inTypes)
|
||||
{
|
||||
if (inTypes->unknown())
|
||||
return false;
|
||||
|
||||
// First iterate to make sure they all are DOM objects, then freeze all of
|
||||
// them as such if they are.
|
||||
for (unsigned i = 0; i < inTypes->getObjectCount(); i++) {
|
||||
types::TypeObject *curType = inTypes->getTypeObject(i);
|
||||
|
||||
if (!curType) {
|
||||
JSObject *curObj = inTypes->getSingleObject(i);
|
||||
|
||||
// Skip holes in TypeSets.
|
||||
if (!curObj)
|
||||
continue;
|
||||
|
||||
curType = curObj->getType(cx);
|
||||
}
|
||||
|
||||
if (curType->unknownProperties())
|
||||
return false;
|
||||
|
||||
// Unlike TypeSet::HasObjectFlags, TypeObject::hasAnyFlags doesn't add a
|
||||
// freeze.
|
||||
if (curType->hasAnyFlags(types::OBJECT_FLAG_NON_DOM))
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we didn't check anything, no reason to say yes.
|
||||
if (inTypes->getObjectCount() > 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
FreezeDOMTypes(JSContext *cx, types::StackTypeSet *inTypes)
|
||||
{
|
||||
for (unsigned i = 0; i < inTypes->getObjectCount(); i++) {
|
||||
types::TypeObject *curType = inTypes->getTypeObject(i);
|
||||
|
||||
if (!curType) {
|
||||
JSObject *curObj = inTypes->getSingleObject(i);
|
||||
|
||||
// Skip holes in TypeSets.
|
||||
if (!curObj)
|
||||
continue;
|
||||
|
||||
curType = curObj->getType(cx);
|
||||
}
|
||||
|
||||
// Add freeze by asking the question.
|
||||
DebugOnly<bool> wasntDOM =
|
||||
types::HeapTypeSet::HasObjectFlags(cx, curType, types::OBJECT_FLAG_NON_DOM);
|
||||
JS_ASSERT(!wasntDOM);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::annotateGetPropertyCache(JSContext *cx, MDefinition *obj, MGetPropertyCache *getPropCache,
|
||||
types::StackTypeSet *objTypes, types::StackTypeSet *pushedTypes)
|
||||
@ -6311,15 +6322,6 @@ IonBuilder::getPropTryConstant(bool *emitted, HandleId id, types::StackTypeSet *
|
||||
obj->setFoldedUnchecked();
|
||||
|
||||
MConstant *known = MConstant::New(ObjectValue(*singleton));
|
||||
if (singleton->isFunction()) {
|
||||
RootedFunction singletonFunc(cx, singleton->toFunction());
|
||||
if (TestAreKnownDOMTypes(cx, unaryTypes.inTypes) &&
|
||||
TestShouldDOMCall(cx, unaryTypes.inTypes, singletonFunc, JSJitInfo::Method))
|
||||
{
|
||||
FreezeDOMTypes(cx, unaryTypes.inTypes);
|
||||
known->setDOMFunction();
|
||||
}
|
||||
}
|
||||
|
||||
current->add(known);
|
||||
current->push(known);
|
||||
|
Loading…
Reference in New Issue
Block a user