summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2012-11-09 09:42:44 +0100
committerSimon Hausmann <simon.hausmann@digia.com>2012-11-09 09:42:44 +0100
commita59391482883479a9b28a6f1ace6d1ebd08a7ecd (patch)
treefa539db054a20a67bff2fc891c33b0f4ec632916 /Source/JavaScriptCore/runtime
parentcfd86b747d32ac22246a1aa908eaa720c63a88c1 (diff)
downloadqtwebkit-a59391482883479a9b28a6f1ace6d1ebd08a7ecd.tar.gz
Imported WebKit commit 7bcdfab9a40db7d16b4b95bb77d78b8a59c9e701 (http://svn.webkit.org/repository/webkit/trunk@134025)
New snapshot with numerious build fixes, including MSVC 2012 and ARM Thumb-2.
Diffstat (limited to 'Source/JavaScriptCore/runtime')
-rw-r--r--Source/JavaScriptCore/runtime/ArgList.h280
-rw-r--r--Source/JavaScriptCore/runtime/Arguments.h446
-rw-r--r--Source/JavaScriptCore/runtime/ArrayConstructor.cpp14
-rw-r--r--Source/JavaScriptCore/runtime/ArrayConstructor.h54
-rw-r--r--Source/JavaScriptCore/runtime/ArrayPrototype.cpp16
-rw-r--r--Source/JavaScriptCore/runtime/ArrayPrototype.h32
-rw-r--r--Source/JavaScriptCore/runtime/Butterfly.h6
-rw-r--r--Source/JavaScriptCore/runtime/ButterflyInlines.h (renamed from Source/JavaScriptCore/runtime/ButterflyInlineMethods.h)11
-rw-r--r--Source/JavaScriptCore/runtime/CodeCache.cpp37
-rw-r--r--Source/JavaScriptCore/runtime/CodeCache.h50
-rw-r--r--Source/JavaScriptCore/runtime/Executable.cpp5
-rw-r--r--Source/JavaScriptCore/runtime/Executable.h2
-rw-r--r--Source/JavaScriptCore/runtime/FunctionPrototype.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/IndexingHeaderInlines.h (renamed from Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h)9
-rw-r--r--Source/JavaScriptCore/runtime/IndexingType.cpp55
-rw-r--r--Source/JavaScriptCore/runtime/IndexingType.h46
-rw-r--r--Source/JavaScriptCore/runtime/JSActivation.h2
-rw-r--r--Source/JavaScriptCore/runtime/JSArray.cpp454
-rw-r--r--Source/JavaScriptCore/runtime/JSArray.h36
-rw-r--r--Source/JavaScriptCore/runtime/JSCell.h4
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.cpp28
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.h56
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.cpp661
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.h229
-rw-r--r--Source/JavaScriptCore/runtime/JSValue.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/JSValueInlines.h (renamed from Source/JavaScriptCore/runtime/JSValueInlineMethods.h)7
-rw-r--r--Source/JavaScriptCore/runtime/LiteralParser.cpp6
-rw-r--r--Source/JavaScriptCore/runtime/ObjectConstructor.cpp8
-rw-r--r--Source/JavaScriptCore/runtime/Operations.h2
-rw-r--r--Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/RegExpObject.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/StringPrototype.cpp26
-rw-r--r--Source/JavaScriptCore/runtime/Structure.cpp13
-rw-r--r--Source/JavaScriptCore/runtime/StructureTransitionTable.h20
34 files changed, 1937 insertions, 690 deletions
diff --git a/Source/JavaScriptCore/runtime/ArgList.h b/Source/JavaScriptCore/runtime/ArgList.h
index 29010b1ee..1fb1ce911 100644
--- a/Source/JavaScriptCore/runtime/ArgList.h
+++ b/Source/JavaScriptCore/runtime/ArgList.h
@@ -29,153 +29,153 @@
namespace JSC {
- class SlotVisitor;
-
- class MarkedArgumentBuffer {
- WTF_MAKE_NONCOPYABLE(MarkedArgumentBuffer);
- friend class JSGlobalData;
- friend class ArgList;
-
- private:
- static const size_t inlineCapacity = 8;
- typedef Vector<Register, inlineCapacity> VectorType;
- typedef HashSet<MarkedArgumentBuffer*> ListSet;
-
- public:
- // Constructor for a read-write list, to which you may append values.
- // FIXME: Remove all clients of this API, then remove this API.
- MarkedArgumentBuffer()
- : m_size(0)
- , m_capacity(inlineCapacity)
- , m_buffer(&m_inlineBuffer[m_capacity - 1])
- , m_markSet(0)
- {
- }
-
- ~MarkedArgumentBuffer()
- {
- if (m_markSet)
- m_markSet->remove(this);
-
- if (EncodedJSValue* base = mallocBase())
- delete [] base;
- }
-
- size_t size() const { return m_size; }
- bool isEmpty() const { return !m_size; }
-
- JSValue at(int i) const
- {
- if (i >= m_size)
- return jsUndefined();
-
- return JSValue::decode(slotFor(i));
- }
-
- void clear()
- {
- m_size = 0;
- }
-
- void append(JSValue v)
- {
- if (m_size >= m_capacity)
- return slowAppend(v);
-
- slotFor(m_size) = JSValue::encode(v);
- ++m_size;
- }
-
- void removeLast()
- {
- ASSERT(m_size);
- m_size--;
- }
-
- JSValue last()
- {
- ASSERT(m_size);
- return JSValue::decode(slotFor(m_size - 1));
- }
+class SlotVisitor;
+
+class MarkedArgumentBuffer {
+ WTF_MAKE_NONCOPYABLE(MarkedArgumentBuffer);
+ friend class JSGlobalData;
+ friend class ArgList;
+
+private:
+ static const size_t inlineCapacity = 8;
+ typedef Vector<Register, inlineCapacity> VectorType;
+ typedef HashSet<MarkedArgumentBuffer*> ListSet;
+
+public:
+ // Constructor for a read-write list, to which you may append values.
+ // FIXME: Remove all clients of this API, then remove this API.
+ MarkedArgumentBuffer()
+ : m_size(0)
+ , m_capacity(inlineCapacity)
+ , m_buffer(&m_inlineBuffer[m_capacity - 1])
+ , m_markSet(0)
+ {
+ }
+
+ ~MarkedArgumentBuffer()
+ {
+ if (m_markSet)
+ m_markSet->remove(this);
+
+ if (EncodedJSValue* base = mallocBase())
+ delete [] base;
+ }
+
+ size_t size() const { return m_size; }
+ bool isEmpty() const { return !m_size; }
+
+ JSValue at(int i) const
+ {
+ if (i >= m_size)
+ return jsUndefined();
+
+ return JSValue::decode(slotFor(i));
+ }
+
+ void clear()
+ {
+ m_size = 0;
+ }
+
+ void append(JSValue v)
+ {
+ if (m_size >= m_capacity)
+ return slowAppend(v);
+
+ slotFor(m_size) = JSValue::encode(v);
+ ++m_size;
+ }
+
+ void removeLast()
+ {
+ ASSERT(m_size);
+ m_size--;
+ }
+
+ JSValue last()
+ {
+ ASSERT(m_size);
+ return JSValue::decode(slotFor(m_size - 1));
+ }
- static void markLists(HeapRootVisitor&, ListSet&);
+ static void markLists(HeapRootVisitor&, ListSet&);
- private:
- JS_EXPORT_PRIVATE void slowAppend(JSValue);
+private:
+ JS_EXPORT_PRIVATE void slowAppend(JSValue);
- EncodedJSValue& slotFor(int item) const
- {
- return m_buffer[-item];
- }
+ EncodedJSValue& slotFor(int item) const
+ {
+ return m_buffer[-item];
+ }
- EncodedJSValue* mallocBase()
- {
- if (m_capacity == static_cast<int>(inlineCapacity))
- return 0;
- return &slotFor(m_capacity - 1);
- }
+ EncodedJSValue* mallocBase()
+ {
+ if (m_capacity == static_cast<int>(inlineCapacity))
+ return 0;
+ return &slotFor(m_capacity - 1);
+ }
- int m_size;
- int m_capacity;
- EncodedJSValue m_inlineBuffer[inlineCapacity];
- EncodedJSValue* m_buffer;
- ListSet* m_markSet;
-
- private:
- // Prohibits new / delete, which would break GC.
- void* operator new(size_t size)
- {
- return fastMalloc(size);
- }
- void operator delete(void* p)
- {
- fastFree(p);
- }
-
- void* operator new[](size_t);
- void operator delete[](void*);
-
- void* operator new(size_t, void*);
- void operator delete(void*, size_t);
- };
-
- class ArgList {
- friend class JIT;
- public:
- ArgList()
- : m_args(0)
- , m_argCount(0)
- {
- }
-
- ArgList(ExecState* exec)
- : m_args(reinterpret_cast<JSValue*>(&exec[CallFrame::argumentOffset(0)]))
- , m_argCount(exec->argumentCount())
- {
- }
-
- ArgList(const MarkedArgumentBuffer& args)
- : m_args(reinterpret_cast<JSValue*>(args.m_buffer))
- , m_argCount(args.size())
- {
- }
-
- JSValue at(int i) const
- {
- if (i >= m_argCount)
- return jsUndefined();
- return m_args[-i];
- }
-
- bool isEmpty() const { return !m_argCount; }
- size_t size() const { return m_argCount; }
+ int m_size;
+ int m_capacity;
+ EncodedJSValue m_inlineBuffer[inlineCapacity];
+ EncodedJSValue* m_buffer;
+ ListSet* m_markSet;
+
+private:
+ // Prohibits new / delete, which would break GC.
+ void* operator new(size_t size)
+ {
+ return fastMalloc(size);
+ }
+ void operator delete(void* p)
+ {
+ fastFree(p);
+ }
+
+ void* operator new[](size_t);
+ void operator delete[](void*);
+
+ void* operator new(size_t, void*);
+ void operator delete(void*, size_t);
+};
+
+class ArgList {
+ friend class JIT;
+public:
+ ArgList()
+ : m_args(0)
+ , m_argCount(0)
+ {
+ }
+
+ ArgList(ExecState* exec)
+ : m_args(reinterpret_cast<JSValue*>(&exec[CallFrame::argumentOffset(0)]))
+ , m_argCount(exec->argumentCount())
+ {
+ }
+
+ ArgList(const MarkedArgumentBuffer& args)
+ : m_args(reinterpret_cast<JSValue*>(args.m_buffer))
+ , m_argCount(args.size())
+ {
+ }
+
+ JSValue at(int i) const
+ {
+ if (i >= m_argCount)
+ return jsUndefined();
+ return m_args[-i];
+ }
+
+ bool isEmpty() const { return !m_argCount; }
+ size_t size() const { return m_argCount; }
- JS_EXPORT_PRIVATE void getSlice(int startIndex, ArgList& result) const;
+ JS_EXPORT_PRIVATE void getSlice(int startIndex, ArgList& result) const;
- private:
- JSValue* m_args;
- int m_argCount;
- };
+private:
+ JSValue* m_args;
+ int m_argCount;
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Arguments.h b/Source/JavaScriptCore/runtime/Arguments.h
index 7961d4bc8..8ae991422 100644
--- a/Source/JavaScriptCore/runtime/Arguments.h
+++ b/Source/JavaScriptCore/runtime/Arguments.h
@@ -34,246 +34,246 @@
namespace JSC {
- class Arguments : public JSDestructibleObject {
- friend class JIT;
- friend class DFG::SpeculativeJIT;
- public:
- typedef JSDestructibleObject Base;
-
- static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame)
- {
- Arguments* arguments = new (NotNull, allocateCell<Arguments>(globalData.heap)) Arguments(callFrame);
- arguments->finishCreation(callFrame);
- return arguments;
- }
-
- static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame, InlineCallFrame* inlineCallFrame)
- {
- Arguments* arguments = new (NotNull, allocateCell<Arguments>(globalData.heap)) Arguments(callFrame);
- arguments->finishCreation(callFrame, inlineCallFrame);
- return arguments;
- }
-
- enum { MaxArguments = 0x10000 };
-
- private:
- enum NoParametersType { NoParameters };
-
- Arguments(CallFrame*);
- Arguments(CallFrame*, NoParametersType);
-
- void tearOffForInlineCallFrame(JSGlobalData& globalData, Register*, InlineCallFrame*);
+class Arguments : public JSDestructibleObject {
+ friend class JIT;
+ friend class DFG::SpeculativeJIT;
+public:
+ typedef JSDestructibleObject Base;
- public:
- static const ClassInfo s_info;
-
- static void visitChildren(JSCell*, SlotVisitor&);
-
- void fillArgList(ExecState*, MarkedArgumentBuffer&);
-
- uint32_t length(ExecState* exec) const
- {
- if (UNLIKELY(m_overrodeLength))
- return get(exec, exec->propertyNames().length).toUInt32(exec);
- return m_numArguments;
- }
-
- void copyToArguments(ExecState*, CallFrame*, uint32_t length);
- void tearOff(CallFrame*);
- void tearOff(CallFrame*, InlineCallFrame*);
- bool isTornOff() const { return m_registerArray; }
- void didTearOffActivation(ExecState*, JSActivation*);
-
- static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
- }
-
- protected:
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
-
- void finishCreation(CallFrame*);
- void finishCreation(CallFrame*, InlineCallFrame*);
-
- private:
- static void destroy(JSCell*);
- static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
- static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
- static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
- static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
- static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
- static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
- static bool deleteProperty(JSCell*, ExecState*, PropertyName);
- static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
- static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow);
- void createStrictModeCallerIfNecessary(ExecState*);
- void createStrictModeCalleeIfNecessary(ExecState*);
-
- bool isArgument(size_t);
- bool trySetArgument(JSGlobalData&, size_t argument, JSValue);
- JSValue tryGetArgument(size_t argument);
- bool isDeletedArgument(size_t);
- bool tryDeleteArgument(size_t);
- WriteBarrierBase<Unknown>& argument(size_t);
- void allocateSlowArguments();
-
- void init(CallFrame*);
-
- WriteBarrier<JSActivation> m_activation;
-
- unsigned m_numArguments;
-
- // We make these full byte booleans to make them easy to test from the JIT,
- // and because even if they were single-bit booleans we still wouldn't save
- // any space.
- bool m_overrodeLength;
- bool m_overrodeCallee;
- bool m_overrodeCaller;
- bool m_isStrictMode;
-
- WriteBarrierBase<Unknown>* m_registers;
- OwnArrayPtr<WriteBarrier<Unknown> > m_registerArray;
-
- OwnArrayPtr<SlowArgument> m_slowArguments;
-
- WriteBarrier<JSFunction> m_callee;
- };
-
- Arguments* asArguments(JSValue);
-
- inline Arguments* asArguments(JSValue value)
+ static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame)
{
- ASSERT(asObject(value)->inherits(&Arguments::s_info));
- return static_cast<Arguments*>(asObject(value));
+ Arguments* arguments = new (NotNull, allocateCell<Arguments>(globalData.heap)) Arguments(callFrame);
+ arguments->finishCreation(callFrame);
+ return arguments;
}
-
- inline Arguments::Arguments(CallFrame* callFrame)
- : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
+
+ static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame, InlineCallFrame* inlineCallFrame)
{
+ Arguments* arguments = new (NotNull, allocateCell<Arguments>(globalData.heap)) Arguments(callFrame);
+ arguments->finishCreation(callFrame, inlineCallFrame);
+ return arguments;
}
- inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
- : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
- {
- }
+ enum { MaxArguments = 0x10000 };
- inline void Arguments::allocateSlowArguments()
- {
- if (m_slowArguments)
- return;
- m_slowArguments = adoptArrayPtr(new SlowArgument[m_numArguments]);
- for (size_t i = 0; i < m_numArguments; ++i) {
- ASSERT(m_slowArguments[i].status == SlowArgument::Normal);
- m_slowArguments[i].index = CallFrame::argumentOffset(i);
- }
- }
+private:
+ enum NoParametersType { NoParameters };
+
+ Arguments(CallFrame*);
+ Arguments(CallFrame*, NoParametersType);
+
+ void tearOffForInlineCallFrame(JSGlobalData& globalData, Register*, InlineCallFrame*);
- inline bool Arguments::tryDeleteArgument(size_t argument)
- {
- if (!isArgument(argument))
- return false;
- allocateSlowArguments();
- m_slowArguments[argument].status = SlowArgument::Deleted;
- return true;
- }
+public:
+ static const ClassInfo s_info;
- inline bool Arguments::trySetArgument(JSGlobalData& globalData, size_t argument, JSValue value)
- {
- if (!isArgument(argument))
- return false;
- this->argument(argument).set(globalData, this, value);
- return true;
- }
+ static void visitChildren(JSCell*, SlotVisitor&);
- inline JSValue Arguments::tryGetArgument(size_t argument)
- {
- if (!isArgument(argument))
- return JSValue();
- return this->argument(argument).get();
- }
+ void fillArgList(ExecState*, MarkedArgumentBuffer&);
- inline bool Arguments::isDeletedArgument(size_t argument)
+ uint32_t length(ExecState* exec) const
{
- if (argument >= m_numArguments)
- return false;
- if (!m_slowArguments)
- return false;
- if (m_slowArguments[argument].status != SlowArgument::Deleted)
- return false;
- return true;
+ if (UNLIKELY(m_overrodeLength))
+ return get(exec, exec->propertyNames().length).toUInt32(exec);
+ return m_numArguments;
}
-
- inline bool Arguments::isArgument(size_t argument)
- {
- if (argument >= m_numArguments)
- return false;
- if (m_slowArguments && m_slowArguments[argument].status == SlowArgument::Deleted)
- return false;
- return true;
+
+ void copyToArguments(ExecState*, CallFrame*, uint32_t length);
+ void tearOff(CallFrame*);
+ void tearOff(CallFrame*, InlineCallFrame*);
+ bool isTornOff() const { return m_registerArray; }
+ void didTearOffActivation(ExecState*, JSActivation*);
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
}
-
- inline WriteBarrierBase<Unknown>& Arguments::argument(size_t argument)
- {
- ASSERT(isArgument(argument));
- if (!m_slowArguments)
- return m_registers[CallFrame::argumentOffset(argument)];
-
- int index = m_slowArguments[argument].index;
- if (!m_activation || m_slowArguments[argument].status != SlowArgument::Captured)
- return m_registers[index];
-
- return m_activation->registerAt(index);
+
+protected:
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
+
+ void finishCreation(CallFrame*);
+ void finishCreation(CallFrame*, InlineCallFrame*);
+
+private:
+ static void destroy(JSCell*);
+ static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
+ static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
+ static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
+ static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
+ static bool deleteProperty(JSCell*, ExecState*, PropertyName);
+ static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
+ static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow);
+ void createStrictModeCallerIfNecessary(ExecState*);
+ void createStrictModeCalleeIfNecessary(ExecState*);
+
+ bool isArgument(size_t);
+ bool trySetArgument(JSGlobalData&, size_t argument, JSValue);
+ JSValue tryGetArgument(size_t argument);
+ bool isDeletedArgument(size_t);
+ bool tryDeleteArgument(size_t);
+ WriteBarrierBase<Unknown>& argument(size_t);
+ void allocateSlowArguments();
+
+ void init(CallFrame*);
+
+ WriteBarrier<JSActivation> m_activation;
+
+ unsigned m_numArguments;
+
+ // We make these full byte booleans to make them easy to test from the JIT,
+ // and because even if they were single-bit booleans we still wouldn't save
+ // any space.
+ bool m_overrodeLength;
+ bool m_overrodeCallee;
+ bool m_overrodeCaller;
+ bool m_isStrictMode;
+
+ WriteBarrierBase<Unknown>* m_registers;
+ OwnArrayPtr<WriteBarrier<Unknown> > m_registerArray;
+
+ OwnArrayPtr<SlowArgument> m_slowArguments;
+
+ WriteBarrier<JSFunction> m_callee;
+};
+
+Arguments* asArguments(JSValue);
+
+inline Arguments* asArguments(JSValue value)
+{
+ ASSERT(asObject(value)->inherits(&Arguments::s_info));
+ return static_cast<Arguments*>(asObject(value));
+}
+
+inline Arguments::Arguments(CallFrame* callFrame)
+ : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
+{
+}
+
+inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
+ : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
+{
+}
+
+inline void Arguments::allocateSlowArguments()
+{
+ if (m_slowArguments)
+ return;
+ m_slowArguments = adoptArrayPtr(new SlowArgument[m_numArguments]);
+ for (size_t i = 0; i < m_numArguments; ++i) {
+ ASSERT(m_slowArguments[i].status == SlowArgument::Normal);
+ m_slowArguments[i].index = CallFrame::argumentOffset(i);
}
-
- inline void Arguments::finishCreation(CallFrame* callFrame)
- {
- Base::finishCreation(callFrame->globalData());
- ASSERT(inherits(&s_info));
-
- JSFunction* callee = jsCast<JSFunction*>(callFrame->callee());
- m_numArguments = callFrame->argumentCount();
- m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers());
- m_callee.set(callFrame->globalData(), this, callee);
- m_overrodeLength = false;
- m_overrodeCallee = false;
- m_overrodeCaller = false;
- m_isStrictMode = callFrame->codeBlock()->isStrictMode();
-
- SharedSymbolTable* symbolTable = callFrame->codeBlock()->symbolTable();
- const SlowArgument* slowArguments = symbolTable->slowArguments();
- if (slowArguments) {
- allocateSlowArguments();
- size_t count = std::min<unsigned>(m_numArguments, symbolTable->parameterCount());
- for (size_t i = 0; i < count; ++i)
- m_slowArguments[i] = slowArguments[i];
- }
-
- // The bytecode generator omits op_tear_off_activation in cases of no
- // declared parameters, so we need to tear off immediately.
- if (m_isStrictMode || !callee->jsExecutable()->parameterCount())
- tearOff(callFrame);
+}
+
+inline bool Arguments::tryDeleteArgument(size_t argument)
+{
+ if (!isArgument(argument))
+ return false;
+ allocateSlowArguments();
+ m_slowArguments[argument].status = SlowArgument::Deleted;
+ return true;
+}
+
+inline bool Arguments::trySetArgument(JSGlobalData& globalData, size_t argument, JSValue value)
+{
+ if (!isArgument(argument))
+ return false;
+ this->argument(argument).set(globalData, this, value);
+ return true;
+}
+
+inline JSValue Arguments::tryGetArgument(size_t argument)
+{
+ if (!isArgument(argument))
+ return JSValue();
+ return this->argument(argument).get();
+}
+
+inline bool Arguments::isDeletedArgument(size_t argument)
+{
+ if (argument >= m_numArguments)
+ return false;
+ if (!m_slowArguments)
+ return false;
+ if (m_slowArguments[argument].status != SlowArgument::Deleted)
+ return false;
+ return true;
+}
+
+inline bool Arguments::isArgument(size_t argument)
+{
+ if (argument >= m_numArguments)
+ return false;
+ if (m_slowArguments && m_slowArguments[argument].status == SlowArgument::Deleted)
+ return false;
+ return true;
+}
+
+inline WriteBarrierBase<Unknown>& Arguments::argument(size_t argument)
+{
+ ASSERT(isArgument(argument));
+ if (!m_slowArguments)
+ return m_registers[CallFrame::argumentOffset(argument)];
+
+ int index = m_slowArguments[argument].index;
+ if (!m_activation || m_slowArguments[argument].status != SlowArgument::Captured)
+ return m_registers[index];
+
+ return m_activation->registerAt(index);
+}
+
+inline void Arguments::finishCreation(CallFrame* callFrame)
+{
+ Base::finishCreation(callFrame->globalData());
+ ASSERT(inherits(&s_info));
+
+ JSFunction* callee = jsCast<JSFunction*>(callFrame->callee());
+ m_numArguments = callFrame->argumentCount();
+ m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers());
+ m_callee.set(callFrame->globalData(), this, callee);
+ m_overrodeLength = false;
+ m_overrodeCallee = false;
+ m_overrodeCaller = false;
+ m_isStrictMode = callFrame->codeBlock()->isStrictMode();
+
+ SharedSymbolTable* symbolTable = callFrame->codeBlock()->symbolTable();
+ const SlowArgument* slowArguments = symbolTable->slowArguments();
+ if (slowArguments) {
+ allocateSlowArguments();
+ size_t count = std::min<unsigned>(m_numArguments, symbolTable->parameterCount());
+ for (size_t i = 0; i < count; ++i)
+ m_slowArguments[i] = slowArguments[i];
}
- inline void Arguments::finishCreation(CallFrame* callFrame, InlineCallFrame* inlineCallFrame)
- {
- Base::finishCreation(callFrame->globalData());
- ASSERT(inherits(&s_info));
-
- JSFunction* callee = inlineCallFrame->callee.get();
- m_numArguments = inlineCallFrame->arguments.size() - 1;
- m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers()) + inlineCallFrame->stackOffset;
- m_callee.set(callFrame->globalData(), this, callee);
- m_overrodeLength = false;
- m_overrodeCallee = false;
- m_overrodeCaller = false;
- m_isStrictMode = jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->isStrictMode();
- ASSERT(!jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->symbolTable(inlineCallFrame->isCall ? CodeForCall : CodeForConstruct)->slowArguments());
-
- // The bytecode generator omits op_tear_off_activation in cases of no
- // declared parameters, so we need to tear off immediately.
- if (m_isStrictMode || !callee->jsExecutable()->parameterCount())
- tearOff(callFrame, inlineCallFrame);
- }
+ // The bytecode generator omits op_tear_off_activation in cases of no
+ // declared parameters, so we need to tear off immediately.
+ if (m_isStrictMode || !callee->jsExecutable()->parameterCount())
+ tearOff(callFrame);
+}
+
+inline void Arguments::finishCreation(CallFrame* callFrame, InlineCallFrame* inlineCallFrame)
+{
+ Base::finishCreation(callFrame->globalData());
+ ASSERT(inherits(&s_info));
+
+ JSFunction* callee = inlineCallFrame->callee.get();
+ m_numArguments = inlineCallFrame->arguments.size() - 1;
+ m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers()) + inlineCallFrame->stackOffset;
+ m_callee.set(callFrame->globalData(), this, callee);
+ m_overrodeLength = false;
+ m_overrodeCallee = false;
+ m_overrodeCaller = false;
+ m_isStrictMode = jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->isStrictMode();
+ ASSERT(!jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->symbolTable(inlineCallFrame->isCall ? CodeForCall : CodeForConstruct)->slowArguments());
+
+ // The bytecode generator omits op_tear_off_activation in cases of no
+ // declared parameters, so we need to tear off immediately.
+ if (m_isStrictMode || !callee->jsExecutable()->parameterCount())
+ tearOff(callFrame, inlineCallFrame);
+}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp
index 5c2cd7167..a3fce45f2 100644
--- a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp
@@ -25,8 +25,8 @@
#include "ArrayConstructor.h"
#include "ArrayPrototype.h"
-#include "ButterflyInlineMethods.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "ButterflyInlines.h"
+#include "CopiedSpaceInlines.h"
#include "Error.h"
#include "ExceptionHelpers.h"
#include "JSArray.h"
@@ -77,15 +77,15 @@ bool ArrayConstructor::getOwnPropertyDescriptor(JSObject* object, ExecState* exe
// ------------------------------ Functions ---------------------------
-JSObject* constructArrayWithSizeQuirk(ExecState* exec, JSGlobalObject* globalObject, JSValue length)
+JSObject* constructArrayWithSizeQuirk(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, JSValue length)
{
if (!length.isNumber())
- return constructArray(exec, globalObject, &length, 1);
+ return constructArray(exec, profile, globalObject, &length, 1);
uint32_t n = length.toUInt32(exec);
if (n != length.toNumber(exec))
return throwError(exec, createRangeError(exec, ASCIILiteral("Array size is not a small enough positive integer.")));
- return constructEmptyArray(exec, globalObject, n);
+ return constructEmptyArray(exec, profile, globalObject, n);
}
static inline JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgList& args)
@@ -94,10 +94,10 @@ static inline JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgLi
// a single numeric argument denotes the array size (!)
if (args.size() == 1)
- return constructArrayWithSizeQuirk(exec, globalObject, args.at(0));
+ return constructArrayWithSizeQuirk(exec, 0, globalObject, args.at(0));
// otherwise the array is constructed with the arguments in it
- return constructArray(exec, globalObject, args);
+ return constructArray(exec, 0, globalObject, args);
}
static EncodedJSValue JSC_HOST_CALL constructWithArrayConstructor(ExecState* exec)
diff --git a/Source/JavaScriptCore/runtime/ArrayConstructor.h b/Source/JavaScriptCore/runtime/ArrayConstructor.h
index dcbf0a1b3..96860b0fc 100644
--- a/Source/JavaScriptCore/runtime/ArrayConstructor.h
+++ b/Source/JavaScriptCore/runtime/ArrayConstructor.h
@@ -25,42 +25,42 @@
namespace JSC {
- class ArrayPrototype;
- class JSArray;
+class ArrayPrototype;
+class JSArray;
- class ArrayConstructor : public InternalFunction {
- public:
- typedef InternalFunction Base;
+class ArrayConstructor : public InternalFunction {
+public:
+ typedef InternalFunction Base;
- static ArrayConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, ArrayPrototype* arrayPrototype)
- {
- ArrayConstructor* constructor = new (NotNull, allocateCell<ArrayConstructor>(*exec->heap())) ArrayConstructor(globalObject, structure);
- constructor->finishCreation(exec, arrayPrototype);
- return constructor;
- }
+ static ArrayConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, ArrayPrototype* arrayPrototype)
+ {
+ ArrayConstructor* constructor = new (NotNull, allocateCell<ArrayConstructor>(*exec->heap())) ArrayConstructor(globalObject, structure);
+ constructor->finishCreation(exec, arrayPrototype);
+ return constructor;
+ }
- static const ClassInfo s_info;
+ static const ClassInfo s_info;
- static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
- }
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
- protected:
- void finishCreation(ExecState*, ArrayPrototype*);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags;
+protected:
+ void finishCreation(ExecState*, ArrayPrototype*);
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags;
- private:
- ArrayConstructor(JSGlobalObject*, Structure*);
- static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
+private:
+ ArrayConstructor(JSGlobalObject*, Structure*);
+ static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
- static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
- static ConstructType getConstructData(JSCell*, ConstructData&);
- static CallType getCallData(JSCell*, CallData&);
- };
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+};
- JSObject* constructArrayWithSizeQuirk(ExecState*, JSGlobalObject*, JSValue);
+JSObject* constructArrayWithSizeQuirk(ExecState*, ArrayAllocationProfile*, JSGlobalObject*, JSValue);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp
index 6975dc778..cc847d8ff 100644
--- a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp
@@ -24,10 +24,10 @@
#include "config.h"
#include "ArrayPrototype.h"
-#include "ButterflyInlineMethods.h"
+#include "ButterflyInlines.h"
#include "CachedCall.h"
#include "CodeBlock.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "CopiedSpaceInlines.h"
#include "Interpreter.h"
#include "JIT.h"
#include "JSStringBuilder.h"
@@ -456,7 +456,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec)
EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec)
{
JSValue thisValue = exec->hostThisValue();
- JSArray* arr = constructEmptyArray(exec);
+ JSArray* arr = constructEmptyArray(exec, 0);
unsigned n = 0;
JSValue curArg = thisValue.toObject(exec);
if (exec->hadException())
@@ -618,7 +618,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec)
return JSValue::encode(jsUndefined());
// We return a new array
- JSArray* resObj = constructEmptyArray(exec);
+ JSArray* resObj = constructEmptyArray(exec, 0);
JSValue result = resObj;
unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
@@ -733,7 +733,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
return JSValue::encode(jsUndefined());
if (!exec->argumentCount())
- return JSValue::encode(constructEmptyArray(exec));
+ return JSValue::encode(constructEmptyArray(exec, 0));
unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
@@ -748,7 +748,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
deleteCount = static_cast<unsigned>(deleteDouble);
}
- JSArray* resObj = JSArray::tryCreateUninitialized(exec->globalData(), exec->lexicalGlobalObject()->arrayStructure(), deleteCount);
+ JSArray* resObj = JSArray::tryCreateUninitialized(exec->globalData(), exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), deleteCount);
if (!resObj)
return JSValue::encode(throwOutOfMemoryError(exec));
@@ -820,7 +820,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec)
return throwVMTypeError(exec);
JSValue applyThis = exec->argument(1);
- JSArray* resultArray = constructEmptyArray(exec);
+ JSArray* resultArray = constructEmptyArray(exec, 0);
unsigned filterIndex = 0;
unsigned k = 0;
@@ -880,7 +880,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec)
JSValue applyThis = exec->argument(1);
- JSArray* resultArray = constructEmptyArray(exec, length);
+ JSArray* resultArray = constructEmptyArray(exec, 0, length);
unsigned k = 0;
if (callType == CallTypeJS && isJSArray(thisObj)) {
JSFunction* f = jsCast<JSFunction*>(function);
diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.h b/Source/JavaScriptCore/runtime/ArrayPrototype.h
index b33021121..2b83d39b7 100644
--- a/Source/JavaScriptCore/runtime/ArrayPrototype.h
+++ b/Source/JavaScriptCore/runtime/ArrayPrototype.h
@@ -26,28 +26,28 @@
namespace JSC {
- class ArrayPrototype : public JSArray {
- private:
- ArrayPrototype(JSGlobalObject*, Structure*, Butterfly*);
+class ArrayPrototype : public JSArray {
+private:
+ ArrayPrototype(JSGlobalObject*, Structure*, Butterfly*);
- public:
- typedef JSArray Base;
+public:
+ typedef JSArray Base;
- static ArrayPrototype* create(ExecState*, JSGlobalObject*, Structure*);
+ static ArrayPrototype* create(ExecState*, JSGlobalObject*, Structure*);
- static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
- static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
+ static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
- static const ClassInfo s_info;
+ static const ClassInfo s_info;
- static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info, ArrayWithArrayStorage);
- }
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info, ArrayWithArrayStorage);
+ }
- protected:
- void finishCreation(JSGlobalObject*);
- };
+protected:
+ void finishCreation(JSGlobalObject*);
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Butterfly.h b/Source/JavaScriptCore/runtime/Butterfly.h
index cb93aea8a..4b8d53f7e 100644
--- a/Source/JavaScriptCore/runtime/Butterfly.h
+++ b/Source/JavaScriptCore/runtime/Butterfly.h
@@ -88,12 +88,18 @@ public:
template<typename T>
T* indexingPayload() { return reinterpret_cast<T*>(this); }
ArrayStorage* arrayStorage() { return indexingPayload<ArrayStorage>(); }
+ WriteBarrier<Unknown>* contiguousInt32() { return indexingPayload<WriteBarrier<Unknown> >(); }
+ double* contiguousDouble() { return indexingPayload<double>(); }
WriteBarrier<Unknown>* contiguous() { return indexingPayload<WriteBarrier<Unknown> >(); }
static Butterfly* fromContiguous(WriteBarrier<Unknown>* contiguous)
{
return reinterpret_cast<Butterfly*>(contiguous);
}
+ static Butterfly* fromContiguous(double* contiguous)
+ {
+ return reinterpret_cast<Butterfly*>(contiguous);
+ }
static ptrdiff_t offsetOfPropertyStorage() { return -static_cast<ptrdiff_t>(sizeof(IndexingHeader)); }
static int indexOfPropertyStorage()
diff --git a/Source/JavaScriptCore/runtime/ButterflyInlineMethods.h b/Source/JavaScriptCore/runtime/ButterflyInlines.h
index 86a836bef..9167497a4 100644
--- a/Source/JavaScriptCore/runtime/ButterflyInlineMethods.h
+++ b/Source/JavaScriptCore/runtime/ButterflyInlines.h
@@ -23,12 +23,12 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ButterflyInlineMethods_h
-#define ButterflyInlineMethods_h
+#ifndef ButterflyInlines_h
+#define ButterflyInlines_h
#include "ArrayStorage.h"
#include "Butterfly.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "CopiedSpaceInlines.h"
#include "CopyVisitor.h"
#include "JSGlobalData.h"
#include "Structure.h"
@@ -61,8 +61,9 @@ inline Butterfly* Butterfly::create(JSGlobalData& globalData, Structure* structu
inline Butterfly* Butterfly::createUninitializedDuringCollection(CopyVisitor& visitor, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes)
{
+ size_t size = totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
Butterfly* result = fromBase(
- visitor.allocateNewSpace(totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes)),
+ visitor.allocateNewSpace(size),
preCapacity, propertyCapacity);
return result;
}
@@ -175,5 +176,5 @@ inline Butterfly* Butterfly::shift(Structure* structure, size_t numberOfSlots)
} // namespace JSC
-#endif // ButterflyInlineMethods_h
+#endif // ButterflyInlines_h
diff --git a/Source/JavaScriptCore/runtime/CodeCache.cpp b/Source/JavaScriptCore/runtime/CodeCache.cpp
index 4de760e49..068919528 100644
--- a/Source/JavaScriptCore/runtime/CodeCache.cpp
+++ b/Source/JavaScriptCore/runtime/CodeCache.cpp
@@ -36,7 +36,6 @@
namespace JSC {
CodeCache::CodeCache()
- : m_randomGenerator(static_cast<uint32_t>(randomNumber() * UINT32_MAX))
{
}
@@ -67,9 +66,9 @@ UnlinkedCodeBlockType* CodeCache::getCodeBlock(JSGlobalData& globalData, Executa
CodeBlockKey key = makeCodeBlockKey(source, CacheTypes<UnlinkedCodeBlockType>::codeType, strictness);
bool storeInCache = false;
if (debuggerMode == DebuggerOff && profilerMode == ProfilerOff) {
- CodeBlockIndicesMap::iterator result = m_cachedCodeBlockIndices.find(key);
- if (result != m_cachedCodeBlockIndices.end()) {
- UnlinkedCodeBlockType* unlinkedCode = jsCast<UnlinkedCodeBlockType*>(m_cachedCodeBlocks[result->value].second.get());
+ const Strong<UnlinkedCodeBlock>* result = m_cachedCodeBlocks.find(key);
+ if (result) {
+ UnlinkedCodeBlockType* unlinkedCode = jsCast<UnlinkedCodeBlockType*>(result->get());
unsigned firstLine = source.firstLine() + unlinkedCode->firstLine();
executable->recordParse(unlinkedCode->codeFeatures(), unlinkedCode->hasCapturedVariables(), firstLine, firstLine + unlinkedCode->lineCount());
return unlinkedCode;
@@ -91,14 +90,8 @@ UnlinkedCodeBlockType* CodeCache::getCodeBlock(JSGlobalData& globalData, Executa
if (error.m_type != ParserError::ErrorNone)
return 0;
- if (storeInCache) {
- size_t index = m_randomGenerator.getUint32() % kMaxCodeBlockEntries;
- if (m_cachedCodeBlocks[index].second)
- m_cachedCodeBlockIndices.remove(m_cachedCodeBlocks[index].first);
- m_cachedCodeBlockIndices.set(key, index);
- m_cachedCodeBlocks[index].second.set(globalData, unlinkedCode);
- m_cachedCodeBlocks[index].first = key;
- }
+ if (storeInCache)
+ m_cachedCodeBlocks.add(key, Strong<UnlinkedCodeBlock>(globalData, unlinkedCode));
return unlinkedCode;
}
@@ -133,6 +126,7 @@ UnlinkedFunctionCodeBlock* CodeCache::generateFunctionCodeBlock(JSGlobalData& gl
body->destroyData();
if (error.m_type != ParserError::ErrorNone)
return 0;
+ m_cachedFunctionCode.add(result, Strong<UnlinkedFunctionCodeBlock>(globalData, result));
return result;
}
@@ -149,9 +143,9 @@ CodeCache::GlobalFunctionKey CodeCache::makeGlobalFunctionKey(const SourceCode&
UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(JSGlobalData& globalData, const Identifier& name, const SourceCode& source, ParserError& error)
{
GlobalFunctionKey key = makeGlobalFunctionKey(source, name.string());
- GlobalFunctionIndicesMap::iterator result = m_cachedGlobalFunctionIndices.find(key);
- if (result != m_cachedGlobalFunctionIndices.end())
- return m_cachedGlobalFunctions[result->value].second.get();
+ const Strong<UnlinkedFunctionExecutable>* result = m_cachedGlobalFunctions.find(key);
+ if (result)
+ return result->get();
RefPtr<ProgramNode> program = parse<ProgramNode>(&globalData, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error);
if (!program) {
@@ -173,14 +167,13 @@ UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(JSGlo
UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&globalData, source, body);
functionExecutable->m_nameValue.set(globalData, functionExecutable, jsString(&globalData, name.string()));
- size_t index = m_randomGenerator.getUint32() % kMaxGlobalFunctionEntries;
- if (m_cachedGlobalFunctions[index].second)
- m_cachedGlobalFunctionIndices.remove(m_cachedGlobalFunctions[index].first);
- m_cachedGlobalFunctionIndices.set(key, index);
- m_cachedGlobalFunctions[index].second.set(globalData, functionExecutable);
- m_cachedGlobalFunctions[index].first = key;
-
+ m_cachedGlobalFunctions.add(key, Strong<UnlinkedFunctionExecutable>(globalData, functionExecutable));
return functionExecutable;
}
+void CodeCache::usedFunctionCode(JSGlobalData& globalData, UnlinkedFunctionCodeBlock* codeBlock)
+{
+ m_cachedFunctionCode.add(codeBlock, Strong<UnlinkedFunctionCodeBlock>(globalData, codeBlock));
+}
+
}
diff --git a/Source/JavaScriptCore/runtime/CodeCache.h b/Source/JavaScriptCore/runtime/CodeCache.h
index 4d4617189..740aaa6df 100644
--- a/Source/JavaScriptCore/runtime/CodeCache.h
+++ b/Source/JavaScriptCore/runtime/CodeCache.h
@@ -34,6 +34,7 @@
#include <wtf/FixedArray.h>
#include <wtf/Forward.h>
#include <wtf/PassOwnPtr.h>
+#include <wtf/RandomNumber.h>
#include <wtf/text/WTFString.h>
namespace JSC {
@@ -51,6 +52,41 @@ struct ParserError;
class SourceCode;
class SourceProvider;
+template <typename KeyType, typename EntryType, int CacheSize> class Thingy {
+ typedef typename HashMap<KeyType, unsigned>::iterator iterator;
+public:
+ Thingy()
+ : m_randomGenerator((static_cast<uint32_t>(randomNumber() * UINT32_MAX)))
+ {
+ }
+ const EntryType* find(const KeyType& key)
+ {
+ iterator result = m_map.find(key);
+ if (result == m_map.end())
+ return 0;
+ return &m_data[result->value].second;
+ }
+ void add(const KeyType& key, const EntryType& value)
+ {
+ iterator result = m_map.find(key);
+ if (result != m_map.end()) {
+ m_data[result->value].second = value;
+ return;
+ }
+ size_t newIndex = m_randomGenerator.getUint32() % CacheSize;
+ if (m_data[newIndex].second)
+ m_map.remove(m_data[newIndex].first);
+ m_map.add(key, newIndex);
+ m_data[newIndex].first = key;
+ m_data[newIndex].second = value;
+ ASSERT(m_map.size() <= CacheSize);
+ }
+private:
+ HashMap<KeyType, unsigned> m_map;
+ FixedArray<std::pair<KeyType, EntryType>, CacheSize> m_data;
+ WeakRandom m_randomGenerator;
+};
+
class CodeCache {
public:
static PassOwnPtr<CodeCache> create() { return adoptPtr(new CodeCache); }
@@ -59,13 +95,12 @@ public:
UnlinkedEvalCodeBlock* getEvalCodeBlock(JSGlobalData&, EvalExecutable*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&);
UnlinkedFunctionCodeBlock* getFunctionCodeBlock(JSGlobalData&, UnlinkedFunctionExecutable*, const SourceCode&, CodeSpecializationKind, DebuggerMode, ProfilerMode, ParserError&);
UnlinkedFunctionExecutable* getFunctionExecutableFromGlobalCode(JSGlobalData&, const Identifier&, const SourceCode&, ParserError&);
+ void usedFunctionCode(JSGlobalData&, UnlinkedFunctionCodeBlock*);
~CodeCache();
enum CodeType { EvalType, ProgramType, FunctionType };
typedef std::pair<String, unsigned> CodeBlockKey;
- typedef HashMap<CodeBlockKey, unsigned> CodeBlockIndicesMap;
typedef std::pair<String, String> GlobalFunctionKey;
- typedef HashMap<GlobalFunctionKey, unsigned> GlobalFunctionIndicesMap;
private:
CodeCache();
@@ -74,18 +109,17 @@ private:
template <class UnlinkedCodeBlockType, class ExecutableType> inline UnlinkedCodeBlockType* getCodeBlock(JSGlobalData&, ExecutableType*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&);
CodeBlockKey makeCodeBlockKey(const SourceCode&, CodeType, JSParserStrictness);
- CodeBlockIndicesMap m_cachedCodeBlockIndices;
GlobalFunctionKey makeGlobalFunctionKey(const SourceCode&, const String&);
- GlobalFunctionIndicesMap m_cachedGlobalFunctionIndices;
enum {
kMaxCodeBlockEntries = 1024,
- kMaxGlobalFunctionEntries = 1024
+ kMaxGlobalFunctionEntries = 1024,
+ kMaxFunctionCodeBlocks = 1024
};
- FixedArray<std::pair<CodeBlockKey, Strong<UnlinkedCodeBlock> >, kMaxCodeBlockEntries> m_cachedCodeBlocks;
- FixedArray<std::pair<GlobalFunctionKey, Strong<UnlinkedFunctionExecutable> >, kMaxGlobalFunctionEntries> m_cachedGlobalFunctions;
- WeakRandom m_randomGenerator;
+ Thingy<CodeBlockKey, Strong<UnlinkedCodeBlock>, kMaxCodeBlockEntries> m_cachedCodeBlocks;
+ Thingy<GlobalFunctionKey, Strong<UnlinkedFunctionExecutable>, kMaxGlobalFunctionEntries> m_cachedGlobalFunctions;
+ Thingy<UnlinkedFunctionCodeBlock*, Strong<UnlinkedFunctionCodeBlock>, kMaxFunctionCodeBlocks> m_cachedFunctionCode;
};
}
diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp
index 20a2e2acb..49a0e256d 100644
--- a/Source/JavaScriptCore/runtime/Executable.cpp
+++ b/Source/JavaScriptCore/runtime/Executable.cpp
@@ -620,18 +620,17 @@ void FunctionExecutable::clearCodeIfNotCompiling()
clearCode();
}
-void FunctionExecutable::clearUnlinkedCodeIfNotCompiling()
+void FunctionExecutable::clearUnlinkedCodeForRecompilationIfNotCompiling()
{
if (isCompiling())
return;
- m_unlinkedExecutable->clearCode();
+ m_unlinkedExecutable->clearCodeForRecompilation();
}
void FunctionExecutable::clearCode()
{
m_codeBlockForCall.clear();
m_codeBlockForConstruct.clear();
- m_unlinkedExecutable->clearCode();
Base::clearCode();
}
diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h
index 74b4add75..98471b85b 100644
--- a/Source/JavaScriptCore/runtime/Executable.h
+++ b/Source/JavaScriptCore/runtime/Executable.h
@@ -704,7 +704,7 @@ namespace JSC {
SharedSymbolTable* symbolTable(CodeSpecializationKind kind) const { return m_unlinkedExecutable->symbolTable(kind); }
void clearCodeIfNotCompiling();
- void clearUnlinkedCodeIfNotCompiling();
+ void clearUnlinkedCodeForRecompilationIfNotCompiling();
static void visitChildren(JSCell*, SlotVisitor&);
static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
{
diff --git a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp
index a4b2202c1..8e4390b1b 100644
--- a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp
@@ -186,7 +186,7 @@ EncodedJSValue JSC_HOST_CALL functionProtoFuncBind(ExecState* exec)
// Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (arg1, arg2 etc), in order.
size_t numBoundArgs = exec->argumentCount() > 1 ? exec->argumentCount() - 1 : 0;
- JSArray* boundArgs = JSArray::tryCreateUninitialized(exec->globalData(), globalObject->arrayStructure(), numBoundArgs);
+ JSArray* boundArgs = JSArray::tryCreateUninitialized(exec->globalData(), globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), numBoundArgs);
if (!boundArgs)
return JSValue::encode(throwOutOfMemoryError(exec));
diff --git a/Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h b/Source/JavaScriptCore/runtime/IndexingHeaderInlines.h
index 22785ce24..cfad1c8c2 100644
--- a/Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h
+++ b/Source/JavaScriptCore/runtime/IndexingHeaderInlines.h
@@ -23,8 +23,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef IndexingHeaderInlineMethods_h
-#define IndexingHeaderInlineMethods_h
+#ifndef IndexingHeaderInlines_h
+#define IndexingHeaderInlines_h
#include "ArrayStorage.h"
#include "IndexingHeader.h"
@@ -43,6 +43,9 @@ inline size_t IndexingHeader::preCapacity(Structure* structure)
inline size_t IndexingHeader::indexingPayloadSizeInBytes(Structure* structure)
{
switch (structure->indexingType()) {
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return vectorLength() * sizeof(EncodedJSValue);
@@ -57,5 +60,5 @@ inline size_t IndexingHeader::indexingPayloadSizeInBytes(Structure* structure)
} // namespace JSC
-#endif // IndexingHeaderInlineMethods_h
+#endif // IndexingHeaderInlines_h
diff --git a/Source/JavaScriptCore/runtime/IndexingType.cpp b/Source/JavaScriptCore/runtime/IndexingType.cpp
index 7261847a2..dc2733ad1 100644
--- a/Source/JavaScriptCore/runtime/IndexingType.cpp
+++ b/Source/JavaScriptCore/runtime/IndexingType.cpp
@@ -31,6 +31,46 @@
namespace JSC {
+IndexingType leastUpperBoundOfIndexingTypes(IndexingType a, IndexingType b)
+{
+ // It doesn't make sense to LUB something that is an array with something that isn't.
+ ASSERT((a & IsArray) == (b & IsArray));
+
+ // Boy, this sure is easy right now.
+ return std::max(a, b);
+}
+
+IndexingType leastUpperBoundOfIndexingTypeAndType(IndexingType indexingType, SpeculatedType type)
+{
+ if (!type)
+ return indexingType;
+ switch (indexingType) {
+ case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ case ALL_INT32_INDEXING_TYPES:
+ if (isInt32Speculation(type))
+ return (indexingType & ~IndexingShapeMask) | Int32Shape;
+ if (isNumberSpeculation(type))
+ return (indexingType & ~IndexingShapeMask) | DoubleShape;
+ return (indexingType & ~IndexingShapeMask) | ContiguousShape;
+ case ALL_DOUBLE_INDEXING_TYPES:
+ if (isNumberSpeculation(type))
+ return indexingType;
+ return (indexingType & ~IndexingShapeMask) | ContiguousShape;
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ return indexingType;
+ default:
+ CRASH();
+ return 0;
+ }
+}
+
+IndexingType leastUpperBoundOfIndexingTypeAndValue(IndexingType indexingType, JSValue value)
+{
+ return leastUpperBoundOfIndexingTypeAndType(indexingType, speculationFromValue(value));
+}
+
const char* indexingTypeToString(IndexingType indexingType)
{
static char result[128];
@@ -39,6 +79,12 @@ const char* indexingTypeToString(IndexingType indexingType)
case NonArray:
basicName = "NonArray";
break;
+ case NonArrayWithInt32:
+ basicName = "NonArrayWithInt32";
+ break;
+ case NonArrayWithDouble:
+ basicName = "NonArrayWithDouble";
+ break;
case NonArrayWithContiguous:
basicName = "NonArrayWithContiguous";
break;
@@ -51,6 +97,15 @@ const char* indexingTypeToString(IndexingType indexingType)
case ArrayClass:
basicName = "ArrayClass";
break;
+ case ArrayWithUndecided:
+ basicName = "ArrayWithUndecided";
+ break;
+ case ArrayWithInt32:
+ basicName = "ArrayWithInt32";
+ break;
+ case ArrayWithDouble:
+ basicName = "ArrayWithDouble";
+ break;
case ArrayWithContiguous:
basicName = "ArrayWithContiguous";
break;
diff --git a/Source/JavaScriptCore/runtime/IndexingType.h b/Source/JavaScriptCore/runtime/IndexingType.h
index 4bbe3cfa0..ab253be1e 100644
--- a/Source/JavaScriptCore/runtime/IndexingType.h
+++ b/Source/JavaScriptCore/runtime/IndexingType.h
@@ -26,6 +26,7 @@
#ifndef IndexingType_h
#define IndexingType_h
+#include "SpeculatedType.h"
#include <wtf/StdLibExtras.h>
namespace JSC {
@@ -37,21 +38,32 @@ static const IndexingType IsArray = 1;
// The shape of the indexed property storage.
static const IndexingType IndexingShapeMask = 30;
-static const IndexingType NoIndexingShape = 0;
+static const IndexingType NoIndexingShape = 0;
+static const IndexingType UndecidedShape = 2; // Only useful for arrays.
+static const IndexingType Int32Shape = 20;
+static const IndexingType DoubleShape = 22;
static const IndexingType ContiguousShape = 26;
static const IndexingType ArrayStorageShape = 28;
static const IndexingType SlowPutArrayStorageShape = 30;
+static const IndexingType IndexingShapeShift = 1;
+static const IndexingType NumberOfIndexingShapes = 16;
+
// Additional flags for tracking the history of the type. These are usually
// masked off unless you ask for them directly.
static const IndexingType MayHaveIndexedAccessors = 32;
// List of acceptable array types.
static const IndexingType NonArray = 0;
+static const IndexingType NonArrayWithInt32 = Int32Shape;
+static const IndexingType NonArrayWithDouble = DoubleShape;
static const IndexingType NonArrayWithContiguous = ContiguousShape;
static const IndexingType NonArrayWithArrayStorage = ArrayStorageShape;
static const IndexingType NonArrayWithSlowPutArrayStorage = SlowPutArrayStorageShape;
static const IndexingType ArrayClass = IsArray; // I'd want to call this "Array" but this would lead to disastrous namespace pollution.
+static const IndexingType ArrayWithUndecided = IsArray | UndecidedShape;
+static const IndexingType ArrayWithInt32 = IsArray | Int32Shape;
+static const IndexingType ArrayWithDouble = IsArray | DoubleShape;
static const IndexingType ArrayWithContiguous = IsArray | ContiguousShape;
static const IndexingType ArrayWithArrayStorage = IsArray | ArrayStorageShape;
static const IndexingType ArrayWithSlowPutArrayStorage = IsArray | SlowPutArrayStorageShape;
@@ -60,6 +72,17 @@ static const IndexingType ArrayWithSlowPutArrayStorage = IsArray | SlowPutArr
NonArray: \
case ArrayClass
+#define ALL_UNDECIDED_INDEXING_TYPES \
+ ArrayWithUndecided
+
+#define ALL_INT32_INDEXING_TYPES \
+ NonArrayWithInt32: \
+ case ArrayWithInt32
+
+#define ALL_DOUBLE_INDEXING_TYPES \
+ NonArrayWithDouble: \
+ case ArrayWithDouble
+
#define ALL_CONTIGUOUS_INDEXING_TYPES \
NonArrayWithContiguous: \
case ArrayWithContiguous
@@ -83,6 +106,21 @@ static inline bool hasIndexingHeader(IndexingType type)
return hasIndexedProperties(type);
}
+static inline bool hasUndecided(IndexingType indexingType)
+{
+ return (indexingType & IndexingShapeMask) == UndecidedShape;
+}
+
+static inline bool hasInt32(IndexingType indexingType)
+{
+ return (indexingType & IndexingShapeMask) == Int32Shape;
+}
+
+static inline bool hasDouble(IndexingType indexingType)
+{
+ return (indexingType & IndexingShapeMask) == DoubleShape;
+}
+
static inline bool hasContiguous(IndexingType indexingType)
{
return (indexingType & IndexingShapeMask) == ContiguousShape;
@@ -105,6 +143,12 @@ static inline bool shouldUseSlowPut(IndexingType indexingType)
return (indexingType & IndexingShapeMask) == SlowPutArrayStorageShape;
}
+// Return an indexing type that can handle all of the elements of both indexing types.
+IndexingType leastUpperBoundOfIndexingTypes(IndexingType, IndexingType);
+
+IndexingType leastUpperBoundOfIndexingTypeAndType(IndexingType, SpeculatedType);
+IndexingType leastUpperBoundOfIndexingTypeAndValue(IndexingType, JSValue);
+
const char* indexingTypeToString(IndexingType);
// Mask of all possible types.
diff --git a/Source/JavaScriptCore/runtime/JSActivation.h b/Source/JavaScriptCore/runtime/JSActivation.h
index fc6336463..b8f5621af 100644
--- a/Source/JavaScriptCore/runtime/JSActivation.h
+++ b/Source/JavaScriptCore/runtime/JSActivation.h
@@ -30,7 +30,7 @@
#define JSActivation_h
#include "CodeBlock.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "CopiedSpaceInlines.h"
#include "JSVariableObject.h"
#include "Nodes.h"
#include "SymbolTable.h"
diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp
index d1ece1a36..4ba5cc2bd 100644
--- a/Source/JavaScriptCore/runtime/JSArray.cpp
+++ b/Source/JavaScriptCore/runtime/JSArray.cpp
@@ -24,14 +24,14 @@
#include "JSArray.h"
#include "ArrayPrototype.h"
-#include "ButterflyInlineMethods.h"
-#include "CopiedSpace.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "ButterflyInlines.h"
#include "CachedCall.h"
+#include "CopiedSpace.h"
+#include "CopiedSpaceInlines.h"
#include "Error.h"
#include "Executable.h"
#include "GetterSetter.h"
-#include "IndexingHeaderInlineMethods.h"
+#include "IndexingHeaderInlines.h"
#include "PropertyNameArray.h"
#include "Reject.h"
#include <wtf/AVLTree.h>
@@ -410,25 +410,33 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException
exec, newLength, throwException,
convertContiguousToArrayStorage(exec->globalData()));
}
- createInitialContiguous(exec->globalData(), newLength);
+ createInitialUndecided(exec->globalData(), newLength);
return true;
+ case ArrayWithUndecided:
+ case ArrayWithInt32:
+ case ArrayWithDouble:
case ArrayWithContiguous:
if (newLength == m_butterfly->publicLength())
return true;
if (newLength >= MAX_ARRAY_INDEX // This case ensures that we can do fast push.
|| (newLength >= MIN_SPARSE_ARRAY_INDEX
- && !isDenseEnoughForVector(newLength, countElementsInContiguous(m_butterfly)))) {
+ && !isDenseEnoughForVector(newLength, countElements()))) {
return setLengthWithArrayStorage(
exec, newLength, throwException,
- convertContiguousToArrayStorage(exec->globalData()));
+ ensureArrayStorage(exec->globalData()));
}
if (newLength > m_butterfly->publicLength()) {
- ensureContiguousLength(exec->globalData(), newLength);
+ ensureLength(exec->globalData(), newLength);
return true;
}
- for (unsigned i = m_butterfly->publicLength(); i-- > newLength;)
- m_butterfly->contiguous()[i].clear();
+ if (structure()->indexingType() == ArrayWithDouble) {
+ for (unsigned i = m_butterfly->publicLength(); i-- > newLength;)
+ m_butterfly->contiguousDouble()[i] = QNaN;
+ } else {
+ for (unsigned i = m_butterfly->publicLength(); i-- > newLength;)
+ m_butterfly->contiguous()[i].clear();
+ }
m_butterfly->setPublicLength(newLength);
return true;
@@ -448,6 +456,13 @@ JSValue JSArray::pop(ExecState* exec)
case ArrayClass:
return jsUndefined();
+ case ArrayWithUndecided:
+ if (!m_butterfly->publicLength())
+ return jsUndefined();
+ // We have nothing but holes. So, drop down to the slow version.
+ break;
+
+ case ArrayWithInt32:
case ArrayWithContiguous: {
unsigned length = m_butterfly->publicLength();
@@ -464,6 +479,22 @@ JSValue JSArray::pop(ExecState* exec)
break;
}
+ case ArrayWithDouble: {
+ unsigned length = m_butterfly->publicLength();
+
+ if (!length--)
+ return jsUndefined();
+
+ ASSERT(length < m_butterfly->vectorLength());
+ double value = m_butterfly->contiguousDouble()[length];
+ if (value == value) {
+ m_butterfly->contiguousDouble()[length] = QNaN;
+ m_butterfly->setPublicLength(length);
+ return JSValue(JSValue::EncodeAsDouble, value);
+ }
+ break;
+ }
+
case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = m_butterfly->arrayStorage();
@@ -518,10 +549,42 @@ void JSArray::push(ExecState* exec, JSValue value)
{
switch (structure()->indexingType()) {
case ArrayClass: {
- putByIndexBeyondVectorLengthWithArrayStorage(exec, 0, value, true, createInitialArrayStorage(exec->globalData()));
- break;
+ createInitialUndecided(exec->globalData(), 0);
+ // Fall through.
+ }
+
+ case ArrayWithUndecided: {
+ convertUndecidedForValue(exec->globalData(), value);
+ push(exec, value);
+ return;
}
+ case ArrayWithInt32: {
+ if (!value.isInt32()) {
+ convertInt32ForValue(exec->globalData(), value);
+ push(exec, value);
+ return;
+ }
+
+ unsigned length = m_butterfly->publicLength();
+ ASSERT(length <= m_butterfly->vectorLength());
+ if (length < m_butterfly->vectorLength()) {
+ m_butterfly->contiguousInt32()[length].setWithoutWriteBarrier(value);
+ m_butterfly->setPublicLength(length + 1);
+ return;
+ }
+
+ if (length > MAX_ARRAY_INDEX) {
+ methodTable()->putByIndex(this, exec, length, value, true);
+ if (!exec->hadException())
+ throwError(exec, createRangeError(exec, "Invalid array length"));
+ return;
+ }
+
+ putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, length, value);
+ return;
+ }
+
case ArrayWithContiguous: {
unsigned length = m_butterfly->publicLength();
ASSERT(length <= m_butterfly->vectorLength());
@@ -538,10 +601,42 @@ void JSArray::push(ExecState* exec, JSValue value)
return;
}
- putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, length, value);
+ putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, length, value);
return;
}
+ case ArrayWithDouble: {
+ if (!value.isNumber()) {
+ convertDoubleToContiguous(exec->globalData());
+ push(exec, value);
+ return;
+ }
+ double valueAsDouble = value.asNumber();
+ if (valueAsDouble != valueAsDouble) {
+ convertDoubleToContiguous(exec->globalData());
+ push(exec, value);
+ return;
+ }
+
+ unsigned length = m_butterfly->publicLength();
+ ASSERT(length <= m_butterfly->vectorLength());
+ if (length < m_butterfly->vectorLength()) {
+ m_butterfly->contiguousDouble()[length] = valueAsDouble;
+ m_butterfly->setPublicLength(length + 1);
+ return;
+ }
+
+ if (length > MAX_ARRAY_INDEX) {
+ methodTable()->putByIndex(this, exec, length, value, true);
+ if (!exec->hadException())
+ throwError(exec, createRangeError(exec, "Invalid array length"));
+ return;
+ }
+
+ putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, length, value);
+ break;
+ }
+
case ArrayWithSlowPutArrayStorage: {
unsigned oldLength = length();
if (attemptToInterceptPutByIndexOnHole(exec, oldLength, value, true)) {
@@ -647,6 +742,11 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex
case ArrayClass:
return true;
+ case ArrayWithUndecided:
+ // Don't handle this because it's confusing and it shouldn't come up.
+ return false;
+
+ case ArrayWithInt32:
case ArrayWithContiguous: {
unsigned oldLength = m_butterfly->publicLength();
ASSERT(count <= oldLength);
@@ -654,7 +754,7 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex
// We may have to walk the entire array to do the shift. We're willing to do
// so only if it's not horribly slow.
if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX)
- return shiftCountWithArrayStorage(startIndex, count, convertContiguousToArrayStorage(exec->globalData()));
+ return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData()));
unsigned end = oldLength - count;
for (unsigned i = startIndex; i < end; ++i) {
@@ -668,7 +768,7 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex
// about holes (at least for now), but it can detect them quickly. So
// we convert to array storage and then allow the array storage path to
// figure it out.
- return shiftCountWithArrayStorage(startIndex, count, convertContiguousToArrayStorage(exec->globalData()));
+ return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData()));
}
// No need for a barrier since we're just moving data around in the same vector.
// This is in line with our standing assumption that we won't have a deletion
@@ -682,6 +782,41 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex
return true;
}
+ case ArrayWithDouble: {
+ unsigned oldLength = m_butterfly->publicLength();
+ ASSERT(count <= oldLength);
+
+ // We may have to walk the entire array to do the shift. We're willing to do
+ // so only if it's not horribly slow.
+ if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX)
+ return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData()));
+
+ unsigned end = oldLength - count;
+ for (unsigned i = startIndex; i < end; ++i) {
+ // Storing to a hole is fine since we're still having a good time. But reading
+ // from a hole is totally not fine, since we might have to read from the proto
+ // chain.
+ double v = m_butterfly->contiguousDouble()[i + count];
+ if (UNLIKELY(v != v)) {
+ // The purpose of this path is to ensure that we don't make the same
+ // mistake in the future: shiftCountWithArrayStorage() can't do anything
+ // about holes (at least for now), but it can detect them quickly. So
+ // we convert to array storage and then allow the array storage path to
+ // figure it out.
+ return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData()));
+ }
+ // No need for a barrier since we're just moving data around in the same vector.
+ // This is in line with our standing assumption that we won't have a deletion
+ // barrier.
+ m_butterfly->contiguousDouble()[i] = v;
+ }
+ for (unsigned i = end; i < oldLength; ++i)
+ m_butterfly->contiguousDouble()[i] = QNaN;
+
+ m_butterfly->setPublicLength(oldLength - count);
+ return true;
+ }
+
case ArrayWithArrayStorage:
case ArrayWithSlowPutArrayStorage:
return shiftCountWithArrayStorage(startIndex, count, arrayStorage());
@@ -740,23 +875,25 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd
{
switch (structure()->indexingType()) {
case ArrayClass:
+ case ArrayWithUndecided:
// We could handle this. But it shouldn't ever come up, so we won't.
return false;
-
+
+ case ArrayWithInt32:
case ArrayWithContiguous: {
unsigned oldLength = m_butterfly->publicLength();
// We may have to walk the entire array to do the unshift. We're willing to do so
// only if it's not horribly slow.
if (oldLength - startIndex >= MIN_SPARSE_ARRAY_INDEX)
- return unshiftCountWithArrayStorage(exec, startIndex, count, convertContiguousToArrayStorage(exec->globalData()));
+ return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData()));
- ensureContiguousLength(exec->globalData(), oldLength + count);
+ ensureLength(exec->globalData(), oldLength + count);
for (unsigned i = oldLength; i-- > startIndex;) {
JSValue v = m_butterfly->contiguous()[i].get();
if (UNLIKELY(!v))
- return unshiftCountWithArrayStorage(exec, startIndex, count, convertContiguousToArrayStorage(exec->globalData()));
+ return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData()));
m_butterfly->contiguous()[i + count].setWithoutWriteBarrier(v);
}
@@ -768,6 +905,31 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd
return true;
}
+ case ArrayWithDouble: {
+ unsigned oldLength = m_butterfly->publicLength();
+
+ // We may have to walk the entire array to do the unshift. We're willing to do so
+ // only if it's not horribly slow.
+ if (oldLength - startIndex >= MIN_SPARSE_ARRAY_INDEX)
+ return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData()));
+
+ ensureLength(exec->globalData(), oldLength + count);
+
+ for (unsigned i = oldLength; i-- > startIndex;) {
+ double v = m_butterfly->contiguousDouble()[i];
+ if (UNLIKELY(v != v))
+ return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData()));
+ m_butterfly->contiguousDouble()[i + count] = v;
+ }
+
+ // NOTE: we're leaving being garbage in the part of the array that we shifted out
+ // of. This is fine because the caller is required to store over that area, and
+ // in contiguous mode storing into a hole is guaranteed to behave exactly the same
+ // as storing over an existing element.
+
+ return true;
+ }
+
case ArrayWithArrayStorage:
case ArrayWithSlowPutArrayStorage:
return unshiftCountWithArrayStorage(exec, startIndex, count, arrayStorage());
@@ -778,6 +940,20 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd
}
}
+static int compareNumbersForQSortWithInt32(const void* a, const void* b)
+{
+ int32_t ia = static_cast<const JSValue*>(a)->asInt32();
+ int32_t ib = static_cast<const JSValue*>(b)->asInt32();
+ return ia - ib;
+}
+
+static int compareNumbersForQSortWithDouble(const void* a, const void* b)
+{
+ double da = *static_cast<const double*>(a);
+ double db = *static_cast<const double*>(b);
+ return (da > db) - (da < db);
+}
+
static int compareNumbersForQSort(const void* a, const void* b)
{
double da = static_cast<const JSValue*>(a)->asNumber();
@@ -795,7 +971,7 @@ static int compareByStringPairForQSort(const void* a, const void* b)
template<IndexingType indexingType>
void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
{
- ASSERT(indexingType == ArrayWithContiguous || indexingType == ArrayWithArrayStorage);
+ ASSERT(indexingType == ArrayWithInt32 || indexingType == ArrayWithDouble || indexingType == ArrayWithContiguous || indexingType == ArrayWithArrayStorage);
unsigned lengthNotIncludingUndefined;
unsigned newRelevantLength;
@@ -814,11 +990,19 @@ void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallTy
return;
bool allValuesAreNumbers = true;
- for (size_t i = 0; i < newRelevantLength; ++i) {
- if (!data[i].isNumber()) {
- allValuesAreNumbers = false;
- break;
+ switch (indexingType) {
+ case ArrayWithInt32:
+ case ArrayWithDouble:
+ break;
+
+ default:
+ for (size_t i = 0; i < newRelevantLength; ++i) {
+ if (!data[i].isNumber()) {
+ allValuesAreNumbers = false;
+ break;
+ }
}
+ break;
}
if (!allValuesAreNumbers)
@@ -827,7 +1011,23 @@ void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallTy
// For numeric comparison, which is fast, qsort is faster than mergesort. We
// also don't require mergesort's stability, since there's no user visible
// side-effect from swapping the order of equal primitive values.
- qsort(data, newRelevantLength, sizeof(WriteBarrier<Unknown>), compareNumbersForQSort);
+ int (*compare)(const void*, const void*);
+ switch (indexingType) {
+ case ArrayWithInt32:
+ compare = compareNumbersForQSortWithInt32;
+ break;
+
+ case ArrayWithDouble:
+ compare = compareNumbersForQSortWithDouble;
+ ASSERT(sizeof(WriteBarrier<Unknown>) == sizeof(double));
+ break;
+
+ default:
+ compare = compareNumbersForQSort;
+ break;
+ }
+
+ qsort(data, newRelevantLength, sizeof(WriteBarrier<Unknown>), compare);
return;
}
@@ -839,6 +1039,14 @@ void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType cal
case ArrayClass:
return;
+ case ArrayWithInt32:
+ sortNumericVector<ArrayWithInt32>(exec, compareFunction, callType, callData);
+ break;
+
+ case ArrayWithDouble:
+ sortNumericVector<ArrayWithDouble>(exec, compareFunction, callType, callData);
+ break;
+
case ArrayWithContiguous:
sortNumericVector<ArrayWithContiguous>(exec, compareFunction, callType, callData);
return;
@@ -854,7 +1062,7 @@ void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType cal
}
template<IndexingType indexingType>
-void JSArray::sortCompactedVector(ExecState* exec, WriteBarrier<Unknown>* begin, unsigned relevantLength)
+void JSArray::sortCompactedVector(ExecState* exec, void* begin, unsigned relevantLength)
{
if (!relevantLength)
return;
@@ -875,11 +1083,31 @@ void JSArray::sortCompactedVector(ExecState* exec, WriteBarrier<Unknown>* begin,
Heap::heap(this)->pushTempSortVector(&values);
bool isSortingPrimitiveValues = true;
- for (size_t i = 0; i < relevantLength; i++) {
- JSValue value = begin[i].get();
- ASSERT(!value.isUndefined());
- values[i].first = value;
- isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive();
+ switch (indexingType) {
+ case ArrayWithInt32:
+ for (size_t i = 0; i < relevantLength; i++) {
+ JSValue value = static_cast<WriteBarrier<Unknown>*>(begin)[i].get();
+ ASSERT(value.isInt32());
+ values[i].first = value;
+ }
+ break;
+
+ case ArrayWithDouble:
+ for (size_t i = 0; i < relevantLength; i++) {
+ double value = static_cast<double*>(begin)[i];
+ ASSERT(value == value);
+ values[i].first = JSValue(JSValue::EncodeAsDouble, value);
+ }
+ break;
+
+ default:
+ for (size_t i = 0; i < relevantLength; i++) {
+ JSValue value = static_cast<WriteBarrier<Unknown>*>(begin)[i].get();
+ ASSERT(!value.isUndefined());
+ values[i].first = value;
+ isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive();
+ }
+ break;
}
// FIXME: The following loop continues to call toString on subsequent values even after
@@ -910,8 +1138,10 @@ void JSArray::sortCompactedVector(ExecState* exec, WriteBarrier<Unknown>* begin,
// If the toString function changed the length of the array or vector storage,
// increase the length to handle the orignal number of actual values.
switch (indexingType) {
+ case ArrayWithInt32:
+ case ArrayWithDouble:
case ArrayWithContiguous:
- ensureContiguousLength(globalData, relevantLength);
+ ensureLength(globalData, relevantLength);
break;
case ArrayWithArrayStorage:
@@ -927,8 +1157,12 @@ void JSArray::sortCompactedVector(ExecState* exec, WriteBarrier<Unknown>* begin,
CRASH();
}
- for (size_t i = 0; i < relevantLength; i++)
- begin[i].set(globalData, this, values[i].first);
+ for (size_t i = 0; i < relevantLength; i++) {
+ if (indexingType == ArrayWithDouble)
+ static_cast<double*>(begin)[i] = values[i].first.asNumber();
+ else
+ static_cast<WriteBarrier<Unknown>*>(begin)[i].set(globalData, this, values[i].first);
+ }
Heap::heap(this)->popTempSortVector(&values);
}
@@ -939,8 +1173,31 @@ void JSArray::sort(ExecState* exec)
switch (structure()->indexingType()) {
case ArrayClass:
+ case ArrayWithUndecided:
return;
+ case ArrayWithInt32: {
+ unsigned lengthNotIncludingUndefined;
+ unsigned newRelevantLength;
+ compactForSorting<ArrayWithInt32>(
+ lengthNotIncludingUndefined, newRelevantLength);
+
+ sortCompactedVector<ArrayWithInt32>(
+ exec, m_butterfly->contiguousInt32(), lengthNotIncludingUndefined);
+ return;
+ }
+
+ case ArrayWithDouble: {
+ unsigned lengthNotIncludingUndefined;
+ unsigned newRelevantLength;
+ compactForSorting<ArrayWithDouble>(
+ lengthNotIncludingUndefined, newRelevantLength);
+
+ sortCompactedVector<ArrayWithDouble>(
+ exec, m_butterfly->contiguousDouble(), lengthNotIncludingUndefined);
+ return;
+ }
+
case ArrayWithContiguous: {
unsigned lengthNotIncludingUndefined;
unsigned newRelevantLength;
@@ -1087,12 +1344,12 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call
unsigned numDefined = 0;
unsigned numUndefined = 0;
-
+
// Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree.
for (; numDefined < usedVectorLength; ++numDefined) {
if (numDefined > m_butterfly->vectorLength())
break;
- JSValue v = currentIndexingData()[numDefined].get();
+ JSValue v = getHolyIndexQuickly(numDefined);
if (!v || v.isUndefined())
break;
tree.abstractor().m_nodes[numDefined].value = v;
@@ -1101,7 +1358,7 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call
for (unsigned i = numDefined; i < usedVectorLength; ++i) {
if (i > m_butterfly->vectorLength())
break;
- JSValue v = currentIndexingData()[i].get();
+ JSValue v = getHolyIndexQuickly(i);
if (v) {
if (v.isUndefined())
++numUndefined;
@@ -1112,7 +1369,7 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call
}
}
}
-
+
unsigned newUsedVectorLength = numDefined + numUndefined;
// The array size may have changed. Figure out the new bounds.
@@ -1127,16 +1384,31 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call
iter.start_iter_least(tree);
JSGlobalData& globalData = exec->globalData();
for (unsigned i = 0; i < elementsToExtractThreshold; ++i) {
- currentIndexingData()[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value);
+ if (structure()->indexingType() == ArrayWithDouble)
+ butterfly()->contiguousDouble()[i] = tree.abstractor().m_nodes[*iter].value.asNumber();
+ else
+ currentIndexingData()[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value);
++iter;
}
// Put undefined values back in.
- for (unsigned i = elementsToExtractThreshold; i < undefinedElementsThreshold; ++i)
- currentIndexingData()[i].setUndefined();
+ switch (structure()->indexingType()) {
+ case ArrayWithInt32:
+ case ArrayWithDouble:
+ ASSERT(elementsToExtractThreshold == undefinedElementsThreshold);
+ break;
+
+ default:
+ for (unsigned i = elementsToExtractThreshold; i < undefinedElementsThreshold; ++i)
+ currentIndexingData()[i].setUndefined();
+ }
// Ensure that unused values in the vector are zeroed out.
- for (unsigned i = undefinedElementsThreshold; i < clearElementsThreshold; ++i)
- currentIndexingData()[i].clear();
+ for (unsigned i = undefinedElementsThreshold; i < clearElementsThreshold; ++i) {
+ if (structure()->indexingType() == ArrayWithDouble)
+ butterfly()->contiguousDouble()[i] = QNaN;
+ else
+ currentIndexingData()[i].clear();
+ }
if (hasArrayStorage(structure()->indexingType()))
arrayStorage()->m_numValuesInVector = newUsedVectorLength;
@@ -1148,8 +1420,17 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType,
switch (structure()->indexingType()) {
case ArrayClass:
+ case ArrayWithUndecided:
return;
+ case ArrayWithInt32:
+ sortVector<ArrayWithInt32>(exec, compareFunction, callType, callData);
+ return;
+
+ case ArrayWithDouble:
+ sortVector<ArrayWithDouble>(exec, compareFunction, callType, callData);
+ return;
+
case ArrayWithContiguous:
sortVector<ArrayWithContiguous>(exec, compareFunction, callType, callData);
return;
@@ -1173,11 +1454,30 @@ void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
case ArrayClass:
return;
+ case ArrayWithUndecided: {
+ vector = 0;
+ vectorEnd = 0;
+ break;
+ }
+
+ case ArrayWithInt32:
case ArrayWithContiguous: {
vectorEnd = m_butterfly->publicLength();
vector = m_butterfly->contiguous();
break;
}
+
+ case ArrayWithDouble: {
+ vector = 0;
+ vectorEnd = 0;
+ for (; i < m_butterfly->publicLength(); ++i) {
+ double v = butterfly()->contiguousDouble()[i];
+ if (v != v)
+ break;
+ args.append(JSValue(JSValue::EncodeAsDouble, v));
+ }
+ break;
+ }
case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = m_butterfly->arrayStorage();
@@ -1216,12 +1516,31 @@ void JSArray::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t le
case ArrayClass:
return;
+ case ArrayWithUndecided: {
+ vector = 0;
+ vectorEnd = 0;
+ break;
+ }
+
+ case ArrayWithInt32:
case ArrayWithContiguous: {
vector = m_butterfly->contiguous();
vectorEnd = m_butterfly->publicLength();
break;
}
+ case ArrayWithDouble: {
+ vector = 0;
+ vectorEnd = 0;
+ for (; i < m_butterfly->publicLength(); ++i) {
+ double v = m_butterfly->contiguousDouble()[i];
+ if (v != v)
+ break;
+ callFrame->setArgument(i, JSValue(JSValue::EncodeAsDouble, v));
+ }
+ break;
+ }
+
case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = m_butterfly->arrayStorage();
vector = storage->m_vector;
@@ -1259,12 +1578,40 @@ void JSArray::compactForSorting(unsigned& numDefined, unsigned& newRelevantLengt
unsigned numUndefined = 0;
for (; numDefined < myRelevantLength; ++numDefined) {
+ if (indexingType == ArrayWithInt32) {
+ JSValue v = m_butterfly->contiguousInt32()[numDefined].get();
+ if (!v)
+ break;
+ ASSERT(v.isInt32());
+ continue;
+ }
+ if (indexingType == ArrayWithDouble) {
+ double v = m_butterfly->contiguousDouble()[numDefined];
+ if (v != v)
+ break;
+ continue;
+ }
JSValue v = indexingData<indexingType>()[numDefined].get();
if (!v || v.isUndefined())
break;
}
for (unsigned i = numDefined; i < myRelevantLength; ++i) {
+ if (indexingType == ArrayWithInt32) {
+ JSValue v = m_butterfly->contiguousInt32()[i].get();
+ if (!v)
+ continue;
+ ASSERT(v.isInt32());
+ m_butterfly->contiguousInt32()[numDefined++].setWithoutWriteBarrier(v);
+ continue;
+ }
+ if (indexingType == ArrayWithDouble) {
+ double v = m_butterfly->contiguousDouble()[i];
+ if (v != v)
+ continue;
+ m_butterfly->contiguousDouble()[numDefined++] = v;
+ continue;
+ }
JSValue v = indexingData<indexingType>()[i].get();
if (v) {
if (v.isUndefined())
@@ -1279,10 +1626,23 @@ void JSArray::compactForSorting(unsigned& numDefined, unsigned& newRelevantLengt
if (hasArrayStorage(indexingType))
ASSERT(!arrayStorage()->m_sparseMap);
- for (unsigned i = numDefined; i < newRelevantLength; ++i)
- indexingData<indexingType>()[i].setUndefined();
- for (unsigned i = newRelevantLength; i < myRelevantLength; ++i)
- indexingData<indexingType>()[i].clear();
+ switch (indexingType) {
+ case ArrayWithInt32:
+ case ArrayWithDouble:
+ ASSERT(numDefined == newRelevantLength);
+ break;
+
+ default:
+ for (unsigned i = numDefined; i < newRelevantLength; ++i)
+ indexingData<indexingType>()[i].setUndefined();
+ break;
+ }
+ for (unsigned i = newRelevantLength; i < myRelevantLength; ++i) {
+ if (indexingType == ArrayWithDouble)
+ m_butterfly->contiguousDouble()[i] = QNaN;
+ else
+ indexingData<indexingType>()[i].clear();
+ }
if (hasArrayStorage(indexingType))
arrayStorage()->m_numValuesInVector = newRelevantLength;
diff --git a/Source/JavaScriptCore/runtime/JSArray.h b/Source/JavaScriptCore/runtime/JSArray.h
index 1d1e64173..ea1ed9047 100644
--- a/Source/JavaScriptCore/runtime/JSArray.h
+++ b/Source/JavaScriptCore/runtime/JSArray.h
@@ -22,7 +22,7 @@
#define JSArray_h
#include "ArrayConventions.h"
-#include "ButterflyInlineMethods.h"
+#include "ButterflyInlines.h"
#include "JSObject.h"
namespace JSC {
@@ -162,7 +162,7 @@ private:
void sortNumericVector(ExecState*, JSValue compareFunction, CallType, const CallData&);
template<IndexingType indexingType>
- void sortCompactedVector(ExecState*, WriteBarrier<Unknown>* begin, unsigned relevantLength);
+ void sortCompactedVector(ExecState*, void* begin, unsigned relevantLength);
template<IndexingType indexingType>
void sortVector(ExecState*, JSValue compareFunction, CallType, const CallData&);
@@ -174,13 +174,14 @@ private:
void compactForSorting(unsigned& numDefined, unsigned& newRelevantLength);
};
-inline Butterfly* createContiguousArrayButterfly(JSGlobalData& globalData, unsigned length)
+inline Butterfly* createContiguousArrayButterfly(JSGlobalData& globalData, unsigned length, unsigned& vectorLength)
{
IndexingHeader header;
- header.setVectorLength(std::max(length, BASE_VECTOR_LEN));
+ vectorLength = std::max(length, BASE_VECTOR_LEN);
+ header.setVectorLength(vectorLength);
header.setPublicLength(length);
Butterfly* result = Butterfly::create(
- globalData, 0, 0, true, header, header.vectorLength() * sizeof(EncodedJSValue));
+ globalData, 0, 0, true, header, vectorLength * sizeof(EncodedJSValue));
return result;
}
@@ -200,13 +201,23 @@ Butterfly* createArrayButterflyInDictionaryIndexingMode(JSGlobalData&, unsigned
inline JSArray* JSArray::create(JSGlobalData& globalData, Structure* structure, unsigned initialLength)
{
Butterfly* butterfly;
- if (LIKELY(structure->indexingType() == ArrayWithContiguous)) {
- butterfly = createContiguousArrayButterfly(globalData, initialLength);
+ if (LIKELY(!hasArrayStorage(structure->indexingType()))) {
+ ASSERT(
+ hasUndecided(structure->indexingType())
+ || hasInt32(structure->indexingType())
+ || hasDouble(structure->indexingType())
+ || hasContiguous(structure->indexingType()));
+ unsigned vectorLength;
+ butterfly = createContiguousArrayButterfly(globalData, initialLength, vectorLength);
ASSERT(initialLength < MIN_SPARSE_ARRAY_INDEX);
+ if (hasDouble(structure->indexingType())) {
+ for (unsigned i = 0; i < vectorLength; ++i)
+ butterfly->contiguousDouble()[i] = QNaN;
+ }
} else {
ASSERT(
structure->indexingType() == ArrayWithSlowPutArrayStorage
- || (initialLength && structure->indexingType() == ArrayWithArrayStorage));
+ || structure->indexingType() == ArrayWithArrayStorage);
butterfly = createArrayButterfly(globalData, initialLength);
}
JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure, butterfly);
@@ -221,8 +232,13 @@ inline JSArray* JSArray::tryCreateUninitialized(JSGlobalData& globalData, Struct
return 0;
Butterfly* butterfly;
- if (LIKELY(structure->indexingType() == ArrayWithContiguous)) {
-
+ if (LIKELY(!hasArrayStorage(structure->indexingType()))) {
+ ASSERT(
+ hasUndecided(structure->indexingType())
+ || hasInt32(structure->indexingType())
+ || hasDouble(structure->indexingType())
+ || hasContiguous(structure->indexingType()));
+
void* temp;
if (!globalData.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, vectorLength * sizeof(EncodedJSValue)), &temp))
return 0;
diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h
index 3b37613d1..df31b8542 100644
--- a/Source/JavaScriptCore/runtime/JSCell.h
+++ b/Source/JavaScriptCore/runtime/JSCell.h
@@ -28,9 +28,9 @@
#include "ConstructData.h"
#include "Heap.h"
#include "JSLock.h"
-#include "JSValueInlineMethods.h"
+#include "JSValueInlines.h"
#include "SlotVisitor.h"
-#include "SlotVisitorInlineMethods.h"
+#include "SlotVisitorInlines.h"
#include "TypedArrayDescriptor.h"
#include "WriteBarrier.h"
#include <wtf/Noncopyable.h>
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
index c466a2b04..a7c6c8c18 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
@@ -230,9 +230,16 @@ void JSGlobalObject::reset(JSValue prototype)
m_callbackObjectStructure.set(exec->globalData(), this, JSCallbackObject<JSDestructibleObject>::createStructure(exec->globalData(), this, m_objectPrototype.get()));
m_arrayPrototype.set(exec->globalData(), this, ArrayPrototype::create(exec, this, ArrayPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get())));
- m_arrayStructure.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithContiguous));
- m_arrayStructureWithArrayStorage.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithArrayStorage));
- m_arrayStructureForSlowPut.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithSlowPutArrayStorage));
+
+ m_originalArrayStructureForIndexingShape[UndecidedShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithUndecided));
+ m_originalArrayStructureForIndexingShape[Int32Shape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithInt32));
+ m_originalArrayStructureForIndexingShape[DoubleShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithDouble));
+ m_originalArrayStructureForIndexingShape[ContiguousShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithContiguous));
+ m_originalArrayStructureForIndexingShape[ArrayStorageShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithArrayStorage));
+ m_originalArrayStructureForIndexingShape[SlowPutArrayStorageShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithSlowPutArrayStorage));
+ for (unsigned i = 0; i < NumberOfIndexingShapes; ++i)
+ m_arrayStructureForIndexingShapeDuringAllocation[i] = m_originalArrayStructureForIndexingShape[i];
+
m_regExpMatchesArrayStructure.set(exec->globalData(), this, RegExpMatchesArray::createStructure(exec->globalData(), this, m_arrayPrototype.get()));
m_stringPrototype.set(exec->globalData(), this, StringPrototype::create(exec, this, StringPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get())));
@@ -360,7 +367,9 @@ inline bool hasBrokenIndexing(JSObject* object)
{
// This will change if we have more indexing types.
IndexingType type = object->structure()->indexingType();
- return hasContiguous(type) || hasFastArrayStorage(type);
+ // This could be made obviously more efficient, but isn't made so right now, because
+ // we expect this to be an unlikely slow path anyway.
+ return hasUndecided(type) || hasInt32(type) || hasDouble(type) || hasContiguous(type) || hasFastArrayStorage(type);
}
void ObjectsWithBrokenIndexingFinder::operator()(JSCell* cell)
@@ -412,8 +421,8 @@ void JSGlobalObject::haveABadTime(JSGlobalData& globalData)
// Make sure that all JSArray allocations that load the appropriate structure from
// this object now load a structure that uses SlowPut.
- m_arrayStructure.set(globalData, this, m_arrayStructureForSlowPut.get());
- m_arrayStructureWithArrayStorage.set(globalData, this, m_arrayStructureForSlowPut.get());
+ for (unsigned i = 0; i < NumberOfIndexingShapes; ++i)
+ m_arrayStructureForIndexingShapeDuringAllocation[i].set(globalData, this, originalArrayStructureForIndexingType(ArrayWithSlowPutArrayStorage));
// Make sure that all objects that have indexed storage switch to the slow kind of
// indexed storage.
@@ -488,9 +497,10 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
visitor.append(&thisObject->m_activationStructure);
visitor.append(&thisObject->m_nameScopeStructure);
visitor.append(&thisObject->m_argumentsStructure);
- visitor.append(&thisObject->m_arrayStructure);
- visitor.append(&thisObject->m_arrayStructureWithArrayStorage);
- visitor.append(&thisObject->m_arrayStructureForSlowPut);
+ for (unsigned i = 0; i < NumberOfIndexingShapes; ++i)
+ visitor.append(&thisObject->m_originalArrayStructureForIndexingShape[i]);
+ for (unsigned i = 0; i < NumberOfIndexingShapes; ++i)
+ visitor.append(&thisObject->m_arrayStructureForIndexingShapeDuringAllocation[i]);
visitor.append(&thisObject->m_booleanObjectStructure);
visitor.append(&thisObject->m_callbackConstructorStructure);
visitor.append(&thisObject->m_callbackFunctionStructure);
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h
index 3212363ab..121b71b72 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.h
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h
@@ -22,6 +22,7 @@
#ifndef JSGlobalObject_h
#define JSGlobalObject_h
+#include "ArrayAllocationProfile.h"
#include "JSArray.h"
#include "JSGlobalData.h"
#include "JSSegmentedVariableObject.h"
@@ -130,9 +131,12 @@ namespace JSC {
WriteBarrier<Structure> m_activationStructure;
WriteBarrier<Structure> m_nameScopeStructure;
WriteBarrier<Structure> m_argumentsStructure;
- WriteBarrier<Structure> m_arrayStructure; // This gets set to m_arrayStructureForSlowPut as soon as we decide to have a bad time.
- WriteBarrier<Structure> m_arrayStructureWithArrayStorage; // This gets set to m_arrayStructureForSlowPut as soon as we decide to have a bad time.
- WriteBarrier<Structure> m_arrayStructureForSlowPut;
+
+ // Lists the actual structures used for having these particular indexing shapes.
+ WriteBarrier<Structure> m_originalArrayStructureForIndexingShape[NumberOfIndexingShapes];
+ // Lists the structures we should use during allocation for these particular indexing shapes.
+ WriteBarrier<Structure> m_arrayStructureForIndexingShapeDuringAllocation[NumberOfIndexingShapes];
+
WriteBarrier<Structure> m_booleanObjectStructure;
WriteBarrier<Structure> m_callbackConstructorStructure;
WriteBarrier<Structure> m_callbackFunctionStructure;
@@ -275,14 +279,26 @@ namespace JSC {
Structure* activationStructure() const { return m_activationStructure.get(); }
Structure* nameScopeStructure() const { return m_nameScopeStructure.get(); }
Structure* argumentsStructure() const { return m_argumentsStructure.get(); }
- Structure* arrayStructure() const { return m_arrayStructure.get(); }
- Structure* arrayStructureWithArrayStorage() const { return m_arrayStructureWithArrayStorage.get(); }
- void* addressOfArrayStructure() { return &m_arrayStructure; }
- void* addressOfArrayStructureWithArrayStorage() { return &m_arrayStructureWithArrayStorage; }
+ Structure* originalArrayStructureForIndexingType(IndexingType indexingType) const
+ {
+ ASSERT(indexingType & IsArray);
+ return m_originalArrayStructureForIndexingShape[(indexingType & IndexingShapeMask) >> IndexingShapeShift].get();
+ }
+ Structure* arrayStructureForIndexingTypeDuringAllocation(IndexingType indexingType) const
+ {
+ ASSERT(indexingType & IsArray);
+ return m_arrayStructureForIndexingShapeDuringAllocation[(indexingType & IndexingShapeMask) >> IndexingShapeShift].get();
+ }
+ Structure* arrayStructureForProfileDuringAllocation(ArrayAllocationProfile* profile) const
+ {
+ return arrayStructureForIndexingTypeDuringAllocation(ArrayAllocationProfile::selectIndexingTypeFor(profile));
+ }
+
bool isOriginalArrayStructure(Structure* structure)
{
- return structure == m_arrayStructure.get() || structure == m_arrayStructureWithArrayStorage.get();
+ return originalArrayStructureForIndexingType(structure->indexingType() | IsArray) == structure;
}
+
Structure* booleanObjectStructure() const { return m_booleanObjectStructure.get(); }
Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); }
Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); }
@@ -497,34 +513,34 @@ namespace JSC {
return constructEmptyObject(exec, exec->lexicalGlobalObject());
}
- inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject, unsigned initialLength = 0)
+ inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, unsigned initialLength = 0)
{
- return JSArray::create(exec->globalData(), initialLength >= MIN_SPARSE_ARRAY_INDEX ? globalObject->arrayStructureWithArrayStorage() : globalObject->arrayStructure(), initialLength);
+ return ArrayAllocationProfile::updateLastAllocationFor(profile, JSArray::create(exec->globalData(), initialLength >= MIN_SPARSE_ARRAY_INDEX ? globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage) : globalObject->arrayStructureForProfileDuringAllocation(profile), initialLength));
}
- inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength = 0)
+ inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, unsigned initialLength = 0)
{
- return constructEmptyArray(exec, exec->lexicalGlobalObject(), initialLength);
+ return constructEmptyArray(exec, profile, exec->lexicalGlobalObject(), initialLength);
}
- inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, const ArgList& values)
+ inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const ArgList& values)
{
- return constructArray(exec, globalObject->arrayStructure(), values);
+ return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject->arrayStructureForProfileDuringAllocation(profile), values));
}
- inline JSArray* constructArray(ExecState* exec, const ArgList& values)
+ inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const ArgList& values)
{
- return constructArray(exec, exec->lexicalGlobalObject(), values);
+ return constructArray(exec, profile, exec->lexicalGlobalObject(), values);
}
- inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, const JSValue* values, unsigned length)
+ inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const JSValue* values, unsigned length)
{
- return constructArray(exec, globalObject->arrayStructure(), values, length);
+ return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject->arrayStructureForProfileDuringAllocation(profile), values, length));
}
- inline JSArray* constructArray(ExecState* exec, const JSValue* values, unsigned length)
+ inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, unsigned length)
{
- return constructArray(exec, exec->lexicalGlobalObject(), values, length);
+ return constructArray(exec, profile, exec->lexicalGlobalObject(), values, length);
}
class DynamicGlobalObjectScope {
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp
index 6a3fb84e4..a67896b1a 100644
--- a/Source/JavaScriptCore/runtime/JSObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSObject.cpp
@@ -24,14 +24,14 @@
#include "config.h"
#include "JSObject.h"
-#include "ButterflyInlineMethods.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "ButterflyInlines.h"
+#include "CopiedSpaceInlines.h"
#include "CopyVisitor.h"
-#include "CopyVisitorInlineMethods.h"
+#include "CopyVisitorInlines.h"
#include "DatePrototype.h"
#include "ErrorConstructor.h"
#include "GetterSetter.h"
-#include "IndexingHeaderInlineMethods.h"
+#include "IndexingHeaderInlines.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "Lookup.h"
@@ -42,7 +42,7 @@
#include "PropertyDescriptor.h"
#include "PropertyNameArray.h"
#include "Reject.h"
-#include "SlotVisitorInlineMethods.h"
+#include "SlotVisitorInlines.h"
#include <math.h>
#include <wtf/Assertions.h>
@@ -129,7 +129,16 @@ ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butt
size_t count;
switch (structure->indexingType()) {
- case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ case ALL_UNDECIDED_INDEXING_TYPES: {
+ currentTarget = 0;
+ currentSource = 0;
+ count = 0;
+ break;
+ }
+
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES: {
currentTarget = newButterfly->contiguous();
currentSource = butterfly->contiguous();
ASSERT(newButterfly->publicLength() <= newButterfly->vectorLength());
@@ -152,8 +161,7 @@ ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butt
break;
}
- while (count--)
- (currentTarget++)->setWithoutWriteBarrier((currentSource++)->get());
+ memcpy(currentTarget, currentSource, count * sizeof(EncodedJSValue));
}
m_butterfly = newButterfly;
@@ -272,8 +280,10 @@ bool JSObject::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned
switch (thisObject->structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
break;
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES: {
Butterfly* butterfly = thisObject->m_butterfly;
if (i >= butterfly->vectorLength())
@@ -288,6 +298,20 @@ bool JSObject::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned
return false;
}
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ Butterfly* butterfly = thisObject->m_butterfly;
+ if (i >= butterfly->vectorLength())
+ return false;
+
+ double value = butterfly->contiguousDouble()[i];
+ if (value == value) {
+ slot.setValue(JSValue(JSValue::EncodeAsDouble, value));
+ return true;
+ }
+
+ return false;
+ }
+
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
if (i >= storage->length())
@@ -405,6 +429,22 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName,
case ALL_BLANK_INDEXING_TYPES:
break;
+ case ALL_UNDECIDED_INDEXING_TYPES: {
+ thisObject->convertUndecidedForValue(exec->globalData(), value);
+ // Reloop.
+ putByIndex(cell, exec, propertyName, value, shouldThrow);
+ return;
+ }
+
+ case ALL_INT32_INDEXING_TYPES: {
+ if (!value.isInt32()) {
+ thisObject->convertInt32ForValue(exec->globalData(), value);
+ putByIndex(cell, exec, propertyName, value, shouldThrow);
+ return;
+ }
+ // Fall through.
+ }
+
case ALL_CONTIGUOUS_INDEXING_TYPES: {
Butterfly* butterfly = thisObject->m_butterfly;
if (propertyName >= butterfly->vectorLength())
@@ -415,6 +455,29 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName,
return;
}
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ if (!value.isNumber()) {
+ thisObject->convertDoubleToContiguous(exec->globalData());
+ // Reloop.
+ putByIndex(cell, exec, propertyName, value, shouldThrow);
+ return;
+ }
+ double valueAsDouble = value.asNumber();
+ if (valueAsDouble != valueAsDouble) {
+ thisObject->convertDoubleToContiguous(exec->globalData());
+ // Reloop.
+ putByIndex(cell, exec, propertyName, value, shouldThrow);
+ return;
+ }
+ Butterfly* butterfly = thisObject->m_butterfly;
+ if (propertyName >= butterfly->vectorLength())
+ break;
+ butterfly->contiguousDouble()[propertyName] = valueAsDouble;
+ if (propertyName >= butterfly->publicLength())
+ butterfly->setPublicLength(propertyName + 1);
+ return;
+ }
+
case NonArrayWithArrayStorage:
case ArrayWithArrayStorage: {
ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
@@ -507,10 +570,13 @@ ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists
void JSObject::enterDictionaryIndexingMode(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
// NOTE: this is horribly inefficient, as it will perform two conversions. We could optimize
// this case if we ever cared.
- enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertContiguousToArrayStorage(globalData));
+ enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, ensureArrayStorageSlow(globalData));
break;
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage());
@@ -534,7 +600,7 @@ void JSObject::notifyPresenceOfIndexedAccessors(JSGlobalData& globalData)
globalObject()->haveABadTime(globalData);
}
-WriteBarrier<Unknown>* JSObject::createInitialContiguous(JSGlobalData& globalData, unsigned length)
+Butterfly* JSObject::createInitialIndexedStorage(JSGlobalData& globalData, unsigned length, size_t elementSize)
{
ASSERT(length < MAX_ARRAY_INDEX);
IndexingType oldType = structure()->indexingType();
@@ -544,9 +610,41 @@ WriteBarrier<Unknown>* JSObject::createInitialContiguous(JSGlobalData& globalDat
unsigned vectorLength = std::max(length, BASE_VECTOR_LEN);
Butterfly* newButterfly = m_butterfly->growArrayRight(
globalData, structure(), structure()->outOfLineCapacity(), false, 0,
- sizeof(EncodedJSValue) * vectorLength);
+ elementSize * vectorLength);
newButterfly->setPublicLength(length);
newButterfly->setVectorLength(vectorLength);
+ return newButterfly;
+}
+
+Butterfly* JSObject::createInitialUndecided(JSGlobalData& globalData, unsigned length)
+{
+ Butterfly* newButterfly = createInitialIndexedStorage(globalData, length, sizeof(EncodedJSValue));
+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateUndecided);
+ setButterfly(globalData, newButterfly, newStructure);
+ return newButterfly;
+}
+
+WriteBarrier<Unknown>* JSObject::createInitialInt32(JSGlobalData& globalData, unsigned length)
+{
+ Butterfly* newButterfly = createInitialIndexedStorage(globalData, length, sizeof(EncodedJSValue));
+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateInt32);
+ setButterfly(globalData, newButterfly, newStructure);
+ return newButterfly->contiguousInt32();
+}
+
+double* JSObject::createInitialDouble(JSGlobalData& globalData, unsigned length)
+{
+ Butterfly* newButterfly = createInitialIndexedStorage(globalData, length, sizeof(double));
+ for (unsigned i = newButterfly->vectorLength(); i--;)
+ newButterfly->contiguousDouble()[i] = QNaN;
+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateDouble);
+ setButterfly(globalData, newButterfly, newStructure);
+ return newButterfly->contiguousDouble();
+}
+
+WriteBarrier<Unknown>* JSObject::createInitialContiguous(JSGlobalData& globalData, unsigned length)
+{
+ Butterfly* newButterfly = createInitialIndexedStorage(globalData, length, sizeof(EncodedJSValue));
Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous);
setButterfly(globalData, newButterfly, newStructure);
return newButterfly->contiguous();
@@ -577,10 +675,33 @@ ArrayStorage* JSObject::createInitialArrayStorage(JSGlobalData& globalData)
return createArrayStorage(globalData, 0, BASE_VECTOR_LEN);
}
-ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength)
+WriteBarrier<Unknown>* JSObject::convertUndecidedToInt32(JSGlobalData& globalData)
{
- ASSERT(hasContiguous(structure()->indexingType()));
+ ASSERT(hasUndecided(structure()->indexingType()));
+ setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateInt32));
+ return m_butterfly->contiguousInt32();
+}
+
+double* JSObject::convertUndecidedToDouble(JSGlobalData& globalData)
+{
+ ASSERT(hasUndecided(structure()->indexingType()));
+
+ for (unsigned i = m_butterfly->vectorLength(); i--;)
+ m_butterfly->contiguousDouble()[i] = QNaN;
+ setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateDouble));
+ return m_butterfly->contiguousDouble();
+}
+
+WriteBarrier<Unknown>* JSObject::convertUndecidedToContiguous(JSGlobalData& globalData)
+{
+ ASSERT(hasUndecided(structure()->indexingType()));
+ setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous));
+ return m_butterfly->contiguous();
+}
+
+ArrayStorage* JSObject::constructConvertedArrayStorageWithoutCopyingElements(JSGlobalData& globalData, unsigned neededLength)
+{
unsigned publicLength = m_butterfly->publicLength();
unsigned propertyCapacity = structure()->outOfLineCapacity();
unsigned propertySize = structure()->outOfLineSize();
@@ -599,7 +720,66 @@ ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData
newStorage->m_sparseMap.clear();
newStorage->m_indexBias = 0;
newStorage->m_numValuesInVector = 0;
- for (unsigned i = publicLength; i--;) {
+
+ return newStorage;
+}
+
+ArrayStorage* JSObject::convertUndecidedToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength)
+{
+ ASSERT(hasUndecided(structure()->indexingType()));
+
+ ArrayStorage* storage = constructConvertedArrayStorageWithoutCopyingElements(globalData, neededLength);
+ // No need to copy elements.
+
+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition);
+ setButterfly(globalData, storage->butterfly(), newStructure);
+ return storage;
+}
+
+ArrayStorage* JSObject::convertUndecidedToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition)
+{
+ return convertUndecidedToArrayStorage(globalData, transition, m_butterfly->vectorLength());
+}
+
+ArrayStorage* JSObject::convertUndecidedToArrayStorage(JSGlobalData& globalData)
+{
+ return convertUndecidedToArrayStorage(globalData, structure()->suggestedArrayStorageTransition());
+}
+
+double* JSObject::convertInt32ToDouble(JSGlobalData& globalData)
+{
+ ASSERT(hasInt32(structure()->indexingType()));
+
+ for (unsigned i = m_butterfly->vectorLength(); i--;) {
+ WriteBarrier<Unknown>* current = &m_butterfly->contiguousInt32()[i];
+ double* currentAsDouble = bitwise_cast<double*>(current);
+ JSValue v = current->get();
+ if (!v) {
+ *currentAsDouble = QNaN;
+ continue;
+ }
+ ASSERT(v.isInt32());
+ *currentAsDouble = v.asInt32();
+ }
+
+ setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateDouble));
+ return m_butterfly->contiguousDouble();
+}
+
+WriteBarrier<Unknown>* JSObject::convertInt32ToContiguous(JSGlobalData& globalData)
+{
+ ASSERT(hasInt32(structure()->indexingType()));
+
+ setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous));
+ return m_butterfly->contiguous();
+}
+
+ArrayStorage* JSObject::convertInt32ToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength)
+{
+ ASSERT(hasInt32(structure()->indexingType()));
+
+ ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(globalData, neededLength);
+ for (unsigned i = m_butterfly->publicLength(); i--;) {
JSValue v = m_butterfly->contiguous()[i].get();
if (!v)
continue;
@@ -608,7 +788,82 @@ ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData
}
Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition);
- setButterfly(globalData, newButterfly, newStructure);
+ setButterfly(globalData, newStorage->butterfly(), newStructure);
+ return newStorage;
+}
+
+ArrayStorage* JSObject::convertInt32ToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition)
+{
+ return convertInt32ToArrayStorage(globalData, transition, m_butterfly->vectorLength());
+}
+
+ArrayStorage* JSObject::convertInt32ToArrayStorage(JSGlobalData& globalData)
+{
+ return convertInt32ToArrayStorage(globalData, structure()->suggestedArrayStorageTransition());
+}
+
+WriteBarrier<Unknown>* JSObject::convertDoubleToContiguous(JSGlobalData& globalData)
+{
+ ASSERT(hasDouble(structure()->indexingType()));
+
+ for (unsigned i = m_butterfly->vectorLength(); i--;) {
+ double* current = &m_butterfly->contiguousDouble()[i];
+ WriteBarrier<Unknown>* currentAsValue = bitwise_cast<WriteBarrier<Unknown>*>(current);
+ double value = *current;
+ if (value != value) {
+ currentAsValue->clear();
+ continue;
+ }
+ currentAsValue->setWithoutWriteBarrier(JSValue(JSValue::EncodeAsDouble, value));
+ }
+
+ setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous));
+ return m_butterfly->contiguous();
+}
+
+ArrayStorage* JSObject::convertDoubleToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength)
+{
+ ASSERT(hasDouble(structure()->indexingType()));
+
+ ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(globalData, neededLength);
+ for (unsigned i = m_butterfly->publicLength(); i--;) {
+ double value = m_butterfly->contiguousDouble()[i];
+ if (value != value)
+ continue;
+ newStorage->m_vector[i].setWithoutWriteBarrier(JSValue(JSValue::EncodeAsDouble, value));
+ newStorage->m_numValuesInVector++;
+ }
+
+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition);
+ setButterfly(globalData, newStorage->butterfly(), newStructure);
+ return newStorage;
+}
+
+ArrayStorage* JSObject::convertDoubleToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition)
+{
+ return convertDoubleToArrayStorage(globalData, transition, m_butterfly->vectorLength());
+}
+
+ArrayStorage* JSObject::convertDoubleToArrayStorage(JSGlobalData& globalData)
+{
+ return convertDoubleToArrayStorage(globalData, structure()->suggestedArrayStorageTransition());
+}
+
+ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength)
+{
+ ASSERT(hasContiguous(structure()->indexingType()));
+
+ ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(globalData, neededLength);
+ for (unsigned i = m_butterfly->publicLength(); i--;) {
+ JSValue v = m_butterfly->contiguous()[i].get();
+ if (!v)
+ continue;
+ newStorage->m_vector[i].setWithoutWriteBarrier(v);
+ newStorage->m_numValuesInVector++;
+ }
+
+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition);
+ setButterfly(globalData, newStorage->butterfly(), newStructure);
return newStorage;
}
@@ -622,48 +877,154 @@ ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData
return convertContiguousToArrayStorage(globalData, structure()->suggestedArrayStorageTransition());
}
-WriteBarrier<Unknown>* JSObject::ensureContiguousSlow(JSGlobalData& globalData)
+void JSObject::convertUndecidedForValue(JSGlobalData& globalData, JSValue value)
+{
+ if (value.isInt32()) {
+ convertUndecidedToInt32(globalData);
+ return;
+ }
+
+ if (value.isDouble()) {
+ convertUndecidedToDouble(globalData);
+ return;
+ }
+
+ convertUndecidedToContiguous(globalData);
+}
+
+void JSObject::convertInt32ForValue(JSGlobalData& globalData, JSValue value)
+{
+ ASSERT(!value.isInt32());
+
+ if (value.isDouble()) {
+ convertInt32ToDouble(globalData);
+ return;
+ }
+
+ convertInt32ToContiguous(globalData);
+}
+
+void JSObject::setIndexQuicklyToUndecided(JSGlobalData& globalData, unsigned index, JSValue value)
+{
+ ASSERT(index < m_butterfly->publicLength());
+ ASSERT(index < m_butterfly->vectorLength());
+ convertUndecidedForValue(globalData, value);
+ setIndexQuickly(globalData, index, value);
+}
+
+void JSObject::convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(JSGlobalData& globalData, unsigned index, JSValue value)
+{
+ ASSERT(!value.isInt32());
+ convertInt32ForValue(globalData, value);
+ setIndexQuickly(globalData, index, value);
+}
+
+void JSObject::convertDoubleToContiguousWhilePerformingSetIndex(JSGlobalData& globalData, unsigned index, JSValue value)
+{
+ ASSERT(!value.isNumber() || value.asNumber() != value.asNumber());
+ convertDoubleToContiguous(globalData);
+ setIndexQuickly(globalData, index, value);
+}
+
+WriteBarrier<Unknown>* JSObject::ensureInt32Slow(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
return 0;
- return createInitialContiguous(globalData, 0);
+ return createInitialInt32(globalData, 0);
+
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ return convertUndecidedToInt32(globalData);
+
+ case ALL_DOUBLE_INDEXING_TYPES:
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ return 0;
default:
- ASSERT_NOT_REACHED();
+ CRASH();
return 0;
}
}
-ArrayStorage* JSObject::ensureArrayStorageSlow(JSGlobalData& globalData)
+double* JSObject::ensureDoubleSlow(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
+ case ALL_BLANK_INDEXING_TYPES:
+ if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
+ return 0;
+ return createInitialDouble(globalData, 0);
+
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ return convertUndecidedToDouble(globalData);
+
+ case ALL_INT32_INDEXING_TYPES:
+ return convertInt32ToDouble(globalData);
+
case ALL_CONTIGUOUS_INDEXING_TYPES:
- ASSERT(!indexingShouldBeSparse());
- ASSERT(!structure()->needsSlowPutIndexing());
- return convertContiguousToArrayStorage(globalData);
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ return 0;
+ default:
+ CRASH();
+ return 0;
+ }
+}
+
+WriteBarrier<Unknown>* JSObject::ensureContiguousSlow(JSGlobalData& globalData)
+{
+ switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
- if (UNLIKELY(indexingShouldBeSparse()))
- return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData);
- return createInitialArrayStorage(globalData);
+ if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
+ return 0;
+ return createInitialContiguous(globalData, 0);
+
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ return convertUndecidedToContiguous(globalData);
+
+ case ALL_INT32_INDEXING_TYPES:
+ return convertInt32ToContiguous(globalData);
+
+ case ALL_DOUBLE_INDEXING_TYPES:
+ return convertDoubleToContiguous(globalData);
+
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ return 0;
default:
- ASSERT_NOT_REACHED();
+ CRASH();
return 0;
}
}
-Butterfly* JSObject::ensureIndexedStorageSlow(JSGlobalData& globalData)
+ArrayStorage* JSObject::ensureArrayStorageSlow(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
- if (UNLIKELY(structure()->needsSlowPutIndexing()))
- return createInitialArrayStorage(globalData)->butterfly();
if (UNLIKELY(indexingShouldBeSparse()))
- return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData)->butterfly();
- return Butterfly::fromContiguous(createInitialContiguous(globalData, 0));
+ return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData);
+ return createInitialArrayStorage(globalData);
+
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ ASSERT(!indexingShouldBeSparse());
+ ASSERT(!structure()->needsSlowPutIndexing());
+ return convertUndecidedToArrayStorage(globalData);
+
+ case ALL_INT32_INDEXING_TYPES:
+ ASSERT(!indexingShouldBeSparse());
+ ASSERT(!structure()->needsSlowPutIndexing());
+ return convertInt32ToArrayStorage(globalData);
+
+ case ALL_DOUBLE_INDEXING_TYPES:
+ ASSERT(!indexingShouldBeSparse());
+ ASSERT(!structure()->needsSlowPutIndexing());
+ return convertDoubleToArrayStorage(globalData);
+
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ ASSERT(!indexingShouldBeSparse());
+ ASSERT(!structure()->needsSlowPutIndexing());
+ return convertContiguousToArrayStorage(globalData);
default:
ASSERT_NOT_REACHED();
@@ -674,13 +1035,6 @@ Butterfly* JSObject::ensureIndexedStorageSlow(JSGlobalData& globalData)
ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- // FIXME: This could be made way more efficient, if we cared.
- return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertContiguousToArrayStorage(globalData));
-
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage());
-
case ALL_BLANK_INDEXING_TYPES: {
createArrayStorage(globalData, 0, 0);
SparseArrayValueMap* map = allocateSparseIndexMap(globalData);
@@ -688,8 +1042,23 @@ ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(J
return arrayStorage();
}
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertUndecidedToArrayStorage(globalData));
+
+ case ALL_INT32_INDEXING_TYPES:
+ return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertInt32ToArrayStorage(globalData));
+
+ case ALL_DOUBLE_INDEXING_TYPES:
+ return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertDoubleToArrayStorage(globalData));
+
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertContiguousToArrayStorage(globalData));
+
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage());
+
default:
- ASSERT_NOT_REACHED();
+ CRASH();
return 0;
}
}
@@ -697,10 +1066,21 @@ ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(J
void JSObject::switchToSlowPutArrayStorage(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
- case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ convertUndecidedToArrayStorage(globalData, AllocateSlowPutArrayStorage);
+ break;
+
+ case ALL_INT32_INDEXING_TYPES:
+ convertInt32ToArrayStorage(globalData, AllocateSlowPutArrayStorage);
+ break;
+
+ case ALL_DOUBLE_INDEXING_TYPES:
+ convertDoubleToArrayStorage(globalData, AllocateSlowPutArrayStorage);
+ break;
+
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
convertContiguousToArrayStorage(globalData, AllocateSlowPutArrayStorage);
break;
- }
case NonArrayWithArrayStorage:
case ArrayWithArrayStorage: {
@@ -710,7 +1090,7 @@ void JSObject::switchToSlowPutArrayStorage(JSGlobalData& globalData)
}
default:
- ASSERT_NOT_REACHED();
+ CRASH();
break;
}
}
@@ -877,8 +1257,10 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
switch (thisObject->structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
return true;
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES: {
Butterfly* butterfly = thisObject->m_butterfly;
if (i >= butterfly->vectorLength())
@@ -887,6 +1269,14 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
return true;
}
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ Butterfly* butterfly = thisObject->m_butterfly;
+ if (i >= butterfly->vectorLength())
+ return true;
+ butterfly->contiguousDouble()[i] = QNaN;
+ return true;
+ }
+
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
@@ -1058,8 +1448,10 @@ void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNa
// which almost certainly means a different structure for PropertyNameArray.
switch (object->structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
break;
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES: {
Butterfly* butterfly = object->m_butterfly;
unsigned usedLength = butterfly->publicLength();
@@ -1071,6 +1463,18 @@ void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNa
break;
}
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ Butterfly* butterfly = object->m_butterfly;
+ unsigned usedLength = butterfly->publicLength();
+ for (unsigned i = 0; i < usedLength; ++i) {
+ double value = butterfly->contiguousDouble()[i];
+ if (value != value)
+ continue;
+ propertyNames.add(Identifier::from(exec, i));
+ }
+ break;
+ }
+
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = object->m_butterfly->arrayStorage();
@@ -1460,9 +1864,10 @@ bool JSObject::attemptToInterceptPutByIndexOnHole(ExecState* exec, unsigned i, J
return asObject(prototypeValue)->attemptToInterceptPutByIndexOnHoleForPrototype(exec, this, i, value, shouldThrow);
}
-void JSObject::putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState* exec, unsigned i, JSValue value)
+template<IndexingType indexingShape>
+void JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, unsigned i, JSValue value)
{
- ASSERT(hasContiguous(structure()->indexingType()));
+ ASSERT((structure()->indexingType() & IndexingShapeMask) == indexingShape);
ASSERT(!indexingShouldBeSparse());
// For us to get here, the index is either greater than the public length, or greater than
@@ -1473,9 +1878,9 @@ void JSObject::putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState
if (i >= MAX_ARRAY_INDEX - 1
|| (i >= MIN_SPARSE_ARRAY_INDEX
- && !isDenseEnoughForVector(i, countElementsInContiguous(m_butterfly)))) {
+ && !isDenseEnoughForVector(i, countElements<indexingShape>(m_butterfly)))) {
ASSERT(i <= MAX_ARRAY_INDEX);
- convertContiguousToArrayStorage(globalData, AllocateArrayStorage);
+ ensureArrayStorageSlow(globalData);
SparseArrayValueMap* map = allocateSparseIndexMap(globalData);
map->putEntry(exec, this, i, value, false);
ASSERT(i >= arrayStorage()->length());
@@ -1483,10 +1888,30 @@ void JSObject::putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState
return;
}
- ensureContiguousLength(globalData, i + 1);
+ ensureLength(globalData, i + 1);
ASSERT(i < m_butterfly->vectorLength());
- m_butterfly->contiguous()[i].set(globalData, this, value);
+ switch (indexingShape) {
+ case Int32Shape:
+ ASSERT(value.isInt32());
+ m_butterfly->contiguousInt32()[i].setWithoutWriteBarrier(value);
+ break;
+
+ case DoubleShape: {
+ ASSERT(value.isNumber());
+ double valueAsDouble = value.asNumber();
+ ASSERT(valueAsDouble == valueAsDouble);
+ m_butterfly->contiguousDouble()[i] = valueAsDouble;
+ break;
+ }
+
+ case ContiguousShape:
+ m_butterfly->contiguous()[i].set(globalData, this, value);
+ break;
+
+ default:
+ CRASH();
+ }
}
void JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, bool shouldThrow, ArrayStorage* storage)
@@ -1592,8 +2017,23 @@ void JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue
break;
}
+ case ALL_UNDECIDED_INDEXING_TYPES: {
+ CRASH();
+ break;
+ }
+
+ case ALL_INT32_INDEXING_TYPES: {
+ putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, i, value);
+ break;
+ }
+
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, i, value);
+ break;
+ }
+
case ALL_CONTIGUOUS_INDEXING_TYPES: {
- putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, i, value);
+ putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, i, value);
break;
}
@@ -1724,12 +2164,49 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV
return true;
}
+ case ALL_UNDECIDED_INDEXING_TYPES: {
+ convertUndecidedForValue(exec->globalData(), value);
+ // Reloop.
+ return putDirectIndex(exec, i, value, attributes, mode);
+ }
+
+ case ALL_INT32_INDEXING_TYPES: {
+ if (attributes & (ReadOnly | Accessor)) {
+ return putDirectIndexBeyondVectorLengthWithArrayStorage(
+ exec, i, value, attributes, mode, convertInt32ToArrayStorage(globalData));
+ }
+ if (!value.isInt32()) {
+ convertInt32ForValue(globalData, value);
+ return putDirectIndexBeyondVectorLength(exec, i, value, attributes, mode);
+ }
+ putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, i, value);
+ return true;
+ }
+
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ if (attributes & (ReadOnly | Accessor)) {
+ return putDirectIndexBeyondVectorLengthWithArrayStorage(
+ exec, i, value, attributes, mode, convertDoubleToArrayStorage(globalData));
+ }
+ if (!value.isNumber()) {
+ convertDoubleToContiguous(globalData);
+ return putDirectIndexBeyondVectorLength(exec, i, value, attributes, mode);
+ }
+ double valueAsDouble = value.asNumber();
+ if (valueAsDouble != valueAsDouble) {
+ convertDoubleToContiguous(globalData);
+ return putDirectIndexBeyondVectorLength(exec, i, value, attributes, mode);
+ }
+ putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, i, value);
+ return true;
+ }
+
case ALL_CONTIGUOUS_INDEXING_TYPES: {
if (attributes & (ReadOnly | Accessor)) {
return putDirectIndexBeyondVectorLengthWithArrayStorage(
exec, i, value, attributes, mode, convertContiguousToArrayStorage(globalData));
}
- putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, i, value);
+ putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, i, value);
return true;
}
@@ -1769,33 +2246,65 @@ ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned desiredLength)
unsigned vectorLength;
unsigned length;
- switch (structure()->indexingType()) {
- case ALL_BLANK_INDEXING_TYPES:
- vectorLength = 0;
- length = 0;
- break;
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ if (hasIndexedProperties(structure()->indexingType())) {
vectorLength = m_butterfly->vectorLength();
length = m_butterfly->publicLength();
- break;
- default:
- CRASH();
- return 0;
+ } else {
+ vectorLength = 0;
+ length = 0;
}
+
return getNewVectorLength(vectorLength, length, desiredLength);
}
-unsigned JSObject::countElementsInContiguous(Butterfly* butterfly)
+template<IndexingType indexingShape>
+unsigned JSObject::countElements(Butterfly* butterfly)
{
unsigned numValues = 0;
for (unsigned i = butterfly->publicLength(); i--;) {
- if (butterfly->contiguous()[i])
- numValues++;
+ switch (indexingShape) {
+ case Int32Shape:
+ case ContiguousShape:
+ if (butterfly->contiguous()[i])
+ numValues++;
+ break;
+
+ case DoubleShape: {
+ double value = butterfly->contiguousDouble()[i];
+ if (value == value)
+ numValues++;
+ break;
+ }
+
+ default:
+ CRASH();
+ }
}
return numValues;
}
+unsigned JSObject::countElements()
+{
+ switch (structure()->indexingType()) {
+ case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ return 0;
+
+ case ALL_INT32_INDEXING_TYPES:
+ return countElements<Int32Shape>(m_butterfly);
+
+ case ALL_DOUBLE_INDEXING_TYPES:
+ return countElements<DoubleShape>(m_butterfly);
+
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ return countElements<ContiguousShape>(m_butterfly);
+
+ default:
+ CRASH();
+ return 0;
+ }
+}
+
bool JSObject::increaseVectorLength(JSGlobalData& globalData, unsigned newLength)
{
// This function leaves the array in an internally inconsistent state, because it does not move any values from sparse value map
@@ -1839,19 +2348,24 @@ bool JSObject::increaseVectorLength(JSGlobalData& globalData, unsigned newLength
return true;
}
-void JSObject::ensureContiguousLengthSlow(JSGlobalData& globalData, unsigned length)
+void JSObject::ensureLengthSlow(JSGlobalData& globalData, unsigned length)
{
ASSERT(length < MAX_ARRAY_INDEX);
- ASSERT(hasContiguous(structure()->indexingType()));
+ ASSERT(hasContiguous(structure()->indexingType()) || hasInt32(structure()->indexingType()) || hasDouble(structure()->indexingType()) || hasUndecided(structure()->indexingType()));
ASSERT(length > m_butterfly->vectorLength());
unsigned newVectorLength = std::min(
length << 1,
MAX_STORAGE_VECTOR_LENGTH);
+ unsigned oldVectorLength = m_butterfly->vectorLength();
m_butterfly = m_butterfly->growArrayRight(
globalData, structure(), structure()->outOfLineCapacity(), true,
- m_butterfly->vectorLength() * sizeof(EncodedJSValue),
+ oldVectorLength * sizeof(EncodedJSValue),
newVectorLength * sizeof(EncodedJSValue));
+ if (hasDouble(structure()->indexingType())) {
+ for (unsigned i = oldVectorLength; i < newVectorLength; ++i)
+ m_butterfly->contiguousDouble()[i] = QNaN;
+ }
m_butterfly->setVectorLength(newVectorLength);
}
@@ -1881,8 +2395,10 @@ bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Prope
switch (object->structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
return false;
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES: {
Butterfly* butterfly = object->m_butterfly;
if (i >= butterfly->vectorLength())
@@ -1894,6 +2410,17 @@ bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Prope
return true;
}
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ Butterfly* butterfly = object->m_butterfly;
+ if (i >= butterfly->vectorLength())
+ return false;
+ double value = butterfly->contiguousDouble()[i];
+ if (value != value)
+ return false;
+ descriptor.setDescriptor(JSValue(JSValue::EncodeAsDouble, value), 0);
+ return true;
+ }
+
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = object->m_butterfly->arrayStorage();
if (i >= storage->length())
diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h
index 82455390f..f9ae73ed4 100644
--- a/Source/JavaScriptCore/runtime/JSObject.h
+++ b/Source/JavaScriptCore/runtime/JSObject.h
@@ -151,30 +151,16 @@ public:
unsigned getArrayLength() const
{
- switch (structure()->indexingType()) {
- case ALL_BLANK_INDEXING_TYPES:
+ if (!hasIndexedProperties(structure()->indexingType()))
return 0;
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return m_butterfly->publicLength();
- default:
- ASSERT_NOT_REACHED();
- return 0;
- }
+ return m_butterfly->publicLength();
}
unsigned getVectorLength()
{
- switch (structure()->indexingType()) {
- case ALL_BLANK_INDEXING_TYPES:
+ if (!hasIndexedProperties(structure()->indexingType()))
return 0;
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return m_butterfly->vectorLength();
- default:
- ASSERT_NOT_REACHED();
- return 0;
- }
+ return m_butterfly->vectorLength();
}
JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
@@ -214,9 +200,19 @@ public:
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
return false;
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return i < m_butterfly->vectorLength() && m_butterfly->contiguous()[i];
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ if (i >= m_butterfly->vectorLength())
+ return false;
+ double value = m_butterfly->contiguousDouble()[i];
+ if (value != value)
+ return false;
+ return true;
+ }
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return i < m_butterfly->arrayStorage()->vectorLength() && m_butterfly->arrayStorage()->m_vector[i];
default:
@@ -228,8 +224,11 @@ public:
JSValue getIndexQuickly(unsigned i)
{
switch (structure()->indexingType()) {
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return m_butterfly->contiguous()[i].get();
+ case ALL_DOUBLE_INDEXING_TYPES:
+ return JSValue(JSValue::EncodeAsDouble, m_butterfly->contiguousDouble()[i]);
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return m_butterfly->arrayStorage()->m_vector[i].get();
default:
@@ -243,10 +242,19 @@ public:
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
break;
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
if (i < m_butterfly->publicLength())
return m_butterfly->contiguous()[i].get();
break;
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ if (i >= m_butterfly->publicLength())
+ break;
+ double result = m_butterfly->contiguousDouble()[i];
+ if (result != result)
+ break;
+ return JSValue(JSValue::EncodeAsDouble, result);
+ }
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
if (i < m_butterfly->arrayStorage()->vectorLength())
return m_butterfly->arrayStorage()->m_vector[i].get();
@@ -279,7 +287,10 @@ public:
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
return false;
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
case NonArrayWithArrayStorage:
case ArrayWithArrayStorage:
@@ -298,7 +309,10 @@ public:
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
return false;
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return i < m_butterfly->vectorLength();
@@ -311,6 +325,14 @@ public:
void setIndexQuickly(JSGlobalData& globalData, unsigned i, JSValue v)
{
switch (structure()->indexingType()) {
+ case ALL_INT32_INDEXING_TYPES: {
+ ASSERT(i < m_butterfly->vectorLength());
+ if (!v.isInt32()) {
+ convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(globalData, i, v);
+ return;
+ }
+ // Fall through to contiguous case.
+ }
case ALL_CONTIGUOUS_INDEXING_TYPES: {
ASSERT(i < m_butterfly->vectorLength());
m_butterfly->contiguous()[i].set(globalData, this, v);
@@ -318,6 +340,22 @@ public:
m_butterfly->setPublicLength(i + 1);
break;
}
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ ASSERT(i < m_butterfly->vectorLength());
+ if (!v.isNumber()) {
+ convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v);
+ return;
+ }
+ double value = v.asNumber();
+ if (value != value) {
+ convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v);
+ return;
+ }
+ m_butterfly->contiguousDouble()[i] = value;
+ if (i >= m_butterfly->publicLength())
+ m_butterfly->setPublicLength(i + 1);
+ break;
+ }
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = m_butterfly->arrayStorage();
WriteBarrier<Unknown>& x = storage->m_vector[i];
@@ -338,12 +376,40 @@ public:
void initializeIndex(JSGlobalData& globalData, unsigned i, JSValue v)
{
switch (structure()->indexingType()) {
+ case ALL_UNDECIDED_INDEXING_TYPES: {
+ setIndexQuicklyToUndecided(globalData, i, v);
+ break;
+ }
+ case ALL_INT32_INDEXING_TYPES: {
+ ASSERT(i < m_butterfly->publicLength());
+ ASSERT(i < m_butterfly->vectorLength());
+ if (!v.isInt32()) {
+ convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(globalData, i, v);
+ break;
+ }
+ // Fall through.
+ }
case ALL_CONTIGUOUS_INDEXING_TYPES: {
ASSERT(i < m_butterfly->publicLength());
ASSERT(i < m_butterfly->vectorLength());
m_butterfly->contiguous()[i].set(globalData, this, v);
break;
}
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ ASSERT(i < m_butterfly->publicLength());
+ ASSERT(i < m_butterfly->vectorLength());
+ if (!v.isNumber()) {
+ convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v);
+ return;
+ }
+ double value = v.asNumber();
+ if (value != value) {
+ convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v);
+ return;
+ }
+ m_butterfly->contiguousDouble()[i] = value;
+ break;
+ }
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = m_butterfly->arrayStorage();
ASSERT(i < storage->length());
@@ -360,6 +426,9 @@ public:
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return false;
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
@@ -374,6 +443,9 @@ public:
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return false;
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
@@ -571,6 +643,30 @@ public:
// foo->attemptToInterceptPutByIndexOnHole(...);
bool attemptToInterceptPutByIndexOnHoleForPrototype(ExecState*, JSValue thisValue, unsigned propertyName, JSValue, bool shouldThrow);
+ // Returns 0 if int32 storage cannot be created - either because
+ // indexing should be sparse, we're having a bad time, or because
+ // we already have a more general form of storage (double,
+ // contiguous, array storage).
+ WriteBarrier<Unknown>* ensureInt32(JSGlobalData& globalData)
+ {
+ if (LIKELY(hasInt32(structure()->indexingType())))
+ return m_butterfly->contiguousInt32();
+
+ return ensureInt32Slow(globalData);
+ }
+
+ // Returns 0 if double storage cannot be created - either because
+ // indexing should be sparse, we're having a bad time, or because
+ // we already have a more general form of storage (contiguous,
+ // or array storage).
+ double* ensureDouble(JSGlobalData& globalData)
+ {
+ if (LIKELY(hasDouble(structure()->indexingType())))
+ return m_butterfly->contiguousDouble();
+
+ return ensureDoubleSlow(globalData);
+ }
+
// Returns 0 if contiguous storage cannot be created - either because
// indexing should be sparse or because we're having a bad time.
WriteBarrier<Unknown>* ensureContiguous(JSGlobalData& globalData)
@@ -593,14 +689,6 @@ public:
return ensureArrayStorageSlow(globalData);
}
- Butterfly* ensureIndexedStorage(JSGlobalData& globalData)
- {
- if (LIKELY(hasIndexedProperties(structure()->indexingType())))
- return m_butterfly;
-
- return ensureIndexedStorageSlow(globalData);
- }
-
static size_t offsetOfInlineStorage();
static ptrdiff_t butterflyOffset()
@@ -661,19 +749,47 @@ protected:
return 0;
}
}
-
+
+ Butterfly* createInitialUndecided(JSGlobalData&, unsigned length);
+ WriteBarrier<Unknown>* createInitialInt32(JSGlobalData&, unsigned length);
+ double* createInitialDouble(JSGlobalData&, unsigned length);
+ WriteBarrier<Unknown>* createInitialContiguous(JSGlobalData&, unsigned length);
+
+ void convertUndecidedForValue(JSGlobalData&, JSValue);
+ void convertInt32ForValue(JSGlobalData&, JSValue);
+
ArrayStorage* createArrayStorage(JSGlobalData&, unsigned length, unsigned vectorLength);
ArrayStorage* createInitialArrayStorage(JSGlobalData&);
- WriteBarrier<Unknown>* createInitialContiguous(JSGlobalData&, unsigned length);
+
+ WriteBarrier<Unknown>* convertUndecidedToInt32(JSGlobalData&);
+ double* convertUndecidedToDouble(JSGlobalData&);
+ WriteBarrier<Unknown>* convertUndecidedToContiguous(JSGlobalData&);
+ ArrayStorage* convertUndecidedToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength);
+ ArrayStorage* convertUndecidedToArrayStorage(JSGlobalData&, NonPropertyTransition);
+ ArrayStorage* convertUndecidedToArrayStorage(JSGlobalData&);
+
+ double* convertInt32ToDouble(JSGlobalData&);
+ WriteBarrier<Unknown>* convertInt32ToContiguous(JSGlobalData&);
+ ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength);
+ ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&, NonPropertyTransition);
+ ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&);
+
+ WriteBarrier<Unknown>* convertDoubleToContiguous(JSGlobalData&);
+ ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength);
+ ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&, NonPropertyTransition);
+ ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&);
+
ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength);
ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&, NonPropertyTransition);
ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&);
+
ArrayStorage* ensureArrayStorageExistsAndEnterDictionaryIndexingMode(JSGlobalData&);
bool defineOwnNonIndexProperty(ExecState*, PropertyName, PropertyDescriptor&, bool throwException);
- void putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState*, unsigned propertyName, JSValue);
+ template<IndexingType indexingShape>
+ void putByIndexBeyondVectorLengthWithoutAttributes(ExecState*, unsigned propertyName, JSValue);
void putByIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, bool shouldThrow, ArrayStorage*);
bool increaseVectorLength(JSGlobalData&, unsigned newLength);
@@ -687,24 +803,33 @@ protected:
// Call this if you want setIndexQuickly to succeed and you're sure that
// the array is contiguous.
- void ensureContiguousLength(JSGlobalData& globalData, unsigned length)
+ void ensureLength(JSGlobalData& globalData, unsigned length)
{
ASSERT(length < MAX_ARRAY_INDEX);
- ASSERT(hasContiguous(structure()->indexingType()));
+ ASSERT(hasContiguous(structure()->indexingType()) || hasInt32(structure()->indexingType()) || hasDouble(structure()->indexingType()) || hasUndecided(structure()->indexingType()));
if (m_butterfly->vectorLength() < length)
- ensureContiguousLengthSlow(globalData, length);
+ ensureLengthSlow(globalData, length);
if (m_butterfly->publicLength() < length)
m_butterfly->setPublicLength(length);
}
- unsigned countElementsInContiguous(Butterfly*);
+ template<IndexingType indexingShape>
+ unsigned countElements(Butterfly*);
+ // This is relevant to undecided, int32, double, and contiguous.
+ unsigned countElements();
+
+ // This strange method returns a pointer to the start of the indexed data
+ // as if it contained JSValues. But it won't always contain JSValues.
+ // Make sure you cast this to the appropriate type before using.
template<IndexingType indexingType>
WriteBarrier<Unknown>* indexingData()
{
switch (indexingType) {
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return m_butterfly->contiguous();
@@ -720,6 +845,7 @@ protected:
WriteBarrier<Unknown>* currentIndexingData()
{
switch (structure()->indexingType()) {
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return m_butterfly->contiguous();
@@ -732,10 +858,32 @@ protected:
}
}
+ JSValue getHolyIndexQuickly(unsigned i)
+ {
+ switch (structure()->indexingType()) {
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ return m_butterfly->contiguous()[i].get();
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ double value = m_butterfly->contiguousDouble()[i];
+ if (value == value)
+ return JSValue(JSValue::EncodeAsDouble, value);
+ return JSValue();
+ }
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ return m_butterfly->arrayStorage()->m_vector[i].get();
+ default:
+ CRASH();
+ return JSValue();
+ }
+ }
+
template<IndexingType indexingType>
unsigned relevantLength()
{
switch (indexingType) {
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return m_butterfly->publicLength();
@@ -753,6 +901,8 @@ protected:
unsigned currentRelevantLength()
{
switch (structure()->indexingType()) {
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return m_butterfly->publicLength();
@@ -778,6 +928,8 @@ private:
void isObject();
void isString();
+ Butterfly* createInitialIndexedStorage(JSGlobalData&, unsigned length, size_t elementSize);
+
ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(JSGlobalData&, ArrayStorage*);
template<PutMode>
@@ -800,11 +952,18 @@ private:
JS_EXPORT_PRIVATE bool getOwnPropertySlotSlow(ExecState*, PropertyName, PropertySlot&);
- void ensureContiguousLengthSlow(JSGlobalData&, unsigned length);
+ ArrayStorage* constructConvertedArrayStorageWithoutCopyingElements(JSGlobalData&, unsigned neededLength);
+
+ JS_EXPORT_PRIVATE void setIndexQuicklyToUndecided(JSGlobalData&, unsigned index, JSValue);
+ JS_EXPORT_PRIVATE void convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(JSGlobalData&, unsigned index, JSValue);
+ JS_EXPORT_PRIVATE void convertDoubleToContiguousWhilePerformingSetIndex(JSGlobalData&, unsigned index, JSValue);
+
+ void ensureLengthSlow(JSGlobalData&, unsigned length);
+ WriteBarrier<Unknown>* ensureInt32Slow(JSGlobalData&);
+ double* ensureDoubleSlow(JSGlobalData&);
WriteBarrier<Unknown>* ensureContiguousSlow(JSGlobalData&);
ArrayStorage* ensureArrayStorageSlow(JSGlobalData&);
- Butterfly* ensureIndexedStorageSlow(JSGlobalData&);
protected:
Butterfly* m_butterfly;
diff --git a/Source/JavaScriptCore/runtime/JSValue.cpp b/Source/JavaScriptCore/runtime/JSValue.cpp
index e7f8cad17..8f245f98d 100644
--- a/Source/JavaScriptCore/runtime/JSValue.cpp
+++ b/Source/JavaScriptCore/runtime/JSValue.cpp
@@ -215,8 +215,8 @@ char* JSValue::description() const
#endif
} else if (isCell()) {
snprintf(
- description, size, "Cell: %p (%p: %s, %s)",
- asCell(), asCell()->structure(), asCell()->structure()->classInfo()->className,
+ description, size, "Cell: %p -> %p (%p: %s, %s)",
+ asCell(), isObject() ? asObject(*this)->butterfly() : 0, asCell()->structure(), asCell()->structure()->classInfo()->className,
indexingTypeToString(asCell()->structure()->indexingTypeIncludingHistory()));
} else if (isTrue())
snprintf(description, size, "True");
diff --git a/Source/JavaScriptCore/runtime/JSValueInlineMethods.h b/Source/JavaScriptCore/runtime/JSValueInlines.h
index 224982e9e..c5a42f67f 100644
--- a/Source/JavaScriptCore/runtime/JSValueInlineMethods.h
+++ b/Source/JavaScriptCore/runtime/JSValueInlines.h
@@ -23,8 +23,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef JSValueInlineMethods_h
-#define JSValueInlineMethods_h
+#ifndef JSValueInlines_h
+#define JSValueInlines_h
#include "JSValue.h"
@@ -493,4 +493,5 @@ namespace JSC {
} // namespace JSC
-#endif // JSValueInlineMethods_h
+#endif // JSValueInlines_h
+
diff --git a/Source/JavaScriptCore/runtime/LiteralParser.cpp b/Source/JavaScriptCore/runtime/LiteralParser.cpp
index cd854417b..bf27327bf 100644
--- a/Source/JavaScriptCore/runtime/LiteralParser.cpp
+++ b/Source/JavaScriptCore/runtime/LiteralParser.cpp
@@ -27,8 +27,8 @@
#include "config.h"
#include "LiteralParser.h"
-#include "ButterflyInlineMethods.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "ButterflyInlines.h"
+#include "CopiedSpaceInlines.h"
#include "JSArray.h"
#include "JSString.h"
#include "Lexer.h"
@@ -548,7 +548,7 @@ JSValue LiteralParser<CharType>::parse(ParserState initialState)
switch(state) {
startParseArray:
case StartParseArray: {
- JSArray* array = constructEmptyArray(m_exec);
+ JSArray* array = constructEmptyArray(m_exec, 0);
objectStack.append(array);
// fallthrough
}
diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
index 7df047d28..7e74a914b 100644
--- a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
@@ -21,8 +21,8 @@
#include "config.h"
#include "ObjectConstructor.h"
-#include "ButterflyInlineMethods.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "ButterflyInlines.h"
+#include "CopiedSpaceInlines.h"
#include "Error.h"
#include "ExceptionHelpers.h"
#include "JSFunction.h"
@@ -182,7 +182,7 @@ EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState* exe
return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested property names of a value that is not an object.")));
PropertyNameArray properties(exec);
asObject(exec->argument(0))->methodTable()->getOwnPropertyNames(asObject(exec->argument(0)), exec, properties, IncludeDontEnumProperties);
- JSArray* names = constructEmptyArray(exec);
+ JSArray* names = constructEmptyArray(exec, 0);
size_t numProperties = properties.size();
for (size_t i = 0; i < numProperties; i++)
names->push(exec, jsOwnedString(exec, properties[i].string()));
@@ -196,7 +196,7 @@ EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec)
return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested keys of a value that is not an object.")));
PropertyNameArray properties(exec);
asObject(exec->argument(0))->methodTable()->getOwnPropertyNames(asObject(exec->argument(0)), exec, properties, ExcludeDontEnumProperties);
- JSArray* keys = constructEmptyArray(exec);
+ JSArray* keys = constructEmptyArray(exec, 0);
size_t numProperties = properties.size();
for (size_t i = 0; i < numProperties; i++)
keys->push(exec, jsOwnedString(exec, properties[i].string()));
diff --git a/Source/JavaScriptCore/runtime/Operations.h b/Source/JavaScriptCore/runtime/Operations.h
index 01df7e98c..ed14e895f 100644
--- a/Source/JavaScriptCore/runtime/Operations.h
+++ b/Source/JavaScriptCore/runtime/Operations.h
@@ -26,7 +26,7 @@
#include "Interpreter.h"
#include "JSProxy.h"
#include "JSString.h"
-#include "JSValueInlineMethods.h"
+#include "JSValueInlines.h"
namespace JSC {
diff --git a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp
index ce9c2d2db..19f3b81ad 100644
--- a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp
@@ -26,7 +26,7 @@
#include "config.h"
#include "RegExpMatchesArray.h"
-#include "ButterflyInlineMethods.h"
+#include "ButterflyInlines.h"
namespace JSC {
diff --git a/Source/JavaScriptCore/runtime/RegExpObject.cpp b/Source/JavaScriptCore/runtime/RegExpObject.cpp
index 35de40912..00dd1ed74 100644
--- a/Source/JavaScriptCore/runtime/RegExpObject.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpObject.cpp
@@ -21,8 +21,8 @@
#include "config.h"
#include "RegExpObject.h"
-#include "ButterflyInlineMethods.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "ButterflyInlines.h"
+#include "CopiedSpaceInlines.h"
#include "Error.h"
#include "ExceptionHelpers.h"
#include "JSArray.h"
diff --git a/Source/JavaScriptCore/runtime/StringPrototype.cpp b/Source/JavaScriptCore/runtime/StringPrototype.cpp
index 5aafe8bb3..93009d806 100644
--- a/Source/JavaScriptCore/runtime/StringPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp
@@ -22,9 +22,9 @@
#include "config.h"
#include "StringPrototype.h"
-#include "ButterflyInlineMethods.h"
+#include "ButterflyInlines.h"
#include "CachedCall.h"
-#include "CopiedSpaceInlineMethods.h"
+#include "CopiedSpaceInlines.h"
#include "Error.h"
#include "Executable.h"
#include "JSGlobalObjectFunctions.h"
@@ -870,7 +870,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec)
return JSValue::encode(jsNull());
}
- return JSValue::encode(constructArray(exec, list));
+ return JSValue::encode(constructArray(exec, static_cast<ArrayAllocationProfile*>(0), list));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec)
@@ -973,7 +973,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
// 3. Let A be a new array created as if by the expression new Array()
// where Array is the standard built-in constructor with that name.
- JSArray* result = constructEmptyArray(exec);
+ JSArray* result = constructEmptyArray(exec, 0);
// 4. Let lengthA be 0.
unsigned resultLength = 0;
@@ -1388,7 +1388,10 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState* exec)
return throwVMTypeError(exec);
String s = thisValue.toString(exec)->value(exec);
JSValue a0 = exec->argument(0);
- return JSValue::encode(jsMakeNontrivialString(exec, "<font color=\"", a0.toString(exec)->value(exec), "\">", s, "</font>"));
+ String color = a0.toWTFString(exec);
+ color.replaceWithLiteral('"', "&quot;");
+
+ return JSValue::encode(jsMakeNontrivialString(exec, "<font color=\"", color, "\">", s, "</font>"));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec)
@@ -1433,7 +1436,10 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec)
return JSValue::encode(jsNontrivialString(exec, impl));
}
- return JSValue::encode(jsMakeNontrivialString(exec, "<font size=\"", a0.toString(exec)->value(exec), "\">", s, "</font>"));
+ String fontSize = a0.toWTFString(exec);
+ fontSize.replaceWithLiteral('"', "&quot;");
+
+ return JSValue::encode(jsMakeNontrivialString(exec, "<font size=\"", fontSize, "\">", s, "</font>"));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec)
@@ -1443,7 +1449,10 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec)
return throwVMTypeError(exec);
String s = thisValue.toString(exec)->value(exec);
JSValue a0 = exec->argument(0);
- return JSValue::encode(jsMakeNontrivialString(exec, "<a name=\"", a0.toString(exec)->value(exec), "\">", s, "</a>"));
+ String anchor = a0.toWTFString(exec);
+ anchor.replaceWithLiteral('"', "&quot;");
+
+ return JSValue::encode(jsMakeNontrivialString(exec, "<a name=\"", anchor, "\">", s, "</a>"));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec)
@@ -1453,7 +1462,8 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec)
return throwVMTypeError(exec);
String s = thisValue.toString(exec)->value(exec);
JSValue a0 = exec->argument(0);
- String linkText = a0.toString(exec)->value(exec);
+ String linkText = a0.toWTFString(exec);
+ linkText.replaceWithLiteral('"', "&quot;");
unsigned linkTextSize = linkText.length();
unsigned stringSize = s.length();
diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp
index e733c7e23..e930c022a 100644
--- a/Source/JavaScriptCore/runtime/Structure.cpp
+++ b/Source/JavaScriptCore/runtime/Structure.cpp
@@ -543,12 +543,13 @@ Structure* Structure::nonPropertyTransition(JSGlobalData& globalData, Structure*
unsigned attributes = toAttributes(transitionKind);
IndexingType indexingType = newIndexingType(structure->indexingTypeIncludingHistory(), transitionKind);
- JSGlobalObject* globalObject = structure->globalObject();
- if (structure == globalObject->arrayStructure()) {
- Structure* transition = globalObject->arrayStructureWithArrayStorage();
- if (transition->indexingTypeIncludingHistory() == indexingType) {
- structure->notifyTransitionFromThisStructure();
- return transition;
+ if (JSGlobalObject* globalObject = structure->m_globalObject.get()) {
+ if (globalObject->isOriginalArrayStructure(structure)) {
+ Structure* result = globalObject->originalArrayStructureForIndexingType(indexingType);
+ if (result->indexingTypeIncludingHistory() == indexingType) {
+ structure->notifyTransitionFromThisStructure();
+ return result;
+ }
}
}
diff --git a/Source/JavaScriptCore/runtime/StructureTransitionTable.h b/Source/JavaScriptCore/runtime/StructureTransitionTable.h
index 3ab7b2014..5291ed540 100644
--- a/Source/JavaScriptCore/runtime/StructureTransitionTable.h
+++ b/Source/JavaScriptCore/runtime/StructureTransitionTable.h
@@ -43,6 +43,9 @@ static const unsigned FirstInternalAttribute = 1 << 6; // Use for transitions th
// Support for attributes used to indicate transitions not related to properties.
// If any of these are used, the string portion of the key should be 0.
enum NonPropertyTransition {
+ AllocateUndecided,
+ AllocateInt32,
+ AllocateDouble,
AllocateContiguous,
AllocateArrayStorage,
AllocateSlowPutArrayStorage,
@@ -58,14 +61,23 @@ inline unsigned toAttributes(NonPropertyTransition transition)
inline IndexingType newIndexingType(IndexingType oldType, NonPropertyTransition transition)
{
switch (transition) {
- case AllocateContiguous:
+ case AllocateUndecided:
ASSERT(!hasIndexedProperties(oldType));
- return oldType | ContiguousShape;
+ return oldType | UndecidedShape;
+ case AllocateInt32:
+ ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType));
+ return (oldType & ~IndexingShapeMask) | Int32Shape;
+ case AllocateDouble:
+ ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType));
+ return (oldType & ~IndexingShapeMask) | DoubleShape;
+ case AllocateContiguous:
+ ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType));
+ return (oldType & ~IndexingShapeMask) | ContiguousShape;
case AllocateArrayStorage:
- ASSERT(!hasIndexedProperties(oldType) || hasContiguous(oldType));
+ ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType));
return (oldType & ~IndexingShapeMask) | ArrayStorageShape;
case AllocateSlowPutArrayStorage:
- ASSERT(!hasIndexedProperties(oldType) || hasContiguous(oldType));
+ ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType) || hasContiguous(oldType));
return (oldType & ~IndexingShapeMask) | SlowPutArrayStorageShape;
case SwitchToSlowPutArrayStorage:
ASSERT(hasFastArrayStorage(oldType));