Bug 887016 - Part 8: Add ObjectHasPrototype. r=nbp

This commit is contained in:
Tooru Fujisawa 2016-01-27 23:43:04 +09:00
Родитель 1b4d64f711
Коммит 877fae40b2
5 изменённых файлов: 138 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,63 @@
setJitCompilerOption("ion.warmup.trigger", 4);
var ObjectHasPrototype = getSelfHostedValue("ObjectHasPrototype");
var StringProto = String.prototype;
var ObjectProto = Object.prototype;
function testBasic() {
var f = function() {
assertEq(ObjectHasPrototype(StringProto, ObjectProto), true);
};
for (var i = 0; i < 40; i++) {
f();
}
}
testBasic();
function testProtoChange(proto) {
var f = function(expected) {
assertEq(ObjectHasPrototype(StringProto, ObjectProto), expected);
};
var expected = true;
for (var i = 0; i < 120; i++) {
f(expected);
if (i == 40) {
Object.setPrototypeOf(StringProto, proto);
expected = false;
}
if (i == 80) {
Object.setPrototypeOf(StringProto, ObjectProto);
expected = true;
}
}
}
testProtoChange(null);
// Different singleton
testProtoChange(Function.prototype);
// native non-singleton
testProtoChange(/a/);
// non-native non-singleton
testProtoChange({});
var Int32ArrayProto = Int32Array.prototype;
var TypedArrayProto = Object.getPrototypeOf(Int32ArrayProto);
function testProtoProtoChange(proto) {
var f = function() {
assertEq(ObjectHasPrototype(Int32ArrayProto, TypedArrayProto), true);
};
for (var i = 0; i < 120; i++) {
f();
if (i == 40)
Object.setPrototypeOf(TypedArrayProto, proto);
if (i == 80)
Object.setPrototypeOf(TypedArrayProto, Object);
}
}
testProtoProtoChange(null);
// Different singleton
testProtoProtoChange(Function.prototype);
// native non-singleton
testProtoProtoChange(/a/);
// non-native non-singleton
testProtoProtoChange({});

Просмотреть файл

@ -106,6 +106,7 @@
_(IntrinsicIsConstructing) \
_(IntrinsicSubstringKernel) \
_(IntrinsicDefineDataProperty) \
_(IntrinsicObjectHasPrototype) \
\
_(IntrinsicIsArrayIterator) \
_(IntrinsicIsMapIterator) \

Просмотреть файл

@ -922,6 +922,7 @@ class IonBuilder
const Class* clasp4 = nullptr);
InliningStatus inlineIsConstructing(CallInfo& callInfo);
InliningStatus inlineSubstringKernel(CallInfo& callInfo);
InliningStatus inlineObjectHasPrototype(CallInfo& callInfo);
// Testing functions.
InliningStatus inlineBailout(CallInfo& callInfo);

Просмотреть файл

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jsmath.h"
#include "jsobj.h"
#include "jsstr.h"
#include "builtin/AtomicsObject.h"
@ -266,6 +267,8 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target)
return inlineHasClass(callInfo, &ListIteratorObject::class_);
case InlinableNative::IntrinsicDefineDataProperty:
return inlineDefineDataProperty(callInfo);
case InlinableNative::IntrinsicObjectHasPrototype:
return inlineObjectHasPrototype(callInfo);
// Map intrinsics.
case InlinableNative::IntrinsicGetNextMapEntryForIterator:
@ -1613,6 +1616,58 @@ IonBuilder::inlineStringSplit(CallInfo& callInfo)
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineObjectHasPrototype(CallInfo& callInfo)
{
if (callInfo.argc() != 2 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
MDefinition* objArg = callInfo.getArg(0);
MDefinition* protoArg = callInfo.getArg(1);
if (objArg->type() != MIRType_Object)
return InliningStatus_NotInlined;
if (protoArg->type() != MIRType_Object)
return InliningStatus_NotInlined;
// Inline only when both obj and proto are singleton objects and
// obj does not have uncacheable proto and obj.__proto__ is proto.
TemporaryTypeSet* objTypes = objArg->resultTypeSet();
if (!objTypes || objTypes->unknownObject() || objTypes->getObjectCount() != 1)
return InliningStatus_NotInlined;
TypeSet::ObjectKey* objKey = objTypes->getObject(0);
if (!objKey || !objKey->hasStableClassAndProto(constraints()))
return InliningStatus_NotInlined;
if (!objKey->isSingleton() || !objKey->singleton()->is<NativeObject>())
return InliningStatus_NotInlined;
JSObject* obj = &objKey->singleton()->as<NativeObject>();
if (obj->hasUncacheableProto())
return InliningStatus_NotInlined;
JSObject* actualProto = checkNurseryObject(objKey->proto().toObjectOrNull());
if (actualProto == nullptr)
return InliningStatus_NotInlined;
TemporaryTypeSet* protoTypes = protoArg->resultTypeSet();
if (!protoTypes || protoTypes->unknownObject() || protoTypes->getObjectCount() != 1)
return InliningStatus_NotInlined;
TypeSet::ObjectKey* protoKey = protoTypes->getObject(0);
if (!protoKey || !protoKey->hasStableClassAndProto(constraints()))
return InliningStatus_NotInlined;
if (!protoKey->isSingleton() || !protoKey->singleton()->is<NativeObject>())
return InliningStatus_NotInlined;
JSObject* proto = &protoKey->singleton()->as<NativeObject>();
pushConstant(BooleanValue(proto == actualProto));
callInfo.setImplicitlyUsedUnchecked();
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineStrCharCodeAt(CallInfo& callInfo)
{

Просмотреть файл

@ -585,6 +585,22 @@ intrinsic_DefineDataProperty(JSContext* cx, unsigned argc, Value* vp)
return true;
}
static bool
intrinsic_ObjectHasPrototype(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2);
RootedObject obj(cx, &args[0].toObject());
RootedObject proto(cx, &args[1].toObject());
RootedObject actualProto(cx);
if (!GetPrototype(cx, obj, &actualProto))
return false;
args.rval().setBoolean(actualProto == proto);
return true;
}
static bool
intrinsic_UnsafeSetReservedSlot(JSContext* cx, unsigned argc, Value* vp)
{
@ -2175,6 +2191,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
IntrinsicSubstringKernel),
JS_INLINABLE_FN("_DefineDataProperty", intrinsic_DefineDataProperty, 4,0,
IntrinsicDefineDataProperty),
JS_INLINABLE_FN("ObjectHasPrototype", intrinsic_ObjectHasPrototype, 2,0,
IntrinsicObjectHasPrototype),
JS_INLINABLE_FN("UnsafeSetReservedSlot", intrinsic_UnsafeSetReservedSlot, 3,0,
IntrinsicUnsafeSetReservedSlot),
JS_INLINABLE_FN("UnsafeGetReservedSlot", intrinsic_UnsafeGetReservedSlot, 2,0,