[JSC] Remove JSFixedArray, and use JSImmutableButterfly instead
authorysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 14 Dec 2019 04:34:45 +0000 (04:34 +0000)
committerysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 14 Dec 2019 04:34:45 +0000 (04:34 +0000)
https://bugs.webkit.org/show_bug.cgi?id=204402

Reviewed by Mark Lam.

JSTests:

* stress/new-array-with-spread-cow-double.js: Added.
(shouldBe):
(shouldBeArray):
(test):
* stress/new-array-with-spread-cow-int.js: Added.
(shouldBe):
(shouldBeArray):
(test):
* stress/new-array-with-spread-cow.js: Added.
(shouldBe):
(shouldBeArray):
(test):

Source/JavaScriptCore:

This patch removes JSFixedArray, and use JSImmutableButterfly instead. JSFixedArray can be replaced by
JSImmutableButterfly with Contiguous shape. And further, we can create an array from JSImmutableButterfly
generated by Spread node in NewArrayBufferWithSpread.

Currently, we are always creating contiguous JSImmutableButterfly from Spread. If it takes contiguous CoW
array, we can reuse JSImmutableButterfly of the input. But if it is CoW and not contiguous shape (like,
CopyOnWriteArrayWithInt32), we create a JSImmutableButterfly and copy it to this new butterfly. We can
extend it to accept non-contiguous JSImmutableButterfly in the future.

* JavaScriptCore.xcodeproj/project.pbxproj:
* Sources.txt:
* bytecompiler/BytecodeGenerator.cpp:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileSpread):
(JSC::DFG::SpeculativeJIT::compileNewArrayWithSpread):
(JSC::DFG::SpeculativeJIT::compileObjectKeys):
* ftl/FTLAbstractHeapRepository.h:
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNewArrayWithSpread):
(JSC::FTL::DFG::LowerDFGToB3::compileSpread):
(JSC::FTL::DFG::LowerDFGToB3::toButterfly):
* ftl/FTLOperations.cpp:
(JSC::FTL::operationMaterializeObjectInOSR):
* interpreter/Interpreter.cpp:
(JSC::sizeOfVarargs):
(JSC::loadVarargs):
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/JSCast.h:
* runtime/JSFixedArray.cpp: Removed.
* runtime/JSFixedArray.h: Removed.
* runtime/JSImmutableButterfly.h:
(JSC::JSImmutableButterfly::createFromArray):
(JSC::JSImmutableButterfly::offsetOfPublicLength):
(JSC::JSImmutableButterfly::offsetOfVectorLength):
* runtime/JSType.cpp:
(WTF::printInternal):
* runtime/JSType.h:
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:

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

28 files changed:
JSTests/ChangeLog
JSTests/stress/new-array-with-spread-cow-double.js [new file with mode: 0644]
JSTests/stress/new-array-with-spread-cow-int.js [new file with mode: 0644]
JSTests/stress/new-array-with-spread-cow.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/Sources.txt
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/ftl/FTLOperations.cpp
Source/JavaScriptCore/interpreter/Interpreter.cpp
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
Source/JavaScriptCore/runtime/JSCast.h
Source/JavaScriptCore/runtime/JSFixedArray.cpp [deleted file]
Source/JavaScriptCore/runtime/JSFixedArray.h [deleted file]
Source/JavaScriptCore/runtime/JSImmutableButterfly.h
Source/JavaScriptCore/runtime/JSType.cpp
Source/JavaScriptCore/runtime/JSType.h
Source/JavaScriptCore/runtime/VM.cpp
Source/JavaScriptCore/runtime/VM.h

index 1f537aa..7c5af44 100644 (file)
@@ -1,3 +1,23 @@
+2019-12-13  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] Remove JSFixedArray, and use JSImmutableButterfly instead
+        https://bugs.webkit.org/show_bug.cgi?id=204402
+
+        Reviewed by Mark Lam.
+
+        * stress/new-array-with-spread-cow-double.js: Added.
+        (shouldBe):
+        (shouldBeArray):
+        (test):
+        * stress/new-array-with-spread-cow-int.js: Added.
+        (shouldBe):
+        (shouldBeArray):
+        (test):
+        * stress/new-array-with-spread-cow.js: Added.
+        (shouldBe):
+        (shouldBeArray):
+        (test):
+
 2019-12-13  Mark Lam  <mark.lam@apple.com>
 
         Fix bad exception assertion in ExceptionHelpers.cpp's createError().
diff --git a/JSTests/stress/new-array-with-spread-cow-double.js b/JSTests/stress/new-array-with-spread-cow-double.js
new file mode 100644 (file)
index 0000000..0379a2e
--- /dev/null
@@ -0,0 +1,30 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function shouldBeArray(actual, expected) {
+    shouldBe(actual.length, expected.length);
+    for (var i = 0; i < expected.length; ++i) {
+        try {
+            shouldBe(actual[i], expected[i]);
+        } catch(e) {
+            print(JSON.stringify(actual));
+            throw e;
+        }
+    }
+}
+
+function test(flags)
+{
+    var array = [0.1, 0.2, 0.3];
+    if (flags)
+        OSRExit();
+    var cloned = [...array];
+    return cloned
+}
+noInline(test);
+
+for (var i = 0; i < 1e6; ++i)
+    shouldBeArray(test(false), [0.1, 0.2, 0.3]);
+shouldBeArray(test(true), [0.1, 0.2, 0.3]);
diff --git a/JSTests/stress/new-array-with-spread-cow-int.js b/JSTests/stress/new-array-with-spread-cow-int.js
new file mode 100644 (file)
index 0000000..35e6e28
--- /dev/null
@@ -0,0 +1,30 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function shouldBeArray(actual, expected) {
+    shouldBe(actual.length, expected.length);
+    for (var i = 0; i < expected.length; ++i) {
+        try {
+            shouldBe(actual[i], expected[i]);
+        } catch(e) {
+            print(JSON.stringify(actual));
+            throw e;
+        }
+    }
+}
+
+function test(flags)
+{
+    var array = [0, 1, 2, 3];
+    if (flags)
+        OSRExit();
+    var cloned = [...array];
+    return cloned
+}
+noInline(test);
+
+for (var i = 0; i < 1e6; ++i)
+    shouldBeArray(test(false), [0, 1, 2, 3]);
+shouldBeArray(test(true), [0, 1, 2, 3]);
diff --git a/JSTests/stress/new-array-with-spread-cow.js b/JSTests/stress/new-array-with-spread-cow.js
new file mode 100644 (file)
index 0000000..fb22f9f
--- /dev/null
@@ -0,0 +1,30 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function shouldBeArray(actual, expected) {
+    shouldBe(actual.length, expected.length);
+    for (var i = 0; i < expected.length; ++i) {
+        try {
+            shouldBe(actual[i], expected[i]);
+        } catch(e) {
+            print(JSON.stringify(actual));
+            throw e;
+        }
+    }
+}
+
+function test(flags)
+{
+    var array = ["hello", "world"];
+    if (flags)
+        OSRExit();
+    var cloned = [...array];
+    return cloned
+}
+noInline(test);
+
+for (var i = 0; i < 1e6; ++i)
+    shouldBeArray(test(false), ["hello", "world"]);
+shouldBeArray(test(true), ["hello", "world"]);
index 1ba7388..c05bc8b 100644 (file)
@@ -1,3 +1,61 @@
+2019-12-13  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] Remove JSFixedArray, and use JSImmutableButterfly instead
+        https://bugs.webkit.org/show_bug.cgi?id=204402
+
+        Reviewed by Mark Lam.
+
+        This patch removes JSFixedArray, and use JSImmutableButterfly instead. JSFixedArray can be replaced by
+        JSImmutableButterfly with Contiguous shape. And further, we can create an array from JSImmutableButterfly
+        generated by Spread node in NewArrayBufferWithSpread.
+
+        Currently, we are always creating contiguous JSImmutableButterfly from Spread. If it takes contiguous CoW
+        array, we can reuse JSImmutableButterfly of the input. But if it is CoW and not contiguous shape (like,
+        CopyOnWriteArrayWithInt32), we create a JSImmutableButterfly and copy it to this new butterfly. We can
+        extend it to accept non-contiguous JSImmutableButterfly in the future.
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Sources.txt:
+        * bytecompiler/BytecodeGenerator.cpp:
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileSpread):
+        (JSC::DFG::SpeculativeJIT::compileNewArrayWithSpread):
+        (JSC::DFG::SpeculativeJIT::compileObjectKeys):
+        * ftl/FTLAbstractHeapRepository.h:
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNewArrayWithSpread):
+        (JSC::FTL::DFG::LowerDFGToB3::compileSpread):
+        (JSC::FTL::DFG::LowerDFGToB3::toButterfly):
+        * ftl/FTLOperations.cpp:
+        (JSC::FTL::operationMaterializeObjectInOSR):
+        * interpreter/Interpreter.cpp:
+        (JSC::sizeOfVarargs):
+        (JSC::loadVarargs):
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        * runtime/JSCast.h:
+        * runtime/JSFixedArray.cpp: Removed.
+        * runtime/JSFixedArray.h: Removed.
+        * runtime/JSImmutableButterfly.h:
+        (JSC::JSImmutableButterfly::createFromArray):
+        (JSC::JSImmutableButterfly::offsetOfPublicLength):
+        (JSC::JSImmutableButterfly::offsetOfVectorLength):
+        * runtime/JSType.cpp:
+        (WTF::printInternal):
+        * runtime/JSType.h:
+        * runtime/VM.cpp:
+        (JSC::VM::VM):
+        * runtime/VM.h:
+
 2019-12-13  Saam Barati  <sbarati@apple.com>
 
         Structure should have a bloom filter of seen identifiers
index 161d705..d996c1e 100644 (file)
                7980C16D1E3A940E00B71615 /* DFGRegisteredStructureSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 7980C16B1E3A940E00B71615 /* DFGRegisteredStructureSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
                7986943B1F8C0ACC009232AE /* StructureCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 7986943A1F8C0AC8009232AE /* StructureCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
                79872C48221BBAF3008C6969 /* JSBaseInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 79872C47221BBAED008C6969 /* JSBaseInternal.h */; };
-               798937791DCAB57300F8D4FB /* JSFixedArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 798937771DCAB57300F8D4FB /* JSFixedArray.h */; settings = {ATTRIBUTES = (Private, ); }; };
                799EF7C41C56ED96002B0534 /* B3PCToOriginMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 799EF7C31C56ED96002B0534 /* B3PCToOriginMap.h */; settings = {ATTRIBUTES = (Private, ); }; };
                79A090801D768465008B889B /* HashMapImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 79A0907E1D768465008B889B /* HashMapImpl.h */; settings = {ATTRIBUTES = (Private, ); }; };
                79A228361D35D71F00D8E067 /* ArithProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 79A228341D35D71E00D8E067 /* ArithProfile.h */; };
                798694391F8C0AC7009232AE /* StructureCache.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = StructureCache.cpp; sourceTree = "<group>"; };
                7986943A1F8C0AC8009232AE /* StructureCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StructureCache.h; sourceTree = "<group>"; };
                79872C47221BBAED008C6969 /* JSBaseInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSBaseInternal.h; sourceTree = "<group>"; };
-               798937761DCAB57300F8D4FB /* JSFixedArray.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSFixedArray.cpp; sourceTree = "<group>"; };
-               798937771DCAB57300F8D4FB /* JSFixedArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSFixedArray.h; sourceTree = "<group>"; };
                799EF7C31C56ED96002B0534 /* B3PCToOriginMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3PCToOriginMap.h; path = b3/B3PCToOriginMap.h; sourceTree = "<group>"; };
                79A0907D1D768465008B889B /* HashMapImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HashMapImpl.cpp; sourceTree = "<group>"; };
                79A0907E1D768465008B889B /* HashMapImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HashMapImpl.h; sourceTree = "<group>"; };
                                0F7DF1391E29710E0095951B /* JSDestructibleObjectHeapCellType.cpp */,
                                0F7DF13A1E29710E0095951B /* JSDestructibleObjectHeapCellType.h */,
                                A7B4ACAE1484C9CE00B38A36 /* JSExportMacros.h */,
-                               798937761DCAB57300F8D4FB /* JSFixedArray.cpp */,
-                               798937771DCAB57300F8D4FB /* JSFixedArray.h */,
                                0F2B66C117B6B5AB00A7AE3F /* JSFloat32Array.h */,
                                0F2B66C217B6B5AB00A7AE3F /* JSFloat64Array.h */,
                                F692A85E0255597D01FF60F7 /* JSFunction.cpp */,
                                FE384EE61ADDB7AD0055DE2C /* JSDollarVM.h in Headers */,
                                86E3C614167BABD7006D760A /* JSExport.h in Headers */,
                                A7B4ACAF1484C9CE00B38A36 /* JSExportMacros.h in Headers */,
-                               798937791DCAB57300F8D4FB /* JSFixedArray.h in Headers */,
                                0F2B66EF17B6B5AB00A7AE3F /* JSFloat32Array.h in Headers */,
                                0F2B66F017B6B5AB00A7AE3F /* JSFloat64Array.h in Headers */,
                                BC18C41F0E16F5CD00B34460 /* JSFunction.h in Headers */,
index 53ccc74..1818bf7 100644 (file)
@@ -831,7 +831,6 @@ runtime/JSDataView.cpp
 runtime/JSDataViewPrototype.cpp
 runtime/JSDateMath.cpp
 runtime/JSDestructibleObjectHeapCellType.cpp
-runtime/JSFixedArray.cpp
 runtime/JSFunction.cpp
 runtime/JSGenerator.cpp
 runtime/JSGeneratorFunction.cpp
index cbdf269..f80a7c4 100644 (file)
@@ -44,7 +44,6 @@
 #include "JSAsyncGenerator.h"
 #include "JSBigInt.h"
 #include "JSCInlines.h"
-#include "JSFixedArray.h"
 #include "JSFunction.h"
 #include "JSGeneratorFunction.h"
 #include "JSImmutableButterfly.h"
index 5d7e696..64acb54 100644 (file)
@@ -2627,8 +2627,26 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             // We've compiled assuming we're not having a bad time, so to be consistent
             // with StructureRegisterationPhase we must say we produce an original array
             // allocation structure.
-            setForNode(node, 
-                m_graph.globalObjectFor(node->origin.semantic)->originalArrayStructureForIndexingType(ArrayWithContiguous));
+#if USE(JSVALUE64)
+            BitVector* bitVector = node->bitVector();
+            if (node->numChildren() == 1 && bitVector->get(0)) {
+                Edge use = m_graph.varArgChild(node, 0);
+                if (use->op() == PhantomSpread) {
+                    if (use->child1()->op() == PhantomNewArrayBuffer) {
+                        auto* immutableButterfly = use->child1()->castOperand<JSImmutableButterfly*>();
+                        if (hasContiguous(immutableButterfly->indexingType())) {
+                            m_state.setShouldTryConstantFolding(true);
+                            setForNode(node, m_graph.globalObjectFor(node->origin.semantic)->originalArrayStructureForIndexingType(CopyOnWriteArrayWithContiguous));
+                            break;
+                        }
+                    }
+                } else {
+                    setForNode(node, m_graph.globalObjectFor(node->origin.semantic)->originalArrayStructureForIndexingType(CopyOnWriteArrayWithContiguous));
+                    break;
+                }
+            }
+#endif
+            setForNode(node, m_graph.globalObjectFor(node->origin.semantic)->originalArrayStructureForIndexingType(ArrayWithContiguous));
         } else {
             setForNode(node, 
                 m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous));
@@ -2649,8 +2667,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             break;
         }
 
-        setForNode(node, 
-            m_vm.fixedArrayStructure.get());
+        setForNode(node, m_vm.immutableButterflyStructures[arrayIndexFromIndexingType(CopyOnWriteArrayWithContiguous) - NumberOfIndexingShapes].get());
         break;
         
     case NewArrayBuffer:
index f8de95f..7e4a9fe 100644 (file)
@@ -53,7 +53,6 @@
 #include "InByIdStatus.h"
 #include "InstanceOfStatus.h"
 #include "JSCInlines.h"
-#include "JSFixedArray.h"
 #include "JSImmutableButterfly.h"
 #include "JSInternalPromise.h"
 #include "JSInternalPromiseConstructor.h"
index 88efee7..89bc641 100644 (file)
@@ -35,7 +35,6 @@
 #include "DOMJITCallDOMGetterSnippet.h"
 #include "DOMJITSignature.h"
 #include "InlineCallFrame.h"
-#include "JSFixedArray.h"
 #include "JSImmutableButterfly.h"
 
 namespace JSC { namespace DFG {
@@ -1420,8 +1419,8 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
         break;
 
     case NewArrayWithSpread: {
-        // This also reads from JSFixedArray's data store, but we don't have any way of describing that yet.
         read(HeapObjectCount);
+        // This appears to read nothing because it's only reading immutable butterfly data.
         for (unsigned i = 0; i < node->numChildren(); i++) {
             Node* child = graph.varArgChild(node, i).node();
             if (child->op() == PhantomSpread) {
index 3c0b20c..3b165f2 100644 (file)
@@ -857,6 +857,26 @@ private:
                 break;
             }
 
+            case NewArrayWithSpread: {
+                if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
+                    BitVector* bitVector = node->bitVector();
+                    if (node->numChildren() == 1 && bitVector->get(0)) {
+                        Edge use = m_graph.varArgChild(node, 0);
+                        if (use->op() == PhantomSpread) {
+                            if (use->child1()->op() == PhantomNewArrayBuffer) {
+                                auto* immutableButterfly = use->child1()->castOperand<JSImmutableButterfly*>();
+                                if (hasContiguous(immutableButterfly->indexingType())) {
+                                    node->convertToNewArrayBuffer(m_graph.freeze(immutableButterfly));
+                                    changed = true;
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+                break;
+            }
+
             case ToNumber: {
                 if (m_state.forNode(node->child1()).m_type & ~SpecBytecodeNumber)
                     break;
index 0dfe7be..50ca00b 100644 (file)
@@ -54,7 +54,6 @@
 #include "JSAsyncGenerator.h"
 #include "JSBigInt.h"
 #include "JSCInlines.h"
-#include "JSFixedArray.h"
 #include "JSGenericTypedArrayViewConstructorInlines.h"
 #include "JSGlobalObjectFunctions.h"
 #include "JSImmutableButterfly.h"
@@ -3071,8 +3070,8 @@ JSCell* JIT_OPERATION operationNewArrayWithSpreadSlow(JSGlobalObject* globalObje
     Checked<unsigned, RecordOverflow> checkedLength = 0;
     for (unsigned i = 0; i < numItems; i++) {
         JSValue value = JSValue::decode(values[i]);
-        if (JSFixedArray* array = jsDynamicCast<JSFixedArray*>(vm, value))
-            checkedLength += array->size();
+        if (JSImmutableButterfly* array = jsDynamicCast<JSImmutableButterfly*>(vm, value))
+            checkedLength += array->publicLength();
         else
             ++checkedLength;
     }
@@ -3100,9 +3099,9 @@ JSCell* JIT_OPERATION operationNewArrayWithSpreadSlow(JSGlobalObject* globalObje
     unsigned index = 0;
     for (unsigned i = 0; i < numItems; i++) {
         JSValue value = JSValue::decode(values[i]);
-        if (JSFixedArray* array = jsDynamicCast<JSFixedArray*>(vm, value)) {
+        if (JSImmutableButterfly* array = jsDynamicCast<JSImmutableButterfly*>(vm, value)) {
             // We are spreading.
-            for (unsigned i = 0; i < array->size(); i++) {
+            for (unsigned i = 0; i < array->publicLength(); i++) {
                 result->putDirectIndex(globalObject, index, array->get(i));
                 RETURN_IF_EXCEPTION(scope, nullptr);
                 ++index;
@@ -3118,14 +3117,14 @@ JSCell* JIT_OPERATION operationNewArrayWithSpreadSlow(JSGlobalObject* globalObje
     return result;
 }
 
-JSCell* operationCreateFixedArray(JSGlobalObject* globalObject, unsigned length)
+JSCell* operationCreateImmutableButterfly(JSGlobalObject* globalObject, unsigned length)
 {
     VM& vm = globalObject->vm();
     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
     auto scope = DECLARE_THROW_SCOPE(vm);
 
-    if (JSFixedArray* result = JSFixedArray::tryCreate(vm, vm.fixedArrayStructure.get(), length))
+    if (JSImmutableButterfly* result = JSImmutableButterfly::tryCreate(vm, vm.immutableButterflyStructures[arrayIndexFromIndexingType(CopyOnWriteArrayWithContiguous) - NumberOfIndexingShapes].get(), length))
         return result;
 
     throwOutOfMemoryError(globalObject, scope);
@@ -3143,7 +3142,7 @@ JSCell* JIT_OPERATION operationSpreadGeneric(JSGlobalObject* globalObject, JSCel
     if (isJSArray(iterable)) {
         JSArray* array = jsCast<JSArray*>(iterable);
         if (array->isIteratorProtocolFastAndNonObservable())
-            RELEASE_AND_RETURN(throwScope, JSFixedArray::createFromArray(globalObject, vm, array));
+            RELEASE_AND_RETURN(throwScope, JSImmutableButterfly::createFromArray(globalObject, vm, array));
     }
 
     // FIXME: we can probably make this path faster by having our caller JS code call directly into
@@ -3164,7 +3163,7 @@ JSCell* JIT_OPERATION operationSpreadGeneric(JSGlobalObject* globalObject, JSCel
         array = jsCast<JSArray*>(arrayResult);
     }
 
-    RELEASE_AND_RETURN(throwScope, JSFixedArray::createFromArray(globalObject, vm, array));
+    RELEASE_AND_RETURN(throwScope, JSImmutableButterfly::createFromArray(globalObject, vm, array));
 }
 
 JSCell* JIT_OPERATION operationSpreadFastArray(JSGlobalObject* globalObject, JSCell* cell)
@@ -3177,7 +3176,7 @@ JSCell* JIT_OPERATION operationSpreadFastArray(JSGlobalObject* globalObject, JSC
     JSArray* array = jsCast<JSArray*>(cell);
     ASSERT(array->isIteratorProtocolFastAndNonObservable());
 
-    return JSFixedArray::createFromArray(globalObject, vm, array);
+    return JSImmutableButterfly::createFromArray(globalObject, vm, array);
 }
 
 void JIT_OPERATION operationProcessTypeProfilerLogDFG(VM* vmPointer) 
index 93d97bd..7d24d06 100644 (file)
@@ -279,7 +279,7 @@ int32_t JIT_OPERATION operationArrayIndexOfValueInt32OrContiguous(JSGlobalObject
 JSCell* JIT_OPERATION operationSpreadFastArray(JSGlobalObject*, JSCell*);
 JSCell* JIT_OPERATION operationSpreadGeneric(JSGlobalObject*, JSCell*);
 JSCell* JIT_OPERATION operationNewArrayWithSpreadSlow(JSGlobalObject*, void*, uint32_t);
-JSCell* JIT_OPERATION operationCreateFixedArray(JSGlobalObject*, unsigned length);
+JSCell* JIT_OPERATION operationCreateImmutableButterfly(JSGlobalObject*, unsigned length);
 
 JSCell* JIT_OPERATION operationResolveScope(JSGlobalObject*, JSScope*, UniquedStringImpl*);
 EncodedJSValue JIT_OPERATION operationResolveScopeForHoistingFuncDeclInEval(JSGlobalObject*, JSScope*, UniquedStringImpl*);
index 77e9b77..48c28c1 100644 (file)
@@ -54,7 +54,6 @@
 #include "JSAsyncFunction.h"
 #include "JSAsyncGeneratorFunction.h"
 #include "JSCInlines.h"
-#include "JSFixedArray.h"
 #include "JSGeneratorFunction.h"
 #include "JSImmutableButterfly.h"
 #include "JSLexicalEnvironment.h"
@@ -7902,8 +7901,16 @@ void SpeculativeJIT::compileSpread(Node* node)
         FPRReg doubleFPR = doubleRegister.fpr();
 
         MacroAssembler::JumpList slowPath;
+        MacroAssembler::JumpList done;
 
         m_jit.load8(MacroAssembler::Address(argument, JSCell::indexingTypeAndMiscOffset()), scratch1GPR);
+        m_jit.and32(TrustedImm32(IndexingModeMask), scratch1GPR);
+        auto notShareCase = m_jit.branch32(CCallHelpers::NotEqual, scratch1GPR, TrustedImm32(CopyOnWriteArrayWithContiguous));
+        m_jit.loadPtr(MacroAssembler::Address(argument, JSObject::butterflyOffset()), resultGPR);
+        m_jit.addPtr(TrustedImm32(-static_cast<ptrdiff_t>(JSImmutableButterfly::offsetOfData())), resultGPR);
+        done.append(m_jit.jump());
+
+        notShareCase.link(&m_jit);
         m_jit.and32(TrustedImm32(IndexingShapeMask), scratch1GPR);
         m_jit.sub32(TrustedImm32(Int32Shape), scratch1GPR);
 
@@ -7914,15 +7921,14 @@ void SpeculativeJIT::compileSpread(Node* node)
         static_assert(sizeof(JSValue) == 8 && 1 << 3 == 8, "This is strongly assumed in the code below.");
         m_jit.move(lengthGPR, scratch1GPR);
         m_jit.lshift32(TrustedImm32(3), scratch1GPR);
-        m_jit.add32(TrustedImm32(JSFixedArray::offsetOfData()), scratch1GPR);
+        m_jit.add32(TrustedImm32(JSImmutableButterfly::offsetOfData()), scratch1GPR);
 
-        m_jit.emitAllocateVariableSizedCell<JSFixedArray>(vm(), resultGPR, TrustedImmPtr(m_jit.graph().registerStructure(m_jit.graph().m_vm.fixedArrayStructure.get())), scratch1GPR, scratch1GPR, scratch2GPR, slowPath);
-        m_jit.store32(lengthGPR, MacroAssembler::Address(resultGPR, JSFixedArray::offsetOfSize()));
+        m_jit.emitAllocateVariableSizedCell<JSImmutableButterfly>(vm(), resultGPR, TrustedImmPtr(m_jit.graph().registerStructure(m_jit.graph().m_vm.immutableButterflyStructures[arrayIndexFromIndexingType(CopyOnWriteArrayWithContiguous) - NumberOfIndexingShapes].get())), scratch1GPR, scratch1GPR, scratch2GPR, slowPath);
+        m_jit.store32(lengthGPR, MacroAssembler::Address(resultGPR, JSImmutableButterfly::offsetOfPublicLength()));
+        m_jit.store32(lengthGPR, MacroAssembler::Address(resultGPR, JSImmutableButterfly::offsetOfVectorLength()));
 
         m_jit.loadPtr(MacroAssembler::Address(argument, JSObject::butterflyOffset()), scratch1GPR);
 
-        MacroAssembler::JumpList done;
-
         m_jit.load8(MacroAssembler::Address(argument, JSCell::indexingTypeAndMiscOffset()), scratch2GPR);
         m_jit.and32(TrustedImm32(IndexingShapeMask), scratch2GPR);
         auto isDoubleArray = m_jit.branch32(MacroAssembler::Equal, scratch2GPR, TrustedImm32(DoubleShape));
@@ -7935,7 +7941,7 @@ void SpeculativeJIT::compileSpread(Node* node)
             auto notEmpty = m_jit.branchIfNotEmpty(scratch2GPR);
             m_jit.move(TrustedImm64(JSValue::encode(jsUndefined())), scratch2GPR);
             notEmpty.link(&m_jit);
-            m_jit.store64(scratch2GPR, MacroAssembler::BaseIndex(resultGPR, lengthGPR, MacroAssembler::TimesEight, JSFixedArray::offsetOfData()));
+            m_jit.store64(scratch2GPR, MacroAssembler::BaseIndex(resultGPR, lengthGPR, MacroAssembler::TimesEight, JSImmutableButterfly::offsetOfData()));
             m_jit.branchTest32(MacroAssembler::NonZero, lengthGPR).linkTo(loopStart, &m_jit);
             done.append(m_jit.jump());
         }
@@ -7952,7 +7958,7 @@ void SpeculativeJIT::compileSpread(Node* node)
             notEmpty.link(&m_jit);
             m_jit.boxDouble(doubleFPR, scratch2GPR);
             doStore.link(&m_jit);
-            m_jit.store64(scratch2GPR, MacroAssembler::BaseIndex(resultGPR, lengthGPR, MacroAssembler::TimesEight, JSFixedArray::offsetOfData()));
+            m_jit.store64(scratch2GPR, MacroAssembler::BaseIndex(resultGPR, lengthGPR, MacroAssembler::TimesEight, JSImmutableButterfly::offsetOfData()));
             m_jit.branchTest32(MacroAssembler::NonZero, lengthGPR).linkTo(loopStart, &m_jit);
             done.append(m_jit.jump());
         }
@@ -8142,6 +8148,7 @@ void SpeculativeJIT::compileNewArray(Node* node)
 void SpeculativeJIT::compileNewArrayWithSpread(Node* node)
 {
     ASSERT(node->op() == NewArrayWithSpread);
+    JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
 
 #if USE(JSVALUE64)
     if (m_jit.graph().isWatchingHavingABadTimeWatchpoint(node)) {
@@ -8149,6 +8156,36 @@ void SpeculativeJIT::compileNewArrayWithSpread(Node* node)
         GPRReg resultGPR = result.gpr();
 
         BitVector* bitVector = node->bitVector();
+
+        if (node->numChildren() == 1 && bitVector->get(0)) {
+            Edge use = m_jit.graph().varArgChild(node, 0);
+            SpeculateCellOperand immutableButterfly(this, use);
+            GPRTemporary result(this);
+            GPRTemporary butterfly(this);
+            GPRTemporary scratch1(this);
+            GPRTemporary scratch2(this);
+
+            GPRReg immutableButterflyGPR = immutableButterfly.gpr();
+            GPRReg resultGPR = result.gpr();
+            GPRReg butterflyGPR = butterfly.gpr();
+            GPRReg scratch1GPR = scratch1.gpr();
+            GPRReg scratch2GPR = scratch2.gpr();
+
+            RegisteredStructure structure = m_jit.graph().registerStructure(globalObject->originalArrayStructureForIndexingType(CopyOnWriteArrayWithContiguous));
+
+            MacroAssembler::JumpList slowCases;
+
+            m_jit.move(immutableButterflyGPR, butterflyGPR);
+            m_jit.addPtr(TrustedImm32(JSImmutableButterfly::offsetOfData()), butterflyGPR);
+
+            emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(structure), butterflyGPR, scratch1GPR, scratch2GPR, slowCases);
+
+            addSlowPathGenerator(slowPathCall(slowCases, this, operationNewArrayBuffer, resultGPR, &vm(), structure, immutableButterflyGPR));
+
+            cellResult(resultGPR, node);
+            return;
+        }
+
         {
             unsigned startLength = 0;
             for (unsigned i = 0; i < node->numChildren(); ++i) {
@@ -8163,9 +8200,9 @@ void SpeculativeJIT::compileNewArrayWithSpread(Node* node)
             for (unsigned i = 0; i < node->numChildren(); ++i) {
                 if (bitVector->get(i)) {
                     Edge use = m_jit.graph().varArgChild(node, i);
-                    SpeculateCellOperand fixedArray(this, use);
-                    GPRReg fixedArrayGPR = fixedArray.gpr();
-                    speculationCheck(Overflow, JSValueRegs(), nullptr, m_jit.branchAdd32(MacroAssembler::Overflow, MacroAssembler::Address(fixedArrayGPR, JSFixedArray::offsetOfSize()), lengthGPR));
+                    SpeculateCellOperand immutableButterfly(this, use);
+                    GPRReg immutableButterflyGPR = immutableButterfly.gpr();
+                    speculationCheck(Overflow, JSValueRegs(), nullptr, m_jit.branchAdd32(MacroAssembler::Overflow, MacroAssembler::Address(immutableButterflyGPR, JSImmutableButterfly::offsetOfPublicLength()), lengthGPR));
                 }
             }
 
@@ -8176,7 +8213,7 @@ void SpeculativeJIT::compileNewArrayWithSpread(Node* node)
             // ensured above that the spread array length will definitely fit in a
             // non-ArrayStorage shaped array.
             bool shouldAllowForArrayStorageStructureForLargeArrays = false;
-            compileAllocateNewArrayWithSize(m_jit.graph().globalObjectFor(node->origin.semantic), resultGPR, lengthGPR, ArrayWithContiguous, shouldAllowForArrayStorageStructureForLargeArrays);
+            compileAllocateNewArrayWithSize(globalObject, resultGPR, lengthGPR, ArrayWithContiguous, shouldAllowForArrayStorageStructureForLargeArrays);
         }
 
         GPRTemporary index(this);
@@ -8191,30 +8228,30 @@ void SpeculativeJIT::compileNewArrayWithSpread(Node* node)
         for (unsigned i = 0; i < node->numChildren(); ++i) {
             Edge use = m_jit.graph().varArgChild(node, i);
             if (bitVector->get(i)) {
-                SpeculateCellOperand fixedArray(this, use);
-                GPRReg fixedArrayGPR = fixedArray.gpr();
+                SpeculateCellOperand immutableButterfly(this, use);
+                GPRReg immutableButterflyGPR = immutableButterfly.gpr();
 
-                GPRTemporary fixedIndex(this);
-                GPRReg fixedIndexGPR = fixedIndex.gpr();
+                GPRTemporary immutableButterflyIndex(this);
+                GPRReg immutableButterflyIndexGPR = immutableButterflyIndex.gpr();
 
                 GPRTemporary item(this);
                 GPRReg itemGPR = item.gpr();
 
-                GPRTemporary fixedLength(this);
-                GPRReg fixedLengthGPR = fixedLength.gpr();
+                GPRTemporary immutableButterflyLength(this);
+                GPRReg immutableButterflyLengthGPR = immutableButterflyLength.gpr();
 
-                m_jit.load32(MacroAssembler::Address(fixedArrayGPR, JSFixedArray::offsetOfSize()), fixedLengthGPR);
-                m_jit.move(TrustedImm32(0), fixedIndexGPR);
-                auto done = m_jit.branchPtr(MacroAssembler::AboveOrEqual, fixedIndexGPR, fixedLengthGPR);
+                m_jit.load32(MacroAssembler::Address(immutableButterflyGPR, JSImmutableButterfly::offsetOfPublicLength()), immutableButterflyLengthGPR);
+                m_jit.move(TrustedImm32(0), immutableButterflyIndexGPR);
+                auto done = m_jit.branchPtr(MacroAssembler::AboveOrEqual, immutableButterflyIndexGPR, immutableButterflyLengthGPR);
                 auto loopStart = m_jit.label();
                 m_jit.load64(
-                    MacroAssembler::BaseIndex(fixedArrayGPR, fixedIndexGPR, MacroAssembler::TimesEight, JSFixedArray::offsetOfData()),
+                    MacroAssembler::BaseIndex(immutableButterflyGPR, immutableButterflyIndexGPR, MacroAssembler::TimesEight, JSImmutableButterfly::offsetOfData()),
                     itemGPR);
 
                 m_jit.store64(itemGPR, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight));
-                m_jit.addPtr(TrustedImm32(1), fixedIndexGPR);
+                m_jit.addPtr(TrustedImm32(1), immutableButterflyIndexGPR);
                 m_jit.addPtr(TrustedImm32(1), indexGPR);
-                m_jit.branchPtr(MacroAssembler::Below, fixedIndexGPR, fixedLengthGPR).linkTo(loopStart, &m_jit);
+                m_jit.branchPtr(MacroAssembler::Below, immutableButterflyIndexGPR, immutableButterflyLengthGPR).linkTo(loopStart, &m_jit);
 
                 done.link(&m_jit);
             } else {
@@ -8239,13 +8276,13 @@ void SpeculativeJIT::compileNewArrayWithSpread(Node* node)
     for (unsigned i = 0; i < node->numChildren(); ++i) {
         Edge use = m_jit.graph().m_varArgChildren[node->firstChild() + i];
         if (bitVector->get(i)) {
-            SpeculateCellOperand fixedArray(this, use);
-            GPRReg arrayGPR = fixedArray.gpr();
+            SpeculateCellOperand immutableButterfly(this, use);
+            GPRReg immutableButterflyGPR = immutableButterfly.gpr();
 #if USE(JSVALUE64)
-            m_jit.store64(arrayGPR, &buffer[i]);
+            m_jit.store64(immutableButterflyGPR, &buffer[i]);
 #else
             char* pointer = static_cast<char*>(static_cast<void*>(&buffer[i]));
-            m_jit.store32(arrayGPR, pointer + PayloadOffset);
+            m_jit.store32(immutableButterflyGPR, pointer + PayloadOffset);
             m_jit.store32(TrustedImm32(JSValue::CellTag), pointer + TagOffset);
 #endif
         } else {
@@ -8266,7 +8303,7 @@ void SpeculativeJIT::compileNewArrayWithSpread(Node* node)
     GPRFlushedCallResult result(this);
     GPRReg resultGPR = result.gpr();
 
-    callOperation(operationNewArrayWithSpreadSlow, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), buffer, node->numChildren());
+    callOperation(operationNewArrayWithSpreadSlow, resultGPR, TrustedImmPtr::weakPointer(m_graph, globalObject), buffer, node->numChildren());
     m_jit.exceptionCheck();
     {
         GPRTemporary scratch(this);
@@ -12613,7 +12650,7 @@ void SpeculativeJIT::compileObjectKeys(Node* node)
             RegisteredStructure arrayStructure = m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(CopyOnWriteArrayWithContiguous));
 
             m_jit.move(scratchGPR, scratch3GPR);
-            m_jit.addPtr(TrustedImmPtr(JSImmutableButterfly::offsetOfData()), scratchGPR);
+            m_jit.addPtr(TrustedImm32(JSImmutableButterfly::offsetOfData()), scratchGPR);
 
             emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(arrayStructure), scratchGPR, structureGPR, scratch2GPR, slowButArrayBufferCases);
 
index 8740572..f9b95a6 100644 (file)
@@ -32,7 +32,6 @@
 #include "FTLAbstractHeap.h"
 #include "HasOwnPropertyCache.h"
 #include "IndexingType.h"
-#include "JSFixedArray.h"
 #include "JSGlobalObject.h"
 #include "JSMap.h"
 #include "JSSet.h"
@@ -162,7 +161,6 @@ namespace JSC { namespace FTL {
     macro(WeakMapBucket_value, WeakMapBucket<WeakMapBucketDataKeyValue>::offsetOfValue()) \
     macro(WeakMapBucket_key, WeakMapBucket<WeakMapBucketDataKeyValue>::offsetOfKey()) \
     macro(Symbol_symbolImpl, Symbol::offsetOfSymbolImpl()) \
-    macro(JSFixedArray_size, JSFixedArray::offsetOfSize()) \
 
 #define FOR_EACH_INDEXED_ABSTRACT_HEAP(macro) \
     macro(ArrayStorage_vector, ArrayStorage::vectorOffset(), sizeof(WriteBarrier<Unknown>)) \
@@ -183,7 +181,6 @@ namespace JSC { namespace FTL {
     macro(structureTable, 0, sizeof(Structure*)) \
     macro(variables, 0, sizeof(Register)) \
     macro(HasOwnPropertyCache, 0, sizeof(HasOwnPropertyCache::Entry)) \
-    macro(JSFixedArray_buffer, JSFixedArray::offsetOfData(), sizeof(EncodedJSValue)) \
     
 #define FOR_EACH_NUMBERED_ABSTRACT_HEAP(macro) \
     macro(properties)
index 2f4e096..c2ddada 100644 (file)
@@ -6290,6 +6290,57 @@ private:
             BitVector* bitVector = m_node->bitVector();
             HashMap<InlineCallFrame*, LValue, WTF::DefaultHash<InlineCallFrame*>::Hash, WTF::NullableHashTraits<InlineCallFrame*>> cachedSpreadLengths;
 
+            if (m_node->numChildren() == 1 && bitVector->get(0)) {
+                Edge use = m_graph.varArgChild(m_node, 0);
+                if (use->op() == PhantomSpread) {
+                    if (use->child1()->op() == PhantomNewArrayBuffer) {
+                        auto* immutableButterfly = use->child1()->castOperand<JSImmutableButterfly*>();
+                        if (hasContiguous(immutableButterfly->indexingType())) {
+                            RegisteredStructure structure = m_graph.registerStructure(globalObject->originalArrayStructureForIndexingType(CopyOnWriteArrayWithContiguous));
+                            LBasicBlock slowPath = m_out.newBlock();
+                            LBasicBlock continuation = m_out.newBlock();
+
+                            LValue fastArray = allocateObject<JSArray>(structure, m_out.constIntPtr(immutableButterfly->toButterfly()), slowPath);
+                            ValueFromBlock fastResult = m_out.anchor(fastArray);
+                            m_out.jump(continuation);
+
+                            m_out.appendTo(slowPath, continuation);
+                            LValue slowArray = vmCall(Int64, operationNewArrayBuffer, m_vmValue, weakStructure(structure), frozenPointer(use->child1()->cellOperand()));
+                            ValueFromBlock slowResult = m_out.anchor(slowArray);
+                            m_out.jump(continuation);
+
+                            m_out.appendTo(continuation);
+
+                            mutatorFence();
+                            setJSValue(m_out.phi(pointerType(), slowResult, fastResult));
+                            return;
+                        }
+                    }
+                } else {
+                    // If a node is producing JSImmutableButterfly, it must be contiguous.
+                    LValue immutableButterfly = lowCell(use);
+
+                    RegisteredStructure structure = m_graph.registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(CopyOnWriteArrayWithContiguous));
+                    LBasicBlock slowPath = m_out.newBlock();
+                    LBasicBlock continuation = m_out.newBlock();
+
+                    LValue fastArray = allocateObject<JSArray>(structure, toButterfly(immutableButterfly), slowPath);
+                    ValueFromBlock fastResult = m_out.anchor(fastArray);
+                    m_out.jump(continuation);
+
+                    m_out.appendTo(slowPath, continuation);
+                    LValue slowArray = vmCall(Int64, operationNewArrayBuffer, m_vmValue, weakStructure(structure), immutableButterfly);
+                    ValueFromBlock slowResult = m_out.anchor(slowArray);
+                    m_out.jump(continuation);
+
+                    m_out.appendTo(continuation);
+
+                    mutatorFence();
+                    setJSValue(m_out.phi(pointerType(), slowResult, fastResult));
+                    return;
+                }
+            }
+
             for (unsigned i = 0; i < m_node->numChildren(); ++i) {
                 if (!bitVector->get(i))
                     ++startLength;
@@ -6321,8 +6372,8 @@ private:
                             lengthCheck = m_out.speculateAdd(length, spreadLength);
                         }
                     } else {
-                        LValue fixedArray = lowCell(use);
-                        lengthCheck = m_out.speculateAdd(length, m_out.load32(fixedArray, m_heaps.JSFixedArray_size));
+                        LValue immutableButterfly = lowCell(use);
+                        lengthCheck = m_out.speculateAdd(length, m_out.load32(toButterfly(immutableButterfly), m_heaps.Butterfly_publicLength));
                     }
 
                     if (lengthCheck) {
@@ -6400,35 +6451,36 @@ private:
                         LBasicBlock loopStart = m_out.newBlock();
                         LBasicBlock continuation = m_out.newBlock();
 
-                        LValue fixedArray = lowCell(use);
+                        LValue immutableButterfly = lowCell(use);
+                        LValue immutableButterflyStorage = toButterfly(immutableButterfly);
 
-                        ValueFromBlock fixedIndexStart = m_out.anchor(m_out.constIntPtr(0));
+                        ValueFromBlock immutableButterflyIndexStart = m_out.anchor(m_out.constIntPtr(0));
                         ValueFromBlock arrayIndexStart = m_out.anchor(index);
                         ValueFromBlock arrayIndexStartForFinish = m_out.anchor(index);
 
-                        LValue fixedArraySize = m_out.zeroExtPtr(m_out.load32(fixedArray, m_heaps.JSFixedArray_size));
+                        LValue immutableButterflySize = m_out.zeroExtPtr(m_out.load32(immutableButterflyStorage, m_heaps.Butterfly_publicLength));
 
                         m_out.branch(
-                            m_out.isZero64(fixedArraySize),
+                            m_out.isZero64(immutableButterflySize),
                             unsure(continuation), unsure(loopStart));
 
                         LBasicBlock lastNext = m_out.appendTo(loopStart, continuation);
 
                         LValue arrayIndex = m_out.phi(pointerType(), arrayIndexStart);
-                        LValue fixedArrayIndex = m_out.phi(pointerType(), fixedIndexStart);
+                        LValue immutableButterflyIndex = m_out.phi(pointerType(), immutableButterflyIndexStart);
 
-                        LValue item = m_out.load64(m_out.baseIndex(m_heaps.JSFixedArray_buffer, fixedArray, fixedArrayIndex));
+                        LValue item = m_out.load64(m_out.baseIndex(m_heaps.indexedContiguousProperties, immutableButterflyStorage, immutableButterflyIndex));
                         m_out.store64(item, m_out.baseIndex(m_heaps.indexedContiguousProperties, storage, arrayIndex));
 
                         LValue nextArrayIndex = m_out.add(arrayIndex, m_out.constIntPtr(1));
-                        LValue nextFixedArrayIndex = m_out.add(fixedArrayIndex, m_out.constIntPtr(1));
+                        LValue nextImmutableButterflyIndex = m_out.add(immutableButterflyIndex, m_out.constIntPtr(1));
                         ValueFromBlock arrayIndexLoopForFinish = m_out.anchor(nextArrayIndex);
 
-                        m_out.addIncomingToPhi(fixedArrayIndex, m_out.anchor(nextFixedArrayIndex));
+                        m_out.addIncomingToPhi(immutableButterflyIndex, m_out.anchor(nextImmutableButterflyIndex));
                         m_out.addIncomingToPhi(arrayIndex, m_out.anchor(nextArrayIndex));
 
                         m_out.branch(
-                            m_out.below(nextFixedArrayIndex, fixedArraySize),
+                            m_out.below(nextImmutableButterflyIndex, immutableButterflySize),
                             unsure(loopStart), unsure(continuation));
 
                         m_out.appendTo(continuation, lastNext);
@@ -6627,34 +6679,44 @@ private:
     {
         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
         if (m_node->child1()->op() == PhantomNewArrayBuffer) {
-            LBasicBlock slowAllocation = m_out.newBlock();
-            LBasicBlock continuation = m_out.newBlock();
+            ASSERT(m_graph.isWatchingHavingABadTimeWatchpoint(m_node->child1().node()));
 
+            // FIXME: JSImmutableButterfly::createFromArray should support re-using non contiguous indexing types as well.
             auto* immutableButterfly = m_node->child1()->castOperand<JSImmutableButterfly*>();
+            if (hasContiguous(immutableButterfly->indexingType())) {
+                setJSValue(frozenPointer(m_node->child1()->cellOperand()));
+                return;
+            }
+
+            LBasicBlock slowAllocation = m_out.newBlock();
+            LBasicBlock continuation = m_out.newBlock();
 
-            LValue fastFixedArrayValue = allocateVariableSizedCell<JSFixedArray>(
-                m_out.constIntPtr(JSFixedArray::allocationSize(immutableButterfly->length()).unsafeGet()),
-                m_graph.m_vm.fixedArrayStructure.get(), slowAllocation);
-            m_out.store32(m_out.constInt32(immutableButterfly->length()), fastFixedArrayValue, m_heaps.JSFixedArray_size);
-            ValueFromBlock fastFixedArray = m_out.anchor(fastFixedArrayValue);
+            LValue fastImmutableButterflyValue = allocateVariableSizedCell<JSImmutableButterfly>(
+                m_out.constIntPtr(JSImmutableButterfly::allocationSize(immutableButterfly->length()).unsafeGet()),
+                m_graph.m_vm.immutableButterflyStructures[arrayIndexFromIndexingType(CopyOnWriteArrayWithContiguous) - NumberOfIndexingShapes].get(), slowAllocation);
+            LValue fastImmutableButterflyStorage = toButterfly(fastImmutableButterflyValue);
+            m_out.store32(m_out.constInt32(immutableButterfly->length()), fastImmutableButterflyStorage, m_heaps.Butterfly_publicLength);
+            m_out.store32(m_out.constInt32(immutableButterfly->length()), fastImmutableButterflyStorage, m_heaps.Butterfly_vectorLength);
+            ValueFromBlock fastImmutableButterfly = m_out.anchor(fastImmutableButterflyValue);
             m_out.jump(continuation);
 
             LBasicBlock lastNext = m_out.appendTo(slowAllocation, continuation);
-            ValueFromBlock slowFixedArray = m_out.anchor(vmCall(pointerType(), operationCreateFixedArray, weakPointer(globalObject), m_out.constInt32(immutableButterfly->length())));
+            ValueFromBlock slowImmutableButterfly = m_out.anchor(vmCall(pointerType(), operationCreateImmutableButterfly, weakPointer(globalObject), m_out.constInt32(immutableButterfly->length())));
             m_out.jump(continuation);
 
             m_out.appendTo(continuation, lastNext);
-            LValue fixedArray = m_out.phi(pointerType(), fastFixedArray, slowFixedArray);
+            LValue immutableButterflyValue = m_out.phi(pointerType(), fastImmutableButterfly, slowImmutableButterfly);
+            LValue immutableButterflyStorage = toButterfly(immutableButterflyValue);
             for (unsigned i = 0; i < immutableButterfly->length(); i++) {
                 // Because forwarded values are drained as JSValue, we should not generate value
                 // in Double form even if PhantomNewArrayBuffer's indexingType is ArrayWithDouble.
                 int64_t value = JSValue::encode(immutableButterfly->get(i));
                 m_out.store64(
                     m_out.constInt64(value),
-                    m_out.baseIndex(m_heaps.JSFixedArray_buffer, fixedArray, m_out.constIntPtr(i), jsNumber(i)));
+                    m_out.baseIndex(m_heaps.indexedContiguousProperties, immutableButterflyStorage, m_out.constIntPtr(i), jsNumber(i)));
             }
             mutatorFence();
-            setJSValue(fixedArray);
+            setJSValue(immutableButterflyValue);
             return;
         }
 
@@ -6664,6 +6726,9 @@ private:
             // accept Spread's result as input. This usually leads to the Spread node not
             // escaping. However, this can happen if for example we generate a PutStack on
             // the Spread but nothing escapes the CreateRest.
+
+            ASSERT(m_graph.isWatchingHavingABadTimeWatchpoint(m_node->child1().node()));
+
             LBasicBlock loopHeader = m_out.newBlock();
             LBasicBlock loopBody = m_out.newBlock();
             LBasicBlock slowAllocation = m_out.newBlock();
@@ -6677,19 +6742,22 @@ private:
             static_assert(sizeof(JSValue) == 8 && 1 << 3 == 8, "Assumed in the code below.");
             LValue size = m_out.add(
                 m_out.shl(m_out.zeroExtPtr(length), m_out.constInt32(3)),
-                m_out.constIntPtr(JSFixedArray::offsetOfData()));
+                m_out.constIntPtr(JSImmutableButterfly::offsetOfData()));
 
-            LValue fastArrayValue = allocateVariableSizedCell<JSFixedArray>(size, m_graph.m_vm.fixedArrayStructure.get(), slowAllocation);
-            m_out.store32(length, fastArrayValue, m_heaps.JSFixedArray_size);
+            LValue fastArrayValue = allocateVariableSizedCell<JSImmutableButterfly>(size, m_graph.m_vm.immutableButterflyStructures[arrayIndexFromIndexingType(CopyOnWriteArrayWithContiguous) - NumberOfIndexingShapes].get(), slowAllocation);
+            LValue fastArrayStorage = toButterfly(fastArrayValue);
+            m_out.store32(length, fastArrayStorage, m_heaps.Butterfly_vectorLength);
+            m_out.store32(length, fastArrayStorage, m_heaps.Butterfly_publicLength);
             ValueFromBlock fastArray = m_out.anchor(fastArrayValue);
             m_out.jump(loopHeader);
 
             m_out.appendTo(slowAllocation, loopHeader);
-            ValueFromBlock slowArray = m_out.anchor(vmCall(pointerType(), operationCreateFixedArray, weakPointer(globalObject), length));
+            ValueFromBlock slowArray = m_out.anchor(vmCall(pointerType(), operationCreateImmutableButterfly, weakPointer(globalObject), length));
             m_out.jump(loopHeader);
 
             m_out.appendTo(loopHeader, loopBody);
-            LValue fixedArray = m_out.phi(pointerType(), fastArray, slowArray);
+            LValue immutableButterfly = m_out.phi(pointerType(), fastArray, slowArray);
+            LValue immutableButterflyStorage = toButterfly(immutableButterfly);
             ValueFromBlock startIndex = m_out.anchor(m_out.constIntPtr(0));
             m_out.branch(m_out.isZero32(length), unsure(continuation), unsure(loopBody));
 
@@ -6697,14 +6765,14 @@ private:
             LValue index = m_out.phi(pointerType(), startIndex);
             LValue value = m_out.load64(
                 m_out.baseIndex(m_heaps.variables, sourceStart, index));
-            m_out.store64(value, m_out.baseIndex(m_heaps.JSFixedArray_buffer, fixedArray, index));
+            m_out.store64(value, m_out.baseIndex(m_heaps.indexedContiguousProperties, immutableButterflyStorage, index));
             LValue nextIndex = m_out.add(m_out.constIntPtr(1), index);
             m_out.addIncomingToPhi(index, m_out.anchor(nextIndex));
             m_out.branch(m_out.below(nextIndex, m_out.zeroExtPtr(length)), unsure(loopBody), unsure(continuation));
 
             m_out.appendTo(continuation, lastNext);
             mutatorFence();
-            setJSValue(fixedArray);
+            setJSValue(immutableButterfly);
             return;
         }
 
@@ -6716,6 +6784,8 @@ private:
             speculateArray(m_node->child1());
 
         if (m_graph.canDoFastSpread(m_node, m_state.forNode(m_node->child1()))) {
+            LBasicBlock copyOnWriteContiguousCheck = m_out.newBlock();
+            LBasicBlock copyOnWritePropagation = m_out.newBlock();
             LBasicBlock preLoop = m_out.newBlock();
             LBasicBlock loopSelection = m_out.newBlock();
             LBasicBlock contiguousLoopStart = m_out.newBlock();
@@ -6723,25 +6793,33 @@ private:
             LBasicBlock slowPath = m_out.newBlock();
             LBasicBlock continuation = m_out.newBlock();
 
-            LValue indexingShape = m_out.load8ZeroExt32(argument, m_heaps.JSCell_indexingTypeAndMisc);
-            indexingShape = m_out.bitAnd(indexingShape, m_out.constInt32(IndexingShapeMask));
+            LValue indexingMode = m_out.load8ZeroExt32(argument, m_heaps.JSCell_indexingTypeAndMisc);
+            LValue indexingShape = m_out.bitAnd(indexingMode, m_out.constInt32(IndexingShapeMask));
             LValue isOKIndexingType = m_out.belowOrEqual(
                 m_out.sub(indexingShape, m_out.constInt32(Int32Shape)),
                 m_out.constInt32(ContiguousShape - Int32Shape));
 
-            m_out.branch(isOKIndexingType, unsure(preLoop), unsure(slowPath));
-            LBasicBlock lastNext = m_out.appendTo(preLoop, loopSelection);
-
+            m_out.branch(isOKIndexingType, unsure(copyOnWriteContiguousCheck), unsure(slowPath));
+            LBasicBlock lastNext = m_out.appendTo(copyOnWriteContiguousCheck, copyOnWritePropagation);
             LValue butterfly = m_out.loadPtr(argument, m_heaps.JSObject_butterfly);
+            m_out.branch(m_out.equal(m_out.bitAnd(indexingMode, m_out.constInt32(IndexingModeMask)), m_out.constInt32(CopyOnWriteArrayWithContiguous)), unsure(copyOnWritePropagation), unsure(preLoop));
+
+            m_out.appendTo(copyOnWritePropagation, preLoop);
+            ValueFromBlock sharedResult = m_out.anchor(m_out.add(butterfly, m_out.constIntPtr(-JSImmutableButterfly::offsetOfData())));
+            m_out.jump(continuation);
+
+            m_out.appendTo(preLoop, loopSelection);
             LValue length = m_out.load32NonNegative(butterfly, m_heaps.Butterfly_publicLength);
             static_assert(sizeof(JSValue) == 8 && 1 << 3 == 8, "Assumed in the code below.");
             LValue size = m_out.add(
                 m_out.shl(m_out.zeroExtPtr(length), m_out.constInt32(3)),
-                m_out.constIntPtr(JSFixedArray::offsetOfData()));
+                m_out.constIntPtr(JSImmutableButterfly::offsetOfData()));
 
-            LValue fastAllocation = allocateVariableSizedCell<JSFixedArray>(size, m_graph.m_vm.fixedArrayStructure.get(), slowPath);
+            LValue fastAllocation = allocateVariableSizedCell<JSImmutableButterfly>(size, m_graph.m_vm.immutableButterflyStructures[arrayIndexFromIndexingType(CopyOnWriteArrayWithContiguous) - NumberOfIndexingShapes].get(), slowPath);
+            LValue fastStorage = toButterfly(fastAllocation);
+            m_out.store32(length, fastStorage, m_heaps.Butterfly_vectorLength);
+            m_out.store32(length, fastStorage, m_heaps.Butterfly_publicLength);
             ValueFromBlock fastResult = m_out.anchor(fastAllocation);
-            m_out.store32(length, fastAllocation, m_heaps.JSFixedArray_size);
 
             ValueFromBlock startIndexForContiguous = m_out.anchor(m_out.constIntPtr(0));
             ValueFromBlock startIndexForDouble = m_out.anchor(m_out.constIntPtr(0));
@@ -6759,7 +6837,7 @@ private:
                 TypedPointer loadSite = m_out.baseIndex(m_heaps.root, butterfly, index, ScaleEight); // We read TOP here since we can be reading either int32 or contiguous properties.
                 LValue value = m_out.load64(loadSite);
                 value = m_out.select(m_out.isZero64(value), m_out.constInt64(JSValue::encode(jsUndefined())), value);
-                m_out.store64(value, m_out.baseIndex(m_heaps.JSFixedArray_buffer, fastAllocation, index));
+                m_out.store64(value, m_out.baseIndex(m_heaps.indexedContiguousProperties, fastStorage, index));
 
                 LValue nextIndex = m_out.add(index, m_out.constIntPtr(1));
                 m_out.addIncomingToPhi(index, m_out.anchor(nextIndex));
@@ -6777,7 +6855,7 @@ private:
                 LValue holeResult = m_out.constInt64(JSValue::encode(jsUndefined()));
                 LValue normalResult = boxDouble(value);
                 value = m_out.select(isNaN, holeResult, normalResult);
-                m_out.store64(value, m_out.baseIndex(m_heaps.JSFixedArray_buffer, fastAllocation, index));
+                m_out.store64(value, m_out.baseIndex(m_heaps.indexedContiguousProperties, fastStorage, index));
 
                 LValue nextIndex = m_out.add(index, m_out.constIntPtr(1));
                 m_out.addIncomingToPhi(index, m_out.anchor(nextIndex));
@@ -6791,7 +6869,7 @@ private:
             m_out.jump(continuation);
 
             m_out.appendTo(continuation, lastNext);
-            result = m_out.phi(pointerType(), fastResult, slowResult);
+            result = m_out.phi(pointerType(), sharedResult, fastResult, slowResult);
             mutatorFence();
         } else
             result = vmCall(pointerType(), operationSpreadGeneric, weakPointer(globalObject), argument);
@@ -18004,6 +18082,11 @@ private:
         patchpoint->setGenerator([=] (CCallHelpers&, const StackmapGenerationParams&) { });
     }
 
+    LValue toButterfly(LValue immutableButterfly)
+    {
+        return m_out.addPtr(immutableButterfly, JSImmutableButterfly::offsetOfData());
+    }
+
     void addWeakReference(JSCell* target)
     {
         m_graph.m_plan.weakReferences().addLazily(target);
index 829d2ba..7f7cd38 100644 (file)
@@ -40,7 +40,6 @@
 #include "JSAsyncFunction.h"
 #include "JSAsyncGeneratorFunction.h"
 #include "JSCInlines.h"
-#include "JSFixedArray.h"
 #include "JSGeneratorFunction.h"
 #include "JSImmutableButterfly.h"
 #include "JSLexicalEnvironment.h"
@@ -456,11 +455,11 @@ extern "C" JSCell* JIT_OPERATION operationMaterializeObjectInOSR(JSGlobalObject*
         }
         RELEASE_ASSERT(array);
 
-        // Note: it is sound for JSFixedArray::createFromArray to call getDirectIndex here
+        // Note: it is sound for JSImmutableButterfly::createFromArray to call getDirectIndex here
         // because we're guaranteed we won't be calling any getters. The reason for this is
         // that we only support PhantomSpread over CreateRest, which is an array we create.
         // Any attempts to put a getter on any indices on the rest array will escape the array.
-        JSFixedArray* fixedArray = JSFixedArray::createFromArray(globalObject, vm, array);
+        auto* fixedArray = JSImmutableButterfly::createFromArray(globalObject, vm, array);
         RELEASE_ASSERT(fixedArray);
         return fixedArray;
     }
@@ -528,8 +527,8 @@ extern "C" JSCell* JIT_OPERATION operationMaterializeObjectInOSR(JSGlobalObject*
             if (property.location().kind() == NewArrayWithSpreadArgumentPLoc) {
                 ++numProperties;
                 JSValue value = JSValue::decode(values[i]);
-                if (JSFixedArray* fixedArray = jsDynamicCast<JSFixedArray*>(vm, value))
-                    checkedArraySize += fixedArray->size();
+                if (JSImmutableButterfly* immutableButterfly = jsDynamicCast<JSImmutableButterfly*>(vm, value))
+                    checkedArraySize += immutableButterfly->publicLength();
                 else
                     checkedArraySize += 1;
             }
@@ -570,10 +569,10 @@ extern "C" JSCell* JIT_OPERATION operationMaterializeObjectInOSR(JSGlobalObject*
 
         unsigned arrayIndex = 0;
         for (JSValue value : arguments) {
-            if (JSFixedArray* fixedArray = jsDynamicCast<JSFixedArray*>(vm, value)) {
-                for (unsigned i = 0; i < fixedArray->size(); i++) {
-                    ASSERT(fixedArray->get(i));
-                    result->putDirectIndex(globalObject, arrayIndex, fixedArray->get(i));
+            if (JSImmutableButterfly* immutableButterfly = jsDynamicCast<JSImmutableButterfly*>(vm, value)) {
+                for (unsigned i = 0; i < immutableButterfly->publicLength(); i++) {
+                    ASSERT(immutableButterfly->get(i));
+                    result->putDirectIndex(globalObject, arrayIndex, immutableButterfly->get(i));
                     ++arrayIndex;
                 }
             } else {
index 9c1cc42..e7a3d22 100644 (file)
@@ -53,7 +53,6 @@
 #include "JSArrayInlines.h"
 #include "JSBoundFunction.h"
 #include "JSCInlines.h"
-#include "JSFixedArray.h"
 #include "JSImmutableButterfly.h"
 #include "JSLexicalEnvironment.h"
 #include "JSModuleEnvironment.h"
@@ -198,9 +197,6 @@ unsigned sizeOfVarargs(JSGlobalObject* globalObject, JSValue arguments, uint32_t
     case ScopedArgumentsType:
         length = jsCast<ScopedArguments*>(cell)->length(globalObject);
         break;
-    case JSFixedArrayType:
-        length = jsCast<JSFixedArray*>(cell)->size();
-        break;
     case JSImmutableButterflyType:
         length = jsCast<JSImmutableButterfly*>(cell)->length();
         break;
@@ -271,10 +267,6 @@ void loadVarargs(JSGlobalObject* globalObject, CallFrame* callFrame, VirtualRegi
         scope.release();
         jsCast<ScopedArguments*>(cell)->copyToArguments(globalObject, callFrame, firstElementDest, offset, length);
         return;
-    case JSFixedArrayType:
-        scope.release();
-        jsCast<JSFixedArray*>(cell)->copyToArguments(globalObject, callFrame, firstElementDest, offset, length);
-        return;
     case JSImmutableButterflyType:
         scope.release();
         jsCast<JSImmutableButterfly*>(cell)->copyToArguments(globalObject, callFrame, firstElementDest, offset, length);
index ab1889d..f358d48 100644 (file)
@@ -49,7 +49,6 @@
 #include "JSAsyncGenerator.h"
 #include "JSCInlines.h"
 #include "JSCJSValue.h"
-#include "JSFixedArray.h"
 #include "JSGlobalObjectFunctions.h"
 #include "JSImmutableButterfly.h"
 #include "JSInternalPromise.h"
@@ -1367,12 +1366,20 @@ SLOW_PATH_DECL(slow_path_new_array_with_spread)
 
     JSValue* values = bitwise_cast<JSValue*>(&GET(bytecode.m_argv));
 
+    if (numItems == 1 && bitVector.get(0)) {
+        Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(CopyOnWriteArrayWithContiguous);
+        if (isCopyOnWrite(structure->indexingMode())) {
+            JSArray* result = CommonSlowPaths::allocateNewArrayBuffer(vm, structure, jsCast<JSImmutableButterfly*>(values[0]));
+            RETURN(result);
+        }
+    }
+
     Checked<unsigned, RecordOverflow> checkedArraySize = 0;
     for (int i = 0; i < numItems; i++) {
         if (bitVector.get(i)) {
             JSValue value = values[-i];
-            JSFixedArray* array = jsCast<JSFixedArray*>(value);
-            checkedArraySize += array->size();
+            JSImmutableButterfly* array = jsCast<JSImmutableButterfly*>(value);
+            checkedArraySize += array->publicLength();
         } else
             checkedArraySize += 1;
     }
@@ -1395,8 +1402,8 @@ SLOW_PATH_DECL(slow_path_new_array_with_spread)
         JSValue value = values[-i];
         if (bitVector.get(i)) {
             // We are spreading.
-            JSFixedArray* array = jsCast<JSFixedArray*>(value);
-            for (unsigned i = 0; i < array->size(); i++) {
+            JSImmutableButterfly* array = jsCast<JSImmutableButterfly*>(value);
+            for (unsigned i = 0; i < array->publicLength(); i++) {
                 RELEASE_ASSERT(array->get(i));
                 result->putDirectIndex(globalObject, index, array->get(i));
                 CHECK_EXCEPTION();
@@ -1456,10 +1463,10 @@ SLOW_PATH_DECL(slow_path_spread)
     if (iterable.isCell() && isJSArray(iterable.asCell())) {
         JSArray* array = jsCast<JSArray*>(iterable);
         if (array->isIteratorProtocolFastAndNonObservable()) {
-            // JSFixedArray::createFromArray does not consult the prototype chain,
+            // JSImmutableButterfly::createFromArray does not consult the prototype chain,
             // so we must be sure that not consulting the prototype chain would
             // produce the same value during iteration.
-            RETURN(JSFixedArray::createFromArray(globalObject, vm, array));
+            RETURN(JSImmutableButterfly::createFromArray(globalObject, vm, array));
         }
     }
 
@@ -1478,7 +1485,7 @@ SLOW_PATH_DECL(slow_path_spread)
         array = jsCast<JSArray*>(arrayResult);
     }
 
-    RETURN(JSFixedArray::createFromArray(globalObject, vm, array));
+    RETURN(JSImmutableButterfly::createFromArray(globalObject, vm, array));
 }
 
 } // namespace JSC
index 6d854a9..f8f3a4f 100644 (file)
@@ -47,7 +47,7 @@ inline To jsCast(JSValue from)
 
 // Specific type overloads.
 #define FOR_EACH_JS_DYNAMIC_CAST_JS_TYPE_OVERLOAD(macro) \
-    macro(JSFixedArray, JSType::JSFixedArrayType, JSType::JSFixedArrayType) \
+    macro(JSImmutableButterfly, JSType::JSImmutableButterflyType, JSType::JSImmutableButterflyType) \
     macro(JSObject, FirstObjectType, LastObjectType) \
     macro(JSFinalObject, JSType::FinalObjectType, JSType::FinalObjectType) \
     macro(JSFunction, JSType::JSFunctionType, JSType::JSFunctionType) \
diff --git a/Source/JavaScriptCore/runtime/JSFixedArray.cpp b/Source/JavaScriptCore/runtime/JSFixedArray.cpp
deleted file mode 100644 (file)
index 28cb28e..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2016-2019 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
- */
-
-#include "config.h"
-#include "JSFixedArray.h"
-
-#include "CodeBlock.h"
-#include "JSCInlines.h"
-#include <wtf/CommaPrinter.h>
-
-namespace JSC {
-
-const ClassInfo JSFixedArray::s_info = { "JSFixedArray", nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(JSFixedArray) };
-
-void JSFixedArray::visitChildren(JSCell* cell, SlotVisitor& visitor)
-{
-    JSFixedArray* thisObject = jsCast<JSFixedArray*>(cell);
-    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
-    Base::visitChildren(thisObject, visitor);
-    visitor.appendValuesHidden(thisObject->buffer(), thisObject->size());
-}
-
-void JSFixedArray::copyToArguments(JSGlobalObject*, CallFrame* callFrame, VirtualRegister firstElementDest, unsigned offset, unsigned length)
-{
-    for (unsigned i = 0; i < length; ++i) {
-        if ((i + offset) < m_size)
-            callFrame->r(firstElementDest + i) = get(i + offset);
-        else
-            callFrame->r(firstElementDest + i) = jsUndefined();
-    }
-}
-
-void JSFixedArray::dumpToStream(const JSCell* cell, PrintStream& out)
-{
-    VM& vm = cell->vm();
-    const auto* thisObject = jsCast<const JSFixedArray*>(cell);
-    out.printf("<%p, %s, [%u], [", thisObject, thisObject->className(vm), thisObject->length());
-    CommaPrinter comma;
-    for (unsigned index = 0; index < thisObject->length(); ++index)
-        out.print(comma, thisObject->get(index));
-    out.print("]>");
-}
-
-} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSFixedArray.h b/Source/JavaScriptCore/runtime/JSFixedArray.h
deleted file mode 100644 (file)
index cd76eb3..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2016-2019 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include "JSGlobalObject.h"
-#include "JSObject.h"
-
-namespace JSC {
-
-class JSFixedArray final : public JSCell {
-    typedef JSCell Base;
-
-public:
-    static constexpr unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
-
-    DECLARE_INFO;
-
-    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
-    {
-        return Structure::create(vm, globalObject, prototype, TypeInfo(JSFixedArrayType, StructureFlags), info());
-    }
-
-    ALWAYS_INLINE static JSFixedArray* tryCreate(VM& vm, Structure* structure, unsigned size)
-    {
-        Checked<size_t, RecordOverflow> checkedAllocationSize = allocationSize(size);
-        if (UNLIKELY(checkedAllocationSize.hasOverflowed()))
-            return nullptr;
-
-        void* buffer = tryAllocateCell<JSFixedArray>(vm.heap, checkedAllocationSize.unsafeGet());
-        if (UNLIKELY(!buffer))
-            return nullptr;
-        JSFixedArray* result = new (NotNull, buffer) JSFixedArray(vm, structure, size);
-        result->finishCreation(vm);
-        return result;
-    }
-
-    static JSFixedArray* create(VM& vm, unsigned length)
-    {
-        auto* array = tryCreate(vm, vm.fixedArrayStructure.get(), length);
-        RELEASE_ASSERT(array);
-        return array;
-    }
-
-    ALWAYS_INLINE static JSFixedArray* createFromArray(JSGlobalObject* globalObject, VM& vm, JSArray* array)
-    {
-        auto throwScope = DECLARE_THROW_SCOPE(vm);
-
-        IndexingType indexingType = array->indexingType() & IndexingShapeMask;
-        unsigned length = array->length();
-        JSFixedArray* result = JSFixedArray::tryCreate(vm, vm.fixedArrayStructure.get(), length);
-        if (UNLIKELY(!result)) {
-            throwOutOfMemoryError(globalObject, throwScope);
-            return nullptr;
-        }
-
-        if (!length)
-            return result;
-
-        if (indexingType == ContiguousShape || indexingType == Int32Shape) {
-            for (unsigned i = 0; i < length; i++) {
-                JSValue value = array->butterfly()->contiguous().at(array, i).get();
-                value = !!value ? value : jsUndefined();
-                result->buffer()[i].set(vm, result, value);
-            }
-            return result;
-        }
-
-        if (indexingType == DoubleShape) {
-            for (unsigned i = 0; i < length; i++) {
-                double d = array->butterfly()->contiguousDouble().at(array, i);
-                JSValue value = std::isnan(d) ? jsUndefined() : JSValue(JSValue::EncodeAsDouble, d);
-                result->buffer()[i].set(vm, result, value);
-            }
-            return result;
-        }
-
-        for (unsigned i = 0; i < length; i++) {
-            JSValue value = array->getDirectIndex(globalObject, i);
-            if (!value) {
-                // When we see a hole, we assume that it's safe to assume the get would have returned undefined.
-                // We may still call into this function when !globalObject->isArrayIteratorProtocolFastAndNonObservable(),
-                // however, if we do that, we ensure we're calling in with an array with all self properties between
-                // [0, length).
-                //
-                // We may also call into this during OSR exit to materialize a phantom fixed array.
-                // We may be creating a fixed array during OSR exit even after the iterator protocol changed.
-                // But, when the phantom would have logically been created, the protocol hadn't been
-                // changed. Therefore, it is sound to assume empty indices are jsUndefined().
-                value = jsUndefined();
-            }
-            RETURN_IF_EXCEPTION(throwScope, nullptr);
-            result->buffer()[i].set(vm, result, value);
-        }
-        return result;
-    }
-
-    ALWAYS_INLINE JSValue get(unsigned index) const
-    {
-        ASSERT(index < m_size);
-        return buffer()[index].get();
-    }
-
-    void set(VM& vm, unsigned index, JSValue value)
-    {
-        ASSERT(index < m_size);
-        return buffer()[index].set(vm, this, value);
-    }
-
-    ALWAYS_INLINE WriteBarrier<Unknown>* buffer() { return bitwise_cast<WriteBarrier<Unknown>*>(bitwise_cast<char*>(this) + offsetOfData()); }
-    ALWAYS_INLINE WriteBarrier<Unknown>* buffer() const { return const_cast<JSFixedArray*>(this)->buffer(); }
-    ALWAYS_INLINE const JSValue* values() const { return bitwise_cast<const JSValue*>(buffer()); }
-
-    static void visitChildren(JSCell*, SlotVisitor&);
-
-    unsigned size() const { return m_size; }
-    unsigned length() const { return m_size; }
-
-    static size_t offsetOfSize() { return OBJECT_OFFSETOF(JSFixedArray, m_size); }
-
-    static size_t offsetOfData()
-    {
-        return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(JSFixedArray));
-    }
-
-    void copyToArguments(JSGlobalObject*, CallFrame*, VirtualRegister firstElementDest, unsigned offset, unsigned length);
-
-    static void dumpToStream(const JSCell*, PrintStream&);
-
-    static Checked<size_t, RecordOverflow> allocationSize(Checked<size_t, RecordOverflow> numItems)
-    {
-        return offsetOfData() + numItems * sizeof(WriteBarrier<Unknown>);
-    }
-
-private:
-    JSFixedArray(VM& vm, Structure* structure, unsigned size)
-        : Base(vm, structure)
-        , m_size(size)
-    {
-        for (unsigned i = 0; i < m_size; i++)
-            buffer()[i].setStartingValue(JSValue());
-    }
-
-    unsigned m_size;
-};
-
-} // namespace JSC
index 2008e47..a182dc6 100644 (file)
@@ -68,6 +68,66 @@ public:
         return array;
     }
 
+    ALWAYS_INLINE static JSImmutableButterfly* createFromArray(JSGlobalObject* globalObject, VM& vm, JSArray* array)
+    {
+        auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+        IndexingType indexingType = array->indexingType() & IndexingShapeMask;
+        unsigned length = array->length();
+
+        // FIXME: JSImmutableButterfly::createFromArray should support re-using non contiguous indexing types as well.
+        if (isCopyOnWrite(indexingType)) {
+            if (hasContiguous(indexingType))
+                return JSImmutableButterfly::fromButterfly(array->butterfly());
+        }
+
+        JSImmutableButterfly* result = JSImmutableButterfly::tryCreate(vm, vm.immutableButterflyStructures[arrayIndexFromIndexingType(CopyOnWriteArrayWithContiguous) - NumberOfIndexingShapes].get(), length);
+        if (UNLIKELY(!result)) {
+            throwOutOfMemoryError(globalObject, throwScope);
+            return nullptr;
+        }
+
+        if (!length)
+            return result;
+
+        if (indexingType == ContiguousShape || indexingType == Int32Shape) {
+            for (unsigned i = 0; i < length; i++) {
+                JSValue value = array->butterfly()->contiguous().at(array, i).get();
+                value = !!value ? value : jsUndefined();
+                result->setIndex(vm, i, value);
+            }
+            return result;
+        }
+
+        if (indexingType == DoubleShape) {
+            for (unsigned i = 0; i < length; i++) {
+                double d = array->butterfly()->contiguousDouble().at(array, i);
+                JSValue value = std::isnan(d) ? jsUndefined() : JSValue(JSValue::EncodeAsDouble, d);
+                result->setIndex(vm, i, value);
+            }
+            return result;
+        }
+
+        for (unsigned i = 0; i < length; i++) {
+            JSValue value = array->getDirectIndex(globalObject, i);
+            if (!value) {
+                // When we see a hole, we assume that it's safe to assume the get would have returned undefined.
+                // We may still call into this function when !globalObject->isArrayIteratorProtocolFastAndNonObservable(),
+                // however, if we do that, we ensure we're calling in with an array with all self properties between
+                // [0, length).
+                //
+                // We may also call into this during OSR exit to materialize a phantom fixed array.
+                // We may be creating a fixed array during OSR exit even after the iterator protocol changed.
+                // But, when the phantom would have logically been created, the protocol hadn't been
+                // changed. Therefore, it is sound to assume empty indices are jsUndefined().
+                value = jsUndefined();
+            }
+            RETURN_IF_EXCEPTION(throwScope, nullptr);
+            result->setIndex(vm, i, value);
+        }
+        return result;
+    }
+
     unsigned publicLength() const { return m_header.publicLength(); }
     unsigned vectorLength() const { return m_header.vectorLength(); }
     unsigned length() const { return m_header.publicLength(); }
@@ -110,12 +170,22 @@ public:
         return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(JSImmutableButterfly));
     }
 
-private:
+    static ptrdiff_t offsetOfPublicLength()
+    {
+        return OBJECT_OFFSETOF(JSImmutableButterfly, m_header) + IndexingHeader::offsetOfPublicLength();
+    }
+
+    static ptrdiff_t offsetOfVectorLength()
+    {
+        return OBJECT_OFFSETOF(JSImmutableButterfly, m_header) + IndexingHeader::offsetOfVectorLength();
+    }
+
     static Checked<size_t, RecordOverflow> allocationSize(Checked<size_t, RecordOverflow> numItems)
     {
         return offsetOfData() + numItems * sizeof(WriteBarrier<Unknown>);
     }
 
+private:
     JSImmutableButterfly(VM& vm, Structure* structure, unsigned length)
         : Base(vm, structure)
     {
index d37beca..251edc8 100644 (file)
@@ -57,7 +57,6 @@ void printInternal(PrintStream& out, JSC::JSType type)
     CASE(UnlinkedEvalCodeBlockType)
     CASE(UnlinkedFunctionCodeBlockType)
     CASE(CodeBlockType)
-    CASE(JSFixedArrayType)
     CASE(JSImmutableButterflyType)
     CASE(JSSourceCodeType)
     CASE(JSScriptFetcherType)
index 412d9b4..addf769 100644 (file)
@@ -49,7 +49,6 @@ enum JSType : uint8_t {
         
     CodeBlockType,
 
-    JSFixedArrayType,
     JSImmutableButterflyType,
     JSSourceCodeType,
     JSScriptFetcherType,
index af0aa4e..9d54fdc 100644 (file)
@@ -95,7 +95,6 @@
 #include "JSCallee.h"
 #include "JSCustomGetterSetterFunction.h"
 #include "JSDestructibleObjectHeapCellType.h"
-#include "JSFixedArray.h"
 #include "JSFunction.h"
 #include "JSGlobalLexicalEnvironment.h"
 #include "JSGlobalObject.h"
@@ -454,7 +453,6 @@ VM::VM(VMType vmType, HeapType heapType)
     regExpStructure.set(*this, RegExp::createStructure(*this, 0, jsNull()));
     symbolStructure.set(*this, Symbol::createStructure(*this, 0, jsNull()));
     symbolTableStructure.set(*this, SymbolTable::createStructure(*this, 0, jsNull()));
-    fixedArrayStructure.set(*this, JSFixedArray::createStructure(*this, 0, jsNull()));
 
     immutableButterflyStructures[arrayIndexFromIndexingType(CopyOnWriteArrayWithInt32) - NumberOfIndexingShapes].set(*this, JSImmutableButterfly::createStructure(*this, 0, jsNull(), CopyOnWriteArrayWithInt32));
     immutableButterflyStructures[arrayIndexFromIndexingType(CopyOnWriteArrayWithDouble) - NumberOfIndexingShapes].set(*this, JSImmutableButterfly::createStructure(*this, 0, jsNull(), CopyOnWriteArrayWithDouble));
index af20198..e9a90f0 100644 (file)
@@ -660,7 +660,6 @@ public:
     Strong<Structure> regExpStructure;
     Strong<Structure> symbolStructure;
     Strong<Structure> symbolTableStructure;
-    Strong<Structure> fixedArrayStructure;
     Strong<Structure> immutableButterflyStructures[NumberOfCopyOnWriteIndexingModes];
     Strong<Structure> sourceCodeStructure;
     Strong<Structure> scriptFetcherStructure;