author | Tooru Fujisawa <arai_a@mac.com> |
Wed, 27 Jan 2016 23:43:04 +0900 | |
changeset 292174 | ac74c5fe92172d8dbb363eb713e1512570c51af1 |
parent 292173 | 741c4be20f025d1b24b5fcab5b7987bd649bdd0b |
child 292175 | b5b06959919ad3a0150c7ca1dfe0de7d2d9df7e1 |
push id | 74764 |
push user | arai_a@mac.com |
push date | Thu, 07 Apr 2016 10:49:15 +0000 |
treeherder | mozilla-inbound@4d0f975a2311 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | nbp |
bugs | 887016 |
milestone | 48.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/ion/testObjectHasPrototype.js @@ -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({});
--- a/js/src/jit/InlinableNatives.h +++ b/js/src/jit/InlinableNatives.h @@ -100,16 +100,17 @@ _(IntrinsicToObject) \ _(IntrinsicIsObject) \ _(IntrinsicIsWrappedArrayConstructor) \ _(IntrinsicToInteger) \ _(IntrinsicToString) \ _(IntrinsicIsConstructing) \ _(IntrinsicSubstringKernel) \ _(IntrinsicDefineDataProperty) \ + _(IntrinsicObjectHasPrototype) \ \ _(IntrinsicIsArrayIterator) \ _(IntrinsicIsMapIterator) \ _(IntrinsicIsStringIterator) \ _(IntrinsicIsListIterator) \ \ _(IntrinsicGetNextMapEntryForIterator) \ \
--- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -916,16 +916,17 @@ class IonBuilder InliningStatus inlineToString(CallInfo& callInfo); InliningStatus inlineDump(CallInfo& callInfo); InliningStatus inlineHasClass(CallInfo& callInfo, const Class* clasp, const Class* clasp2 = nullptr, const Class* clasp3 = nullptr, const Class* clasp4 = nullptr); InliningStatus inlineIsConstructing(CallInfo& callInfo); InliningStatus inlineSubstringKernel(CallInfo& callInfo); + InliningStatus inlineObjectHasPrototype(CallInfo& callInfo); // Testing functions. InliningStatus inlineBailout(CallInfo& callInfo); InliningStatus inlineAssertFloat32(CallInfo& callInfo); InliningStatus inlineAssertRecoveredOnBailout(CallInfo& callInfo); // Bind function. InliningStatus inlineBoundFunction(CallInfo& callInfo, JSFunction* target);
--- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -1,15 +1,16 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * 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" #include "builtin/SIMD.h" #include "builtin/TestingFunctions.h" #include "builtin/TypedObject.h" #include "jit/BaselineInspector.h" #include "jit/InlinableNatives.h" @@ -259,16 +260,18 @@ IonBuilder::inlineNativeCall(CallInfo& c case InlinableNative::IntrinsicIsMapIterator: return inlineHasClass(callInfo, &MapIteratorObject::class_); case InlinableNative::IntrinsicIsStringIterator: return inlineHasClass(callInfo, &StringIteratorObject::class_); case InlinableNative::IntrinsicIsListIterator: return inlineHasClass(callInfo, &ListIteratorObject::class_); case InlinableNative::IntrinsicDefineDataProperty: return inlineDefineDataProperty(callInfo); + case InlinableNative::IntrinsicObjectHasPrototype: + return inlineObjectHasPrototype(callInfo); // Map intrinsics. case InlinableNative::IntrinsicGetNextMapEntryForIterator: return inlineGetNextMapEntryForIterator(callInfo); // ArrayBuffer intrinsics. case InlinableNative::IntrinsicArrayBufferByteLength: return inlineArrayBufferByteLength(callInfo); @@ -1607,16 +1610,68 @@ IonBuilder::inlineStringSplit(CallInfo& callInfo.getArg(0), templateObjectDef); current->add(ins); current->push(ins); 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) { if (callInfo.argc() != 1 || callInfo.constructing()) { trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm); return InliningStatus_NotInlined; } if (getInlineReturnType() != MIRType_Int32)
--- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -581,16 +581,32 @@ intrinsic_DefineDataProperty(JSContext* if (!DefineProperty(cx, obj, id, desc)) return false; args.rval().setUndefined(); 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) { CallArgs args = CallArgsFromVp(argc, vp); MOZ_ASSERT(args.length() == 3); MOZ_ASSERT(args[0].isObject()); MOZ_ASSERT(args[1].isInt32()); args[0].toObject().as<NativeObject>().setReservedSlot(args[1].toPrivateUint32(), args[2]); @@ -2170,16 +2186,18 @@ static const JSFunctionSpec intrinsic_fu JS_FN("AddContentTelemetry", intrinsic_AddContentTelemetry, 2,0), JS_INLINABLE_FN("_IsConstructing", intrinsic_IsConstructing, 0,0, IntrinsicIsConstructing), JS_INLINABLE_FN("SubstringKernel", intrinsic_SubstringKernel, 3,0, 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, IntrinsicUnsafeGetReservedSlot), JS_INLINABLE_FN("UnsafeGetObjectFromReservedSlot", intrinsic_UnsafeGetObjectFromReservedSlot, 2,0, IntrinsicUnsafeGetObjectFromReservedSlot), JS_INLINABLE_FN("UnsafeGetInt32FromReservedSlot", intrinsic_UnsafeGetInt32FromReservedSlot, 2,0, IntrinsicUnsafeGetInt32FromReservedSlot),