[FTL] Support PutByVal(ArrayStorage/SlowPutArrayStorage)
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 27 Feb 2018 07:32:14 +0000 (07:32 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 27 Feb 2018 07:32:14 +0000 (07:32 +0000)
https://bugs.webkit.org/show_bug.cgi?id=182965

Reviewed by Saam Barati.

JSTests:

* stress/put-by-val-array-storage.js: Added.
(shouldBe):
(testArrayStorageInBounds):
* stress/put-by-val-direct-out-of-bounds-setter.js: Added.
(shouldBe):
(testInt32.createBuiltin):
(set for):
* stress/put-by-val-slow-put-array-storage.js: Added.
(shouldBe):
(testArrayStorageInBounds):

Source/JavaScriptCore:

This patch extends FTL coverage for PutByVal by adding ArrayStorage and SlwoPutArrayStorage support.
Basically large part of the patch is porting from DFG code. Since PutByVal already emits CheckInBounds
for InBounds case, we do not have OutOfBounds check for that case.
This is the last change for FTL to support all the types of DFG nodes except for CreateThis.

* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileDoublePutByVal):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compilePutByVal):
(JSC::FTL::DFG::LowerDFGToB3::contiguousPutByValOutOfBounds):
For consistency, we use operationPutByValXXX and operationPutByValDirectXXX.
But except for SlowPutArrayStorage case, basically it is meaningless since
we do not have indexed accessors.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229053 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
JSTests/ChangeLog
JSTests/stress/put-by-val-array-storage.js [new file with mode: 0644]
JSTests/stress/put-by-val-direct-out-of-bounds-setter.js [new file with mode: 0644]
JSTests/stress/put-by-val-slow-put-array-storage.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.cpp
Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

index 3bcc03e..fb96099 100644 (file)
@@ -1,3 +1,21 @@
+2018-02-25  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [FTL] Support PutByVal(ArrayStorage/SlowPutArrayStorage)
+        https://bugs.webkit.org/show_bug.cgi?id=182965
+
+        Reviewed by Saam Barati.
+
+        * stress/put-by-val-array-storage.js: Added.
+        (shouldBe):
+        (testArrayStorageInBounds):
+        * stress/put-by-val-direct-out-of-bounds-setter.js: Added.
+        (shouldBe):
+        (testInt32.createBuiltin):
+        (set for):
+        * stress/put-by-val-slow-put-array-storage.js: Added.
+        (shouldBe):
+        (testArrayStorageInBounds):
+
 2018-02-26  Saam Barati  <sbarati@apple.com>
 
         validateStackAccess should not validate if the offset is within the stack bounds
diff --git a/JSTests/stress/put-by-val-array-storage.js b/JSTests/stress/put-by-val-array-storage.js
new file mode 100644 (file)
index 0000000..c7d284f
--- /dev/null
@@ -0,0 +1,40 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function testArrayStorageInBounds(array, index, value)
+{
+    array[index] = value;
+}
+noInline(testArrayStorageInBounds);
+
+for (var i = 0; i < 1e5; ++i) {
+    var array = [1, 2, 3, 4, 5];
+    ensureArrayStorage(array);
+    shouldBe(array[0], 1);
+    testArrayStorageInBounds(array, 0, 42);
+    shouldBe(array[0], 42);
+}
+for (var i = 0; i < 1e5; ++i) {
+    var array = [, 2, 3, 4];
+    ensureArrayStorage(array);
+    shouldBe(array[0], undefined);
+    shouldBe(array[1], 2);
+    testArrayStorageInBounds(array, 0, 42);
+    testArrayStorageInBounds(array, 1, 40);
+    shouldBe(array[0], 42);
+    shouldBe(array[1], 40);
+    shouldBe(array.length, 4);
+    testArrayStorageInBounds(array, 4, 42);
+    shouldBe(array[4], 42);
+    shouldBe(array.length, 5);
+}
+for (var i = 0; i < 1e5; ++i) {
+    var array = [, 2, 3, 4];
+    ensureArrayStorage(array);
+    shouldBe(array[6], undefined);
+    testArrayStorageInBounds(array, 6, 42);
+    shouldBe(array.length, 7);
+    shouldBe(array[6], 42);
+}
diff --git a/JSTests/stress/put-by-val-direct-out-of-bounds-setter.js b/JSTests/stress/put-by-val-direct-out-of-bounds-setter.js
new file mode 100644 (file)
index 0000000..4e1401c
--- /dev/null
@@ -0,0 +1,26 @@
+var createBuiltin = $vm.createBuiltin;
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var testInt32 = createBuiltin(`(function (array, index, value) {
+    @putByValDirect(array, index, value);
+})`);
+noInline(testInt32);
+
+Object.defineProperty(Array.prototype, 42, {
+    get() {
+        return 30;
+    },
+    set(value) {
+    }
+});
+for (var i = 0; i < 1e5; ++i) {
+    var array = [1, 2, 3, 4, 5];
+    shouldBe(array[42], 30);
+    testInt32(array, 42, 42);
+    shouldBe(array[42], 42);
+    shouldBe(Array.prototype[42], 30);
+}
diff --git a/JSTests/stress/put-by-val-slow-put-array-storage.js b/JSTests/stress/put-by-val-slow-put-array-storage.js
new file mode 100644 (file)
index 0000000..b910ff5
--- /dev/null
@@ -0,0 +1,67 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function testArrayStorageInBounds(array, index, value)
+{
+    array[index] = value;
+}
+noInline(testArrayStorageInBounds);
+
+for (var i = 0; i < 1e4; ++i) {
+    var array = [1, 2, 3, 4, 5];
+    var object = { a: 10 };
+    Object.defineProperties(object, {
+        "1": {
+            get: function() { return this.a; },
+            set: function(x) { this.a = x; },
+        },
+    });
+    array.__proto__ = object;
+    ensureArrayStorage(array);
+    shouldBe(array[0], 1);
+    testArrayStorageInBounds(array, 0, 42);
+    shouldBe(array[0], 42);
+}
+for (var i = 0; i < 1e4; ++i) {
+    var array = [, 2, 3, 4];
+    var object = { a: 10 };
+    Object.defineProperties(object, {
+        "1": {
+            get: function() { return this.a; },
+            set: function(x) { this.a = x + 20; },
+        },
+    });
+    array.__proto__ = object;
+    ensureArrayStorage(array);
+    shouldBe(array[0], undefined);
+    shouldBe(array[1], 2);
+    testArrayStorageInBounds(array, 0, 42);
+    testArrayStorageInBounds(array, 1, 40);
+    shouldBe(array[0], 42);
+    shouldBe(array[1], 40);
+    testArrayStorageInBounds(array, 4, 42);
+    shouldBe(array[4], 42);
+    shouldBe(array.length, 5);
+}
+for (var i = 0; i < 1e4; ++i) {
+    var array = [, , 3, 4];
+    var object = { a: 10 };
+    Object.defineProperties(object, {
+        "1": {
+            get: function() { return this.a; },
+            set: function(x) { this.a = x + 20; },
+        },
+    });
+    array.__proto__ = object;
+    ensureArrayStorage(array);
+    shouldBe(array[0], undefined);
+    shouldBe(array[1], 10);
+    shouldBe(array[6], undefined);
+    testArrayStorageInBounds(array, 6, 42);
+    testArrayStorageInBounds(array, 1, 42);
+    shouldBe(array.length, 7);
+    shouldBe(array[1], 62);
+    shouldBe(array[6], 42);
+}
index 3374457..8d6e9c9 100644 (file)
@@ -1,3 +1,30 @@
+2018-02-25  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [FTL] Support PutByVal(ArrayStorage/SlowPutArrayStorage)
+        https://bugs.webkit.org/show_bug.cgi?id=182965
+
+        Reviewed by Saam Barati.
+
+        This patch extends FTL coverage for PutByVal by adding ArrayStorage and SlwoPutArrayStorage support.
+        Basically large part of the patch is porting from DFG code. Since PutByVal already emits CheckInBounds
+        for InBounds case, we do not have OutOfBounds check for that case.
+        This is the last change for FTL to support all the types of DFG nodes except for CreateThis.
+
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileDoublePutByVal):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compilePutByVal):
+        (JSC::FTL::DFG::LowerDFGToB3::contiguousPutByValOutOfBounds):
+        For consistency, we use operationPutByValXXX and operationPutByValDirectXXX.
+        But except for SlowPutArrayStorage case, basically it is meaningless since
+        we do not have indexed accessors.
+
 2018-02-26  Saam Barati  <sbarati@apple.com>
 
         validateStackAccess should not validate if the offset is within the stack bounds
index 07b395d..86418cd 100644 (file)
@@ -743,37 +743,37 @@ void JIT_OPERATION operationPutByValCellSymbolNonStrict(ExecState* exec, JSCell*
     putByValCellInternal<false, false>(exec, vm, cell, asSymbol(symbol)->privateName(), JSValue::decode(encodedValue));
 }
 
-void JIT_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue)
+void JIT_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* object, int32_t index, EncodedJSValue encodedValue)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
     
     if (index >= 0) {
-        array->putByIndexInline(exec, index, JSValue::decode(encodedValue), true);
+        object->putByIndexInline(exec, index, JSValue::decode(encodedValue), true);
         return;
     }
     
-    PutPropertySlot slot(array, true);
-    array->methodTable(vm)->put(
-        array, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
+    PutPropertySlot slot(object, true);
+    object->methodTable(vm)->put(
+        object, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
 }
 
-void JIT_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue)
+void JIT_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* object, int32_t index, EncodedJSValue encodedValue)
 {
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
     
     if (index >= 0) {
-        array->putByIndexInline(exec, index, JSValue::decode(encodedValue), false);
+        object->putByIndexInline(exec, index, JSValue::decode(encodedValue), false);
         return;
     }
     
-    PutPropertySlot slot(array, false);
-    array->methodTable(*vm)->put(
-        array, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
+    PutPropertySlot slot(object, false);
+    object->methodTable(*vm)->put(
+        object, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
 }
 
-void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, double value)
+void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* object, int32_t index, double value)
 {
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
@@ -781,16 +781,16 @@ void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState* exe
     JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
     
     if (index >= 0) {
-        array->putByIndexInline(exec, index, jsValue, true);
+        object->putByIndexInline(exec, index, jsValue, true);
         return;
     }
     
-    PutPropertySlot slot(array, true);
-    array->methodTable(*vm)->put(
-        array, exec, Identifier::from(exec, index), jsValue, slot);
+    PutPropertySlot slot(object, true);
+    object->methodTable(*vm)->put(
+        object, exec, Identifier::from(exec, index), jsValue, slot);
 }
 
-void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, double value)
+void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* object, int32_t index, double value)
 {
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
@@ -798,13 +798,45 @@ void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState*
     JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
     
     if (index >= 0) {
-        array->putByIndexInline(exec, index, jsValue, false);
+        object->putByIndexInline(exec, index, jsValue, false);
         return;
     }
     
-    PutPropertySlot slot(array, false);
-    array->methodTable(*vm)->put(
-        array, exec, Identifier::from(exec, index), jsValue, slot);
+    PutPropertySlot slot(object, false);
+    object->methodTable(*vm)->put(
+        object, exec, Identifier::from(exec, index), jsValue, slot);
+}
+
+void JIT_OPERATION operationPutDoubleByValDirectBeyondArrayBoundsStrict(ExecState* exec, JSObject* object, int32_t index, double value)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+
+    JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
+
+    if (index >= 0) {
+        object->putDirectIndex(exec, index, jsValue, 0, PutDirectIndexShouldThrow);
+        return;
+    }
+
+    PutPropertySlot slot(object, true);
+    object->putDirect(vm, Identifier::from(exec, index), jsValue, slot);
+}
+
+void JIT_OPERATION operationPutDoubleByValDirectBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* object, int32_t index, double value)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+
+    JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
+
+    if (index >= 0) {
+        object->putDirectIndex(exec, index, jsValue);
+        return;
+    }
+
+    PutPropertySlot slot(object, false);
+    object->putDirect(vm, Identifier::from(exec, index), jsValue, slot);
 }
 
 void JIT_OPERATION operationPutByValDirectStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
@@ -871,31 +903,31 @@ void JIT_OPERATION operationPutByValDirectCellSymbolNonStrict(ExecState* exec, J
     putByValCellInternal<false, true>(exec, vm, cell, asSymbol(symbol)->privateName(), JSValue::decode(encodedValue));
 }
 
-void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue)
+void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsStrict(ExecState* exec, JSObject* object, int32_t index, EncodedJSValue encodedValue)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
     if (index >= 0) {
-        array->putDirectIndex(exec, index, JSValue::decode(encodedValue), 0, PutDirectIndexShouldThrow);
+        object->putDirectIndex(exec, index, JSValue::decode(encodedValue), 0, PutDirectIndexShouldThrow);
         return;
     }
     
-    PutPropertySlot slot(array, true);
-    array->putDirect(vm, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
+    PutPropertySlot slot(object, true);
+    object->putDirect(vm, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
 }
 
-void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue)
+void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* object, int32_t index, EncodedJSValue encodedValue)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
     
     if (index >= 0) {
-        array->putDirectIndex(exec, index, JSValue::decode(encodedValue));
+        object->putDirectIndex(exec, index, JSValue::decode(encodedValue));
         return;
     }
     
-    PutPropertySlot slot(array, false);
-    array->putDirect(vm, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
+    PutPropertySlot slot(object, false);
+    object->putDirect(vm, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
 }
 
 EncodedJSValue JIT_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue encodedValue, JSArray* array)
index 982d26f..a5290c7 100644 (file)
@@ -131,6 +131,8 @@ void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsStrict(ExecState*, JS
 void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsNonStrict(ExecState*, JSObject*, int32_t index, EncodedJSValue encodedValue) WTF_INTERNAL;
 void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState*, JSObject*, int32_t index, double value) WTF_INTERNAL;
 void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState*, JSObject*, int32_t index, double value) WTF_INTERNAL;
+void JIT_OPERATION operationPutDoubleByValDirectBeyondArrayBoundsStrict(ExecState*, JSObject*, int32_t index, double value) WTF_INTERNAL;
+void JIT_OPERATION operationPutDoubleByValDirectBeyondArrayBoundsNonStrict(ExecState*, JSObject*, int32_t index, double value) WTF_INTERNAL;
 void JIT_OPERATION operationPutByIdWithThis(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
 void JIT_OPERATION operationPutByIdWithThisStrict(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
 void JIT_OPERATION operationPutByValWithThis(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
index a92b871..5c17f00 100644 (file)
@@ -2079,7 +2079,9 @@ void SpeculativeJIT::compileDoublePutByVal(Node* node, SpeculateCellOperand& bas
         addSlowPathGenerator(
             slowPathCall(
                 slowCase, this,
-                m_jit.codeBlock()->isStrictMode() ? operationPutDoubleByValBeyondArrayBoundsStrict : operationPutDoubleByValBeyondArrayBoundsNonStrict,
+                m_jit.codeBlock()->isStrictMode()
+                    ? (node->op() == PutByValDirect ? operationPutDoubleByValDirectBeyondArrayBoundsStrict : operationPutDoubleByValBeyondArrayBoundsStrict)
+                    : (node->op() == PutByValDirect ? operationPutDoubleByValDirectBeyondArrayBoundsNonStrict : operationPutDoubleByValBeyondArrayBoundsNonStrict),
                 NoResult, baseReg, propertyReg, valueReg));
     }
 
index 9293644..96d593a 100644 (file)
@@ -3070,17 +3070,12 @@ void SpeculativeJIT::compile(Node* node)
             storage.use();
             
             if (arrayMode.isOutOfBounds()) {
-                if (node->op() == PutByValDirect) {
-                    addSlowPathGenerator(slowPathCall(
-                        slowCase, this,
-                        m_jit.codeBlock()->isStrictMode() ? operationPutByValDirectBeyondArrayBoundsStrict : operationPutByValDirectBeyondArrayBoundsNonStrict,
-                        NoResult, baseReg, propertyReg, valueReg));
-                } else {
-                    addSlowPathGenerator(slowPathCall(
-                        slowCase, this,
-                        m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
-                        NoResult, baseReg, propertyReg, valueReg));
-                }
+                addSlowPathGenerator(slowPathCall(
+                    slowCase, this,
+                    m_jit.codeBlock()->isStrictMode()
+                        ? (node->op() == PutByValDirect ? operationPutByValDirectBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsStrict)
+                        : (node->op() == PutByValDirect ? operationPutByValDirectBeyondArrayBoundsNonStrict : operationPutByValBeyondArrayBoundsNonStrict),
+                    NoResult, baseReg, propertyReg, valueReg));
             }
 
             noResult(node, UseChildrenCalledExplicitly);
@@ -3159,17 +3154,12 @@ void SpeculativeJIT::compile(Node* node)
             storage.use();
             
             if (!slowCases.empty()) {
-                if (node->op() == PutByValDirect) {
-                    addSlowPathGenerator(slowPathCall(
-                        slowCases, this,
-                        m_jit.codeBlock()->isStrictMode() ? operationPutByValDirectBeyondArrayBoundsStrict : operationPutByValDirectBeyondArrayBoundsNonStrict,
-                        NoResult, baseReg, propertyReg, valueReg));
-                } else {
-                    addSlowPathGenerator(slowPathCall(
-                        slowCases, this,
-                        m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
-                        NoResult, baseReg, propertyReg, valueReg));
-                }
+                addSlowPathGenerator(slowPathCall(
+                    slowCases, this,
+                    m_jit.codeBlock()->isStrictMode()
+                        ? (node->op() == PutByValDirect ? operationPutByValDirectBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsStrict)
+                        : (node->op() == PutByValDirect ? operationPutByValDirectBeyondArrayBoundsNonStrict : operationPutByValBeyondArrayBoundsNonStrict),
+                    NoResult, baseReg, propertyReg, valueReg));
             }
 
             noResult(node, UseChildrenCalledExplicitly);
index 40cc8b8..fcee94d 100644 (file)
@@ -59,6 +59,8 @@ AbstractHeapRepository::AbstractHeapRepository()
 #undef ABSTRACT_FIELD_INITIALIZATION
     
     , JSCell_freeListNext(JSCell_header)
+    , ArrayStorage_publicLength(Butterfly_publicLength)
+    , ArrayStorage_vectorLength(Butterfly_vectorLength)
     
 #define INDEXED_ABSTRACT_HEAP_INITIALIZATION(name, offset, size) , name(&root, #name, offset, size)
     FOR_EACH_INDEXED_ABSTRACT_HEAP(INDEXED_ABSTRACT_HEAP_INITIALIZATION)
index 97101b2..61655a1 100644 (file)
@@ -175,6 +175,8 @@ public:
 #undef ABSTRACT_FIELD_DECLARATION
     
     AbstractHeap& JSCell_freeListNext;
+    AbstractHeap& ArrayStorage_publicLength;
+    AbstractHeap& ArrayStorage_vectorLength;
     
 #define INDEXED_ABSTRACT_HEAP_DECLARATION(name, offset, size) IndexedAbstractHeap name;
     FOR_EACH_INDEXED_ABSTRACT_HEAP(INDEXED_ABSTRACT_HEAP_DECLARATION)
index 5888149..1a3edf5 100644 (file)
@@ -420,6 +420,8 @@ inline CapabilityLevel canCompile(Node* node)
         case Array::Int32:
         case Array::Double:
         case Array::Contiguous:
+        case Array::ArrayStorage:
+        case Array::SlowPutArrayStorage:
             break;
         default:
             if (isTypedView(node->arrayMode().typedArrayType()))
index 0ed85a8..c4324db 100644 (file)
@@ -3650,7 +3650,7 @@ private:
 
         case Array::ArrayStorage:
         case Array::SlowPutArrayStorage: {
-            LValue length = m_out.load32(lowStorage(m_node->child2()), m_heaps.Butterfly_publicLength);
+            LValue length = m_out.load32(lowStorage(m_node->child2()), m_heaps.ArrayStorage_publicLength);
             speculate(Uncountable, noValue(), nullptr, m_out.lessThan(length, m_out.int32Zero));
             setInt32(length);
             return;
@@ -3697,7 +3697,7 @@ private:
         switch (m_node->arrayMode().type()) {
         case Array::ArrayStorage:
         case Array::SlowPutArrayStorage:
-            setInt32(m_out.load32NonNegative(lowStorage(m_node->child2()), m_heaps.Butterfly_vectorLength));
+            setInt32(m_out.load32NonNegative(lowStorage(m_node->child2()), m_heaps.ArrayStorage_vectorLength));
             return;
         default:
             return;
@@ -3964,7 +3964,7 @@ private:
             LBasicBlock continuation = m_out.newBlock();
 
             m_out.branch(
-                m_out.aboveOrEqual(index, m_out.load32NonNegative(storage, m_heaps.Butterfly_vectorLength)),
+                m_out.aboveOrEqual(index, m_out.load32NonNegative(storage, m_heaps.ArrayStorage_vectorLength)),
                 rarely(slowCase), usually(inBounds));
 
             LBasicBlock lastNext = m_out.appendTo(inBounds, slowCase);
@@ -4195,8 +4195,8 @@ private:
                 
                 contiguousPutByValOutOfBounds(
                     codeBlock()->isStrictMode()
-                    ? operationPutByValBeyondArrayBoundsStrict
-                    : operationPutByValBeyondArrayBoundsNonStrict,
+                        ? (m_node->op() == PutByValDirect ? operationPutByValDirectBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsStrict)
+                        : (m_node->op() == PutByValDirect ? operationPutByValDirectBeyondArrayBoundsNonStrict : operationPutByValBeyondArrayBoundsNonStrict),
                     base, storage, index, value, continuation);
                 
                 m_out.store64(value, elementPointer);
@@ -4221,8 +4221,8 @@ private:
                 
                 contiguousPutByValOutOfBounds(
                     codeBlock()->isStrictMode()
-                    ? operationPutDoubleByValBeyondArrayBoundsStrict
-                    : operationPutDoubleByValBeyondArrayBoundsNonStrict,
+                        ? (m_node->op() == PutByValDirect ? operationPutDoubleByValDirectBeyondArrayBoundsStrict : operationPutDoubleByValBeyondArrayBoundsStrict)
+                        : (m_node->op() == PutByValDirect ? operationPutDoubleByValDirectBeyondArrayBoundsNonStrict : operationPutDoubleByValBeyondArrayBoundsNonStrict),
                     base, storage, index, value, continuation);
                 
                 m_out.storeDouble(value, elementPointer);
@@ -4237,8 +4237,85 @@ private:
             m_out.appendTo(continuation, outerLastNext);
             return;
         }
+
+        case Array::ArrayStorage:
+        case Array::SlowPutArrayStorage: {
+            LValue value = lowJSValue(child3);
+
+            TypedPointer elementPointer = m_out.baseIndex(
+                m_heaps.ArrayStorage_vector, storage, m_out.zeroExtPtr(index),
+                provenValue(child2));
+
+            if (m_node->op() == PutByValAlias) {
+                m_out.store64(value, elementPointer);
+                return;
+            }
+
+            if (m_node->arrayMode().isInBounds()) {
+                speculate(StoreToHole, noValue(), 0, m_out.isZero64(m_out.load64(elementPointer)));
+                m_out.store64(value, elementPointer);
+                return;
+            }
+
+            LValue isOutOfBounds = m_out.aboveOrEqual(
+                index, m_out.load32NonNegative(storage, m_heaps.ArrayStorage_vectorLength));
+
+            auto slowPathFunction = codeBlock()->isStrictMode()
+                ? (m_node->op() == PutByValDirect ? operationPutByValDirectBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsStrict)
+                : (m_node->op() == PutByValDirect ? operationPutByValDirectBeyondArrayBoundsNonStrict : operationPutByValBeyondArrayBoundsNonStrict);
+            if (!m_node->arrayMode().isOutOfBounds()) {
+                speculate(OutOfBounds, noValue(), 0, isOutOfBounds);
+                isOutOfBounds = m_out.booleanFalse;
+            }
+
+            LBasicBlock inBoundCase = m_out.newBlock();
+            LBasicBlock slowCase = m_out.newBlock();
+            LBasicBlock holeCase = m_out.newBlock();
+            LBasicBlock doStoreCase = m_out.newBlock();
+            LBasicBlock lengthUpdateCase = m_out.newBlock();
+            LBasicBlock continuation = m_out.newBlock();
+
+            m_out.branch(isOutOfBounds, rarely(slowCase), usually(inBoundCase));
+
+            LBasicBlock lastNext = m_out.appendTo(slowCase, inBoundCase);
+            vmCall(
+                Void, m_out.operation(slowPathFunction),
+                m_callFrame, base, index, value);
+            m_out.jump(continuation);
+
+
+            if (m_node->arrayMode().isSlowPut()) {
+                m_out.appendTo(inBoundCase, doStoreCase);
+                m_out.branch(m_out.isZero64(m_out.load64(elementPointer)), rarely(slowCase), usually(doStoreCase));
+            } else {
+                m_out.appendTo(inBoundCase, holeCase);
+                m_out.branch(m_out.isZero64(m_out.load64(elementPointer)), rarely(holeCase), usually(doStoreCase));
+
+                m_out.appendTo(holeCase, lengthUpdateCase);
+                m_out.store32(
+                    m_out.add(m_out.load32(storage, m_heaps.ArrayStorage_numValuesInVector), m_out.int32One),
+                    storage, m_heaps.ArrayStorage_numValuesInVector);
+                m_out.branch(
+                    m_out.below(
+                        index, m_out.load32NonNegative(storage, m_heaps.ArrayStorage_publicLength)),
+                    unsure(doStoreCase), unsure(lengthUpdateCase));
+
+                m_out.appendTo(lengthUpdateCase, doStoreCase);
+                m_out.store32(
+                    m_out.add(index, m_out.int32One),
+                    storage, m_heaps.ArrayStorage_publicLength);
+                m_out.jump(doStoreCase);
+            }
+
+            m_out.appendTo(doStoreCase, continuation);
+            m_out.store64(value, elementPointer);
+            m_out.jump(continuation);
+
+            m_out.appendTo(continuation, lastNext);
+            return;
+        }
             
-        default:
+        default: {
             TypedArrayType type = m_node->arrayMode().typedArrayType();
             
             if (isTypedView(type)) {
@@ -4298,6 +4375,7 @@ private:
             DFG_CRASH(m_graph, m_node, "Bad array type");
             break;
         }
+        }
     }
 
     void compilePutAccessorById()
@@ -4482,7 +4560,7 @@ private:
             // This ensures that the result of ArrayPush is Int32 in AI.
             int32_t largestPositiveInt32Length = 0x7fffffff - elementCount;
 
-            LValue prevLength = m_out.load32(storage, m_heaps.Butterfly_publicLength);
+            LValue prevLength = m_out.load32(storage, m_heaps.ArrayStorage_publicLength);
             // Refuse to handle bizarre lengths.
             speculate(Uncountable, noValue(), nullptr, m_out.above(prevLength, m_out.constInt32(largestPositiveInt32Length)));
 
@@ -4497,14 +4575,14 @@ private:
 
                 m_out.branch(
                     m_out.aboveOrEqual(
-                        prevLength, m_out.load32(storage, m_heaps.Butterfly_vectorLength)),
+                        prevLength, m_out.load32(storage, m_heaps.ArrayStorage_vectorLength)),
                     rarely(slowPath), usually(fastPath));
 
                 LBasicBlock lastNext = m_out.appendTo(fastPath, slowPath);
                 m_out.store64(
                     value, m_out.baseIndex(m_heaps.ArrayStorage_vector, storage, m_out.zeroExtPtr(prevLength)));
                 LValue newLength = m_out.add(prevLength, m_out.int32One);
-                m_out.store32(newLength, storage, m_heaps.Butterfly_publicLength);
+                m_out.store32(newLength, storage, m_heaps.ArrayStorage_publicLength);
                 m_out.store32(
                     m_out.add(m_out.load32(storage, m_heaps.ArrayStorage_numValuesInVector), m_out.int32One),
                     storage, m_heaps.ArrayStorage_numValuesInVector);
@@ -4530,12 +4608,12 @@ private:
             LBasicBlock slowCallPath = m_out.newBlock();
             LBasicBlock continuation = m_out.newBlock();
 
-            LValue beyondVectorLength = m_out.above(newLength, m_out.load32(storage, m_heaps.Butterfly_vectorLength));
+            LValue beyondVectorLength = m_out.above(newLength, m_out.load32(storage, m_heaps.ArrayStorage_vectorLength));
 
             m_out.branch(beyondVectorLength, rarely(slowPath), usually(fastPath));
 
             LBasicBlock lastNext = m_out.appendTo(fastPath, slowPath);
-            m_out.store32(newLength, storage, m_heaps.Butterfly_publicLength);
+            m_out.store32(newLength, storage, m_heaps.ArrayStorage_publicLength);
             m_out.store32(
                 m_out.add(m_out.load32(storage, m_heaps.ArrayStorage_numValuesInVector), m_out.constInt32(elementCount)),
                 storage, m_heaps.ArrayStorage_numValuesInVector);
@@ -4852,7 +4930,7 @@ private:
             LBasicBlock slowCase = m_out.newBlock();
             LBasicBlock continuation = m_out.newBlock();
 
-            LValue prevLength = m_out.load32(storage, m_heaps.Butterfly_publicLength);
+            LValue prevLength = m_out.load32(storage, m_heaps.ArrayStorage_publicLength);
 
             Vector<ValueFromBlock, 3> results;
             results.append(m_out.anchor(m_out.constInt64(JSValue::encode(jsUndefined()))));
@@ -4862,7 +4940,7 @@ private:
             LBasicBlock lastNext = m_out.appendTo(vectorLengthCheckCase, popCheckCase);
             LValue newLength = m_out.sub(prevLength, m_out.int32One);
             m_out.branch(
-                m_out.aboveOrEqual(newLength, m_out.load32(storage, m_heaps.Butterfly_vectorLength)), rarely(slowCase), usually(popCheckCase));
+                m_out.aboveOrEqual(newLength, m_out.load32(storage, m_heaps.ArrayStorage_vectorLength)), rarely(slowCase), usually(popCheckCase));
 
             m_out.appendTo(popCheckCase, fastCase);
             TypedPointer pointer = m_out.baseIndex(m_heaps.ArrayStorage_vector, storage, m_out.zeroExtPtr(newLength));
@@ -4870,7 +4948,7 @@ private:
             m_out.branch(m_out.notZero64(result), usually(fastCase), rarely(slowCase));
 
             m_out.appendTo(fastCase, slowCase);
-            m_out.store32(newLength, storage, m_heaps.Butterfly_publicLength);
+            m_out.store32(newLength, storage, m_heaps.ArrayStorage_publicLength);
             m_out.store64(m_out.int64Zero, pointer);
             m_out.store32(
                 m_out.sub(m_out.load32(storage, m_heaps.ArrayStorage_numValuesInVector), m_out.int32One),
@@ -9968,7 +10046,7 @@ private:
                 LBasicBlock checkHole = m_out.newBlock();
                 m_out.branch(
                     m_out.aboveOrEqual(
-                        index, m_out.load32NonNegative(storage, m_heaps.Butterfly_vectorLength)),
+                        index, m_out.load32NonNegative(storage, m_heaps.ArrayStorage_vectorLength)),
                     rarely(slowCase), usually(checkHole));
                 lastNext = m_out.appendTo(checkHole, slowCase);
             } else
@@ -13000,14 +13078,14 @@ private:
         FunctionType slowPathFunction, LValue base, LValue storage, LValue index, LValue value,
         LBasicBlock continuation)
     {
-        LValue isNotInBounds = m_out.aboveOrEqual(
-            index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength));
         if (!m_node->arrayMode().isInBounds()) {
             LBasicBlock notInBoundsCase =
                 m_out.newBlock();
             LBasicBlock performStore =
                 m_out.newBlock();
                 
+            LValue isNotInBounds = m_out.aboveOrEqual(
+                index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength));
             m_out.branch(isNotInBounds, unsure(notInBoundsCase), unsure(performStore));
                 
             LBasicBlock lastNext = m_out.appendTo(notInBoundsCase, performStore);