Bug 1165053 - Part 0.2: Inline PossiblyWrappedArrayBufferByteLength self-hosting intrinsic. r=jwalden
☠☠ backed out by 5e115ad804f5 ☠ ☠
authorTooru Fujisawa <arai_a@mac.com>
Sat, 05 Mar 2016 18:56:36 +0900
changeset 290593 fffa0e5cc40628fcb7848dff1fe8c8c7605e9bc7
parent 290592 63d6812ce8ccc5968bb0a5359a5ac9052fc87e48
child 290594 f3195319f23d49c8f91b2edfe2b549a470d386db
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs1165053
milestone48.0a1
Bug 1165053 - Part 0.2: Inline PossiblyWrappedArrayBufferByteLength self-hosting intrinsic. r=jwalden
js/src/jit-test/tests/ion/testPossiblyWrappedArrayBufferByteLength.js
js/src/jit/InlinableNatives.h
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
js/src/jit/MCallOptimize.cpp
js/src/vm/SelfHosting.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/testPossiblyWrappedArrayBufferByteLength.js
@@ -0,0 +1,41 @@
+var PossiblyWrappedArrayBufferByteLength = getSelfHostedValue("PossiblyWrappedArrayBufferByteLength");
+
+setJitCompilerOption("ion.warmup.trigger", 50);
+
+function testBasic() {
+  var arr = [1, 2, 3];
+  var tarr = new Int32Array(arr);
+  var abuf = tarr.buffer;
+
+  var arrLength = arr.length;
+  var bytesPerElement = Int32Array.BYTES_PER_ELEMENT;
+
+  var f = function() {
+    assertEq(PossiblyWrappedArrayBufferByteLength(abuf), arrLength * bytesPerElement);
+  };
+  do {
+    f();
+  } while (!inIon());
+}
+testBasic();
+
+function testWrapped() {
+  var g = newGlobal();
+g.eval(`
+var arr = [1, 2, 3];
+var tarr = new Int32Array(arr);
+var abuf = tarr.buffer;
+`);
+
+  var abuf = g.abuf;
+  var arrLength = g.arr.length;
+  var bytesPerElement = g.Int32Array.BYTES_PER_ELEMENT;
+
+  var f = function() {
+    assertEq(PossiblyWrappedArrayBufferByteLength(abuf), arrLength * bytesPerElement);
+  };
+  do {
+    f();
+  } while (!inIon());
+}
+testWrapped();
--- a/js/src/jit/InlinableNatives.h
+++ b/js/src/jit/InlinableNatives.h
@@ -106,16 +106,18 @@
                                     \
     _(IntrinsicIsArrayIterator)     \
     _(IntrinsicIsMapIterator)       \
     _(IntrinsicIsStringIterator)    \
     _(IntrinsicIsListIterator)      \
                                     \
     _(IntrinsicGetNextMapEntryForIterator) \
                                     \
+    _(IntrinsicPossiblyWrappedArrayBufferByteLength) \
+                                    \
     _(IntrinsicIsTypedArray)        \
     _(IntrinsicIsPossiblyWrappedTypedArray) \
     _(IntrinsicTypedArrayLength)    \
     _(IntrinsicPossiblyWrappedTypedArrayLength)    \
     _(IntrinsicSetDisjointTypedElements) \
                                     \
     _(IntrinsicObjectIsTypedObject) \
     _(IntrinsicObjectIsTransparentTypedObject) \
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -9495,16 +9495,25 @@ IonBuilder::jsop_getelem_dense(MDefiniti
         load->setResultType(knownType);
         load->setResultTypeSet(types);
     }
 
     current->push(load);
     return pushTypeBarrier(load, types, barrier);
 }
 
+MInstruction*
+IonBuilder::addArrayBufferByteLength(MDefinition* obj)
+{
+    MLoadFixedSlot* ins = MLoadFixedSlot::New(alloc(), obj, ArrayBufferObject::BYTE_LENGTH_SLOT);
+    current->add(ins);
+    ins->setResultType(MIRType_Int32);
+    return ins;
+}
+
 void
 IonBuilder::addTypedArrayLengthAndData(MDefinition* obj,
                                        BoundsChecking checking,
                                        MDefinition** index,
                                        MInstruction** length, MInstruction** elements)
 {
     MOZ_ASSERT((index != nullptr) == (elements != nullptr));
 
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -618,16 +618,18 @@ class IonBuilder
                                             MDefinition* index,
                                             TypedObjectPrediction objTypeReprs,
                                             TypedObjectPrediction elemTypeReprs,
                                             int32_t elemSize);
     TemporaryTypeSet* computeHeapType(const TemporaryTypeSet* objTypes, const jsid id);
 
     enum BoundsChecking { DoBoundsCheck, SkipBoundsCheck };
 
+    MInstruction* addArrayBufferByteLength(MDefinition* obj);
+
     // Add instructions to compute a typed array's length and data.  Also
     // optionally convert |*index| into a bounds-checked definition, if
     // requested.
     //
     // If you only need the array's length, use addTypedArrayLength below.
     void addTypedArrayLengthAndData(MDefinition* obj,
                                     BoundsChecking checking,
                                     MDefinition** index,
@@ -839,16 +841,19 @@ class IonBuilder
     // Slot intrinsics.
     InliningStatus inlineUnsafeSetReservedSlot(CallInfo& callInfo);
     InliningStatus inlineUnsafeGetReservedSlot(CallInfo& callInfo,
                                                MIRType knownValueType);
 
     // Map intrinsics.
     InliningStatus inlineGetNextMapEntryForIterator(CallInfo& callInfo);
 
+    // ArrayBuffer intrinsics.
+    InliningStatus inlinePossiblyWrappedArrayBufferByteLength(CallInfo& callInfo);
+
     // TypedArray intrinsics.
     enum WrappingBehavior { AllowWrappedTypedArrays, RejectWrappedTypedArrays };
     InliningStatus inlineIsTypedArrayHelper(CallInfo& callInfo, WrappingBehavior wrappingBehavior);
     InliningStatus inlineIsTypedArray(CallInfo& callInfo);
     InliningStatus inlineIsPossiblyWrappedTypedArray(CallInfo& callInfo);
     InliningStatus inlineTypedArrayLength(CallInfo& callInfo);
     InliningStatus inlinePossiblyWrappedTypedArrayLength(CallInfo& callInfo);
     InliningStatus inlineSetDisjointTypedElements(CallInfo& callInfo);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -259,16 +259,20 @@ IonBuilder::inlineNativeCall(CallInfo& c
         return inlineHasClass(callInfo, &ListIteratorObject::class_);
       case InlinableNative::IntrinsicDefineDataProperty:
         return inlineDefineDataProperty(callInfo);
 
       // Map intrinsics.
       case InlinableNative::IntrinsicGetNextMapEntryForIterator:
         return inlineGetNextMapEntryForIterator(callInfo);
 
+      // ArrayBuffer intrinsics.
+      case InlinableNative::IntrinsicPossiblyWrappedArrayBufferByteLength:
+        return inlinePossiblyWrappedArrayBufferByteLength(callInfo);
+
       // TypedArray intrinsics.
       case InlinableNative::IntrinsicIsTypedArray:
         return inlineIsTypedArray(callInfo);
       case InlinableNative::IntrinsicIsPossiblyWrappedTypedArray:
         return inlineIsPossiblyWrappedTypedArray(callInfo);
       case InlinableNative::IntrinsicPossiblyWrappedTypedArrayLength:
         return inlinePossiblyWrappedTypedArrayLength(callInfo);
       case InlinableNative::IntrinsicTypedArrayLength:
@@ -2229,16 +2233,50 @@ IonBuilder::inlineGetNextMapEntryForIter
     current->push(next);
 
     if (!resumeAfter(next))
         return InliningStatus_Error;
 
     return InliningStatus_Inlined;
 }
 
+static bool
+IsArrayBufferObject(CompilerConstraintList* constraints, MDefinition* def)
+{
+    MOZ_ASSERT(def->type() == MIRType_Object);
+
+    TemporaryTypeSet* types = def->resultTypeSet();
+    if (!types)
+        return false;
+
+    return types->getKnownClass(constraints) == &ArrayBufferObject::class_;
+}
+
+IonBuilder::InliningStatus
+IonBuilder::inlinePossiblyWrappedArrayBufferByteLength(CallInfo& callInfo)
+{
+    MOZ_ASSERT(!callInfo.constructing());
+    MOZ_ASSERT(callInfo.argc() == 1);
+
+    MDefinition* objArg = callInfo.getArg(0);
+    if (objArg->type() != MIRType_Object)
+        return InliningStatus_NotInlined;
+    if (getInlineReturnType() != MIRType_Int32)
+        return InliningStatus_NotInlined;
+
+    if (!IsArrayBufferObject(constraints(), objArg))
+        return InliningStatus_NotInlined;
+
+    MInstruction* ins = addArrayBufferByteLength(objArg);
+    current->push(ins);
+
+    callInfo.setImplicitlyUsedUnchecked();
+    return InliningStatus_Inlined;
+}
+
 IonBuilder::InliningStatus
 IonBuilder::inlineIsTypedArrayHelper(CallInfo& callInfo, WrappingBehavior wrappingBehavior)
 {
     MOZ_ASSERT(!callInfo.constructing());
     MOZ_ASSERT(callInfo.argc() == 1);
 
     if (callInfo.getArg(0)->type() != MIRType_Object)
         return InliningStatus_NotInlined;
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -2164,17 +2164,18 @@ static const JSFunctionSpec intrinsic_fu
     JS_FN("GeneratorSetClosed",      intrinsic_GeneratorSetClosed,      1,0),
 
     JS_FN("IsArrayBuffer",
           intrinsic_IsInstanceOfBuiltin<ArrayBufferObject>,             1,0),
     JS_FN("IsSharedArrayBuffer",
           intrinsic_IsInstanceOfBuiltin<SharedArrayBufferObject>,       1,0),
 
     JS_FN("ArrayBufferByteLength",   intrinsic_ArrayBufferByteLength,   1,0),
-    JS_FN("PossiblyWrappedArrayBufferByteLength", intrinsic_PossiblyWrappedArrayBufferByteLength, 1,0),
+    JS_INLINABLE_FN("PossiblyWrappedArrayBufferByteLength", intrinsic_PossiblyWrappedArrayBufferByteLength, 1,0,
+                    IntrinsicPossiblyWrappedArrayBufferByteLength),
     JS_FN("ArrayBufferCopyData",     intrinsic_ArrayBufferCopyData,     4,0),
 
     JS_FN("IsUint8TypedArray",        intrinsic_IsUint8TypedArray,      1,0),
     JS_FN("IsInt8TypedArray",         intrinsic_IsInt8TypedArray,       1,0),
     JS_FN("IsUint16TypedArray",       intrinsic_IsUint16TypedArray,     1,0),
     JS_FN("IsInt16TypedArray",        intrinsic_IsInt16TypedArray,      1,0),
     JS_FN("IsUint32TypedArray",       intrinsic_IsUint32TypedArray,     1,0),
     JS_FN("IsInt32TypedArray",        intrinsic_IsInt32TypedArray,      1,0),