Diff
Modified: trunk/JSTests/ChangeLog (208376 => 208377)
--- trunk/JSTests/ChangeLog 2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/JSTests/ChangeLog 2016-11-04 06:18:01 UTC (rev 208377)
@@ -1,3 +1,13 @@
+2016-11-03 Mark Lam <[email protected]>
+
+ ClonedArguments need to also support haveABadTime mode.
+ https://bugs.webkit.org/show_bug.cgi?id=164200
+ <rdar://problem/27211336>
+
+ Reviewed by Geoffrey Garen.
+
+ * stress/have-a-bad-time-with-arguments.js: Added.
+
2016-11-03 Filip Pizlo <[email protected]>
DFG plays fast and loose with the shadow values of a Phi
Added: trunk/JSTests/stress/have-a-bad-time-with-arguments.js (0 => 208377)
--- trunk/JSTests/stress/have-a-bad-time-with-arguments.js (rev 0)
+++ trunk/JSTests/stress/have-a-bad-time-with-arguments.js 2016-11-04 06:18:01 UTC (rev 208377)
@@ -0,0 +1,140 @@
+//@ runFTLNoCJIT
+
+// Tests accessing an element in arguments before and after having a bad time.
+// This test should not crash.
+
+let verbose = false;
+
+var utilities = 'function shouldEqual(testId, actual, expected) {' + '\n' +
+ ' if (actual != expected)' + '\n' +
+ ' throw testId + ": ERROR: expect " + expected + ", actual " + actual;' + '\n' +
+ '}' + '\n';
+
+var haveABadTime = 'Object.defineProperty(Object.prototype, 20, { get() { return 20; } });' + '\n';
+
+var directArgumentsDecl = ' var args = arguments;' + '\n';
+
+var scopedArgumentsDecl = ' var args = arguments;' + '\n' +
+ ' function closure() { return x; }' + '\n';
+
+var clonedArgumentsDecl = ' "use strict";' + '\n' +
+ ' var args = arguments;' + '\n';
+
+function testFunction(argsDecl, insertElementAction, indexToReturn) {
+ var script = 'function test(x) {' + '\n' +
+ argsDecl +
+ insertElementAction +
+ ' return args[' + indexToReturn + '];' + '\n' +
+ '}' + '\n' +
+ 'noInline(test);' + '\n';
+ return script;
+}
+
+function warmupFunction(tierWarmupCount, testArgs) {
+ var script = 'function warmup() {' + '\n' +
+ ' for (var i = 0; i < ' + tierWarmupCount + '; i++) {' + '\n' +
+ ' test(' + testArgs + ');' + '\n' +
+ ' }' + '\n' +
+ '}' + '\n';
+ return script;
+}
+
+let argumentsDecls = {
+ direct: directArgumentsDecl,
+ scoped: scopedArgumentsDecl,
+ cloned: clonedArgumentsDecl
+};
+
+let indicesToReturn = {
+ inBounds: 0,
+ outOfBoundsInsertedElement: 10,
+ outOfBoundsInPrototype: 20
+};
+
+let tierWarmupCounts = {
+ llint: 1,
+ baseline: 50,
+ dfg: 1000,
+ ftl: 10000
+};
+
+let testArgsList = {
+ noArgs: {
+ args: '',
+ result: {
+ inBounds: { beforeBadTime: 'undefined', afterBadTime: 'undefined', },
+ outOfBoundsInsertedElement: { beforeBadTime: '10', afterBadTime: '10', },
+ outOfBoundsInPrototype: { beforeBadTime: 'undefined', afterBadTime: '20', },
+ }
+ },
+ someArgs: {
+ args: '1, 2, 3',
+ result: {
+ inBounds: { beforeBadTime: '1', afterBadTime: '1', },
+ outOfBoundsInsertedElement: { beforeBadTime: '10', afterBadTime: '10', },
+ outOfBoundsInPrototype: { beforeBadTime: 'undefined', afterBadTime: '20', },
+ }
+ }
+};
+
+let insertElementActions = {
+ insertElement: ' args[10] = 10;' + '\n',
+ dontInsertElement: ''
+};
+
+for (let argsDeclIndex in argumentsDecls) {
+ let argsDecl = argumentsDecls[argsDeclIndex];
+
+ for (let indexToReturnIndex in indicesToReturn) {
+ let indexToReturn = indicesToReturn[indexToReturnIndex];
+
+ for (let insertElementActionIndex in insertElementActions) {
+ let insertElementAction = insertElementActions[insertElementActionIndex];
+
+ for (let tierWarmupCountIndex in tierWarmupCounts) {
+ let tierWarmupCount = tierWarmupCounts[tierWarmupCountIndex];
+
+ for (let testArgsIndex in testArgsList) {
+ let testArgs = testArgsList[testArgsIndex].args;
+ let expectedResult = testArgsList[testArgsIndex].result[indexToReturnIndex];
+
+ if (indexToReturnIndex == 'outOfBoundsInsertedElement'
+ && insertElementActionIndex == 'dontInsertElement')
+ expectedResult = 'undefined';
+
+ let testName =
+ argsDeclIndex + '-' +
+ indexToReturnIndex + '-' +
+ insertElementActionIndex + '-' +
+ tierWarmupCountIndex + '-' +
+ testArgsIndex;
+
+
+ let script = utilities +
+ testFunction(argsDecl, insertElementAction, indexToReturn) +
+ warmupFunction(tierWarmupCount, testArgs) +
+ 'warmup()' + '\n' +
+ 'shouldEqual(10000, test(' + testArgs + '), ' + expectedResult['beforeBadTime'] + ');' + '\n';
+ haveABadTime +
+ 'shouldEqual(20000, test(' + testArgs + '), ' + expectedResult['afterBadTime'] + ');' + '\n';
+
+ if (verbose) {
+ print('Running test configuration: ' + testName);
+ print(
+ 'Test script: ====================================================\n' +
+ script +
+ '=== END script ==================================================');
+ }
+
+ try {
+ runString(script);
+ } catch (e) {
+ print('FAILED test configuration: ' + testName);
+ print('FAILED test script:\n' + script);
+ throw e;
+ }
+ }
+ }
+ }
+ }
+}
Modified: trunk/Source/_javascript_Core/ChangeLog (208376 => 208377)
--- trunk/Source/_javascript_Core/ChangeLog 2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-11-04 06:18:01 UTC (rev 208377)
@@ -1,3 +1,83 @@
+2016-11-03 Mark Lam <[email protected]>
+
+ ClonedArguments need to also support haveABadTime mode.
+ https://bugs.webkit.org/show_bug.cgi?id=164200
+ <rdar://problem/27211336>
+
+ Reviewed by Geoffrey Garen.
+
+ For those who are not familiar with the parlance, "have a bad time" in the VM
+ means that Object.prototype has been modified in such a way that we can no longer
+ trivially do indexed property accesses without consulting the Object.prototype.
+ This defeats JIT indexed put optimizations, and hence, makes the VM "have a
+ bad time".
+
+ Once the VM enters haveABadTime mode, all existing objects are converted to use
+ slow put storage. Thereafter, JSArrays are always created with slow put storage.
+ JSObjects are always created with a blank indexing type. When a new indexed
+ property is put into the new object, its indexing type will be converted to the
+ slow put array indexing type just before we perform the put operation. This is
+ how we ensure that the objects will also use slow put storage.
+
+ However, ClonedArguments is an object which was previously created unconditionally
+ to use contiguous storage. Subsequently, if we try to call Object.preventExtensions()
+ on that ClonedArguments object, Object.preventExtensions() will:
+ 1. make the ClonedArguments enter dictionary indexing mode, which means it will
+ 2. first ensure that the ClonedArguments is using slow put array storage via
+ JSObject::ensureArrayStorageSlow().
+
+ However, JSObject::ensureArrayStorageSlow() expects that we never see an object
+ with contiguous storage once we're in haveABadTime mode. Our ClonedArguments
+ object did not obey this invariant.
+
+ The fix is to make the ClonedArguments factories create objects that use slow put
+ array storage when in haveABadTime mode. This means:
+
+ 1. JSGlobalObject::haveABadTime() now changes m_clonedArgumentsStructure to use
+ its slow put version.
+
+ Also the caching of the slow put version of m_regExpMatchesArrayStructure,
+ because we only need to create it when we are having a bad time.
+
+ 2. The ClonedArguments factories now allocates a butterfly with slow put array
+ storage if we're in haveABadTime mode.
+
+ Also added some assertions in ClonedArguments' factory methods to ensure that
+ the created object has the slow put indexing type when it needsSlowPutIndexing().
+
+ 3. DFGFixupPhase now watches the havingABadTimeWatchpoint because ClonedArguments'
+ structure will change when having a bad time.
+
+ 4. DFGArgumentEliminationPhase and DFGVarargsForwardingPhase need not be changed
+ because it is still valid to eliminate the creation of the arguments object
+ even having a bad time, as long as the arguments object does not escape.
+
+ 5. The DFGAbstractInterpreterInlines now checks for haveABadTime, and sets the
+ predicted type to be SpecObject.
+
+ Note: this issue does not apply to DirectArguments and ScopedArguments because
+ they use a blank indexing type (just like JSObject).
+
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGArrayMode.cpp:
+ (JSC::DFG::ArrayMode::dump):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * runtime/ClonedArguments.cpp:
+ (JSC::ClonedArguments::createEmpty):
+ (JSC::ClonedArguments::createWithInlineFrame):
+ (JSC::ClonedArguments::createWithMachineFrame):
+ (JSC::ClonedArguments::createByCopyingFrom):
+ (JSC::ClonedArguments::createStructure):
+ (JSC::ClonedArguments::createSlowPutStructure):
+ * runtime/ClonedArguments.h:
+ * runtime/JSGlobalObject.cpp:
+ (JSC::JSGlobalObject::init):
+ (JSC::JSGlobalObject::haveABadTime):
+ (JSC::JSGlobalObject::visitChildren):
+ * runtime/JSGlobalObject.h:
+
2016-11-03 Filip Pizlo <[email protected]>
DFG plays fast and loose with the shadow values of a Phi
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (208376 => 208377)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2016-11-04 06:18:01 UTC (rev 208377)
@@ -1981,6 +1981,10 @@
break;
case CreateClonedArguments:
+ if (!m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
+ forNode(node).setType(m_graph, SpecObject);
+ break;
+ }
forNode(node).set(m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->clonedArgumentsStructure());
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp (208376 => 208377)
--- trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp 2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp 2016-11-04 06:18:01 UTC (rev 208377)
@@ -734,7 +734,7 @@
void ArrayMode::dump(PrintStream& out) const
{
- out.print(type(), arrayClass(), speculation(), conversion());
+ out.print(type(), "+", arrayClass(), "+", speculation(), "+", conversion());
}
} } // namespace JSC::DFG
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (208376 => 208377)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2016-11-04 06:18:01 UTC (rev 208377)
@@ -1550,6 +1550,11 @@
break;
}
+ case CreateClonedArguments: {
+ watchHavingABadTime(node);
+ break;
+ }
+
case CreateScopedArguments:
case CreateActivation:
case NewFunction:
@@ -1776,7 +1781,6 @@
case IsObjectOrNull:
case IsFunction:
case CreateDirectArguments:
- case CreateClonedArguments:
case Jump:
case Return:
case TailCall:
Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.cpp (208376 => 208377)
--- trunk/Source/_javascript_Core/interpreter/Interpreter.cpp 2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.cpp 2016-11-04 06:18:01 UTC (rev 208377)
@@ -32,7 +32,6 @@
#include "BatchedTransitionOptimizer.h"
#include "CallFrameClosure.h"
-#include "ClonedArguments.h"
#include "CodeBlock.h"
#include "DirectArguments.h"
#include "Heap.h"
Modified: trunk/Source/_javascript_Core/runtime/ClonedArguments.cpp (208376 => 208377)
--- trunk/Source/_javascript_Core/runtime/ClonedArguments.cpp 2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/_javascript_Core/runtime/ClonedArguments.cpp 2016-11-04 06:18:01 UTC (rev 208377)
@@ -48,16 +48,23 @@
if (vectorLength > MAX_STORAGE_VECTOR_LENGTH)
return 0;
- void* temp = vm.heap.tryAllocateAuxiliary(nullptr, Butterfly::totalSize(0, structure->outOfLineCapacity(), true, vectorLength * sizeof(EncodedJSValue)));
- if (!temp)
- return 0;
- Butterfly* butterfly = Butterfly::fromBase(temp, 0, structure->outOfLineCapacity());
- butterfly->setVectorLength(vectorLength);
- butterfly->setPublicLength(length);
+ Butterfly* butterfly;
+ if (UNLIKELY(structure->needsSlowPutIndexing())) {
+ butterfly = createArrayStorageButterfly(vm, nullptr, structure, length, vectorLength);
+ butterfly->arrayStorage()->m_numValuesInVector = vectorLength;
+
+ } else {
+ void* temp = vm.heap.tryAllocateAuxiliary(nullptr, Butterfly::totalSize(0, structure->outOfLineCapacity(), true, vectorLength * sizeof(EncodedJSValue)));
+ if (!temp)
+ return 0;
+ butterfly = Butterfly::fromBase(temp, 0, structure->outOfLineCapacity());
+ butterfly->setVectorLength(vectorLength);
+ butterfly->setPublicLength(length);
+
+ for (unsigned i = length; i < vectorLength; ++i)
+ butterfly->contiguous()[i].clear();
+ }
- for (unsigned i = length; i < vectorLength; ++i)
- butterfly->contiguous()[i].clear();
-
ClonedArguments* result =
new (NotNull, allocateCell<ClonedArguments>(vm.heap))
ClonedArguments(vm, structure, butterfly);
@@ -70,9 +77,12 @@
ClonedArguments* ClonedArguments::createEmpty(ExecState* exec, JSFunction* callee, unsigned length)
{
+ VM& vm = exec->vm();
// NB. Some clients might expect that the global object of of this object is the global object
// of the callee. We don't do this for now, but maybe we should.
- return createEmpty(exec->vm(), exec->lexicalGlobalObject()->clonedArgumentsStructure(), callee, length);
+ ClonedArguments* result = createEmpty(vm, exec->lexicalGlobalObject()->clonedArgumentsStructure(), callee, length);
+ ASSERT(!result->structure(vm)->needsSlowPutIndexing() || shouldUseSlowPut(result->structure(vm)->indexingType()));
+ return result;
}
ClonedArguments* ClonedArguments::createWithInlineFrame(ExecState* myFrame, ExecState* targetFrame, InlineCallFrame* inlineCallFrame, ArgumentsMode mode)
@@ -117,12 +127,15 @@
} }
ASSERT(myFrame->lexicalGlobalObject()->clonedArgumentsStructure() == result->structure());
+ ASSERT(!result->structure(vm)->needsSlowPutIndexing() || shouldUseSlowPut(result->structure(vm)->indexingType()));
return result;
}
ClonedArguments* ClonedArguments::createWithMachineFrame(ExecState* myFrame, ExecState* targetFrame, ArgumentsMode mode)
{
- return createWithInlineFrame(myFrame, targetFrame, nullptr, mode);
+ ClonedArguments* result = createWithInlineFrame(myFrame, targetFrame, nullptr, mode);
+ ASSERT(!result->structure()->needsSlowPutIndexing() || shouldUseSlowPut(result->structure()->indexingType()));
+ return result;
}
ClonedArguments* ClonedArguments::createByCopyingFrom(
@@ -134,15 +147,13 @@
for (unsigned i = length; i--;)
result->initializeIndex(vm, i, argumentStart[i].jsValue());
-
+ ASSERT(!result->structure(vm)->needsSlowPutIndexing() || shouldUseSlowPut(result->structure(vm)->indexingType()));
return result;
}
-Structure* ClonedArguments::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+Structure* ClonedArguments::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, IndexingType indexingType)
{
- // We use contiguous storage because optimizations in the FTL assume that cloned arguments creation always produces the same initial structure.
-
- Structure* structure = Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), NonArrayWithContiguous);
+ Structure* structure = Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), indexingType);
PropertyOffset offset;
structure = structure->addPropertyTransition(vm, structure, vm.propertyNames->length, DontEnum, offset);
ASSERT(offset == clonedArgumentsLengthPropertyOffset);
@@ -149,6 +160,17 @@
return structure;
}
+Structure* ClonedArguments::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ // We use contiguous storage because optimizations in the FTL assume that cloned arguments creation always produces the same initial structure.
+ return createStructure(vm, globalObject, prototype, NonArrayWithContiguous);
+}
+
+Structure* ClonedArguments::createSlowPutStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return createStructure(vm, globalObject, prototype, NonArrayWithSlowPutArrayStorage);
+}
+
bool ClonedArguments::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName ident, PropertySlot& slot)
{
ClonedArguments* thisObject = jsCast<ClonedArguments*>(object);
Modified: trunk/Source/_javascript_Core/runtime/ClonedArguments.h (208376 => 208377)
--- trunk/Source/_javascript_Core/runtime/ClonedArguments.h 2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/_javascript_Core/runtime/ClonedArguments.h 2016-11-04 06:18:01 UTC (rev 208377)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -53,6 +53,7 @@
static ClonedArguments* createByCopyingFrom(ExecState*, Structure*, Register* argumentsStart, unsigned length, JSFunction* callee);
static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
+ static Structure* createSlowPutStructure(VM&, JSGlobalObject*, JSValue prototype);
static void visitChildren(JSCell*, SlotVisitor&);
@@ -59,6 +60,8 @@
DECLARE_INFO;
private:
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype, IndexingType);
+
static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
static bool put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (208376 => 208377)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2016-11-04 06:18:01 UTC (rev 208377)
@@ -537,7 +537,6 @@
m_regExpPrototype.set(vm, this, RegExpPrototype::create(vm, this, RegExpPrototype::createStructure(vm, this, m_objectPrototype.get())));
m_regExpStructure.set(vm, this, RegExpObject::createStructure(vm, this, m_regExpPrototype.get()));
m_regExpMatchesArrayStructure.set(vm, this, createRegExpMatchesArrayStructure(vm, this));
- m_regExpMatchesArraySlowPutStructure.set(vm, this, createRegExpMatchesArraySlowPutStructure(vm, this));
m_moduleRecordStructure.set(vm, this, JSModuleRecord::createStructure(vm, this, m_objectPrototype.get()));
m_moduleNamespaceObjectStructure.set(vm, this, JSModuleNamespaceObject::createStructure(vm, this, jsNull()));
@@ -1052,8 +1051,12 @@
m_arrayStructureForIndexingShapeDuringAllocation[i].set(vm, this, originalArrayStructureForIndexingType(ArrayWithSlowPutArrayStorage));
// Same for any special array structures.
- m_regExpMatchesArrayStructure.set(vm, this, m_regExpMatchesArraySlowPutStructure.get());
-
+ Structure* slowPutStructure;
+ slowPutStructure = createRegExpMatchesArraySlowPutStructure(vm, this);
+ m_regExpMatchesArrayStructure.set(vm, this, slowPutStructure);
+ slowPutStructure = ClonedArguments::createSlowPutStructure(vm, this, m_objectPrototype.get());
+ m_clonedArgumentsStructure.set(vm, this, slowPutStructure);
+
// Make sure that all objects that have indexed storage switch to the slow kind of
// indexed storage.
MarkedArgumentBuffer foundObjects; // Use MarkedArgumentBuffer because switchToSlowPutArrayStorage() may GC.
@@ -1191,7 +1194,6 @@
visitor.append(&thisObject->m_generatorFunctionStructure);
visitor.append(&thisObject->m_iteratorResultObjectStructure);
visitor.append(&thisObject->m_regExpMatchesArrayStructure);
- visitor.append(&thisObject->m_regExpMatchesArraySlowPutStructure);
visitor.append(&thisObject->m_moduleRecordStructure);
visitor.append(&thisObject->m_moduleNamespaceObjectStructure);
visitor.append(&thisObject->m_dollarVMStructure);
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (208376 => 208377)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h 2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h 2016-11-04 06:18:01 UTC (rev 208377)
@@ -320,7 +320,6 @@
WriteBarrier<Structure> m_dollarVMStructure;
WriteBarrier<Structure> m_iteratorResultObjectStructure;
WriteBarrier<Structure> m_regExpMatchesArrayStructure;
- WriteBarrier<Structure> m_regExpMatchesArraySlowPutStructure;
WriteBarrier<Structure> m_moduleRecordStructure;
WriteBarrier<Structure> m_moduleNamespaceObjectStructure;
WriteBarrier<Structure> m_proxyObjectStructure;
Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (208376 => 208377)
--- trunk/Source/_javascript_Core/runtime/JSObject.cpp 2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp 2016-11-04 06:18:01 UTC (rev 208377)
@@ -768,14 +768,10 @@
return newButterfly->contiguous();
}
-ArrayStorage* JSObject::createArrayStorage(VM& vm, unsigned length, unsigned vectorLength)
+Butterfly* JSObject::createArrayStorageButterfly(VM& vm, JSCell* intendedOwner, Structure* structure, unsigned length, unsigned vectorLength, Butterfly* oldButterfly)
{
- DeferGC deferGC(vm.heap);
- Structure* structure = this->structure(vm);
- IndexingType oldType = indexingType();
- ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(
- m_butterfly.get(), vm, this, structure, structure->outOfLineCapacity(), false, 0,
+ oldButterfly, vm, intendedOwner, structure, structure->outOfLineCapacity(), false, 0,
ArrayStorage::sizeFor(vectorLength));
RELEASE_ASSERT(newButterfly);
@@ -787,6 +783,19 @@
result->m_indexBias = 0;
for (size_t i = vectorLength; i--;)
result->m_vector[i].setWithoutWriteBarrier(JSValue());
+
+ return newButterfly;
+}
+
+ArrayStorage* JSObject::createArrayStorage(VM& vm, unsigned length, unsigned vectorLength)
+{
+ DeferGC deferGC(vm.heap);
+ Structure* structure = this->structure(vm);
+ IndexingType oldType = indexingType();
+ ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
+
+ Butterfly* newButterfly = createArrayStorageButterfly(vm, this, structure, length, vectorLength, m_butterfly.get());
+ ArrayStorage* result = newButterfly->arrayStorage();
Structure* newStructure = Structure::nonPropertyTransition(vm, structure, structure->suggestedArrayStorageTransition());
setStructureAndButterfly(vm, newStructure, newButterfly);
return result;
Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (208376 => 208377)
--- trunk/Source/_javascript_Core/runtime/JSObject.h 2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h 2016-11-04 06:18:01 UTC (rev 208377)
@@ -902,6 +902,7 @@
void createInitialForValueAndSet(VM&, unsigned index, JSValue);
void convertInt32ForValue(VM&, JSValue);
+ static Butterfly* createArrayStorageButterfly(VM&, JSCell* intendedOwner, Structure*, unsigned length, unsigned vectorLength, Butterfly* oldButterfly = nullptr);
ArrayStorage* createArrayStorage(VM&, unsigned length, unsigned vectorLength);
ArrayStorage* createInitialArrayStorage(VM&);