summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2012-11-22 09:09:45 +0100
committerSimon Hausmann <simon.hausmann@digia.com>2012-11-22 09:10:13 +0100
commit470286ecfe79d59df14944e5b5d34630fc739391 (patch)
tree43983212872e06cebefd2ae474418fa2908ca54c /Source/JavaScriptCore/runtime
parent23037105e948c2065da5a937d3a2396b0ff45c1e (diff)
downloadqtwebkit-470286ecfe79d59df14944e5b5d34630fc739391.tar.gz
Imported WebKit commit e89504fa9195b2063b2530961d4b73dd08de3242 (http://svn.webkit.org/repository/webkit/trunk@135485)
Change-Id: I03774e5ac79721c13ffa30d152537a74d0b12e66 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'Source/JavaScriptCore/runtime')
-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.cpp23
-rw-r--r--Source/JavaScriptCore/runtime/ArrayPrototype.h32
-rw-r--r--Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h38
-rw-r--r--Source/JavaScriptCore/runtime/BooleanConstructor.h48
-rw-r--r--Source/JavaScriptCore/runtime/BooleanObject.h52
-rw-r--r--Source/JavaScriptCore/runtime/BooleanPrototype.h46
-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/CallData.h42
-rw-r--r--Source/JavaScriptCore/runtime/ClassInfo.h206
-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.h3
-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/JSBoundFunction.cpp7
-rw-r--r--Source/JavaScriptCore/runtime/JSBoundFunction.h2
-rw-r--r--Source/JavaScriptCore/runtime/JSCell.h3
-rw-r--r--Source/JavaScriptCore/runtime/JSFunction.cpp19
-rw-r--r--Source/JavaScriptCore/runtime/JSFunction.h24
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalData.cpp10
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.cpp39
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.h83
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/JSLock.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.cpp677
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.h235
-rw-r--r--Source/JavaScriptCore/runtime/JSValue.cpp16
-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.h21
-rw-r--r--Source/JavaScriptCore/runtime/Options.h2
-rw-r--r--Source/JavaScriptCore/runtime/RegExp.cpp12
-rw-r--r--Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/RegExpObject.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/SamplingCounter.cpp6
-rw-r--r--Source/JavaScriptCore/runtime/StringPrototype.cpp26
-rw-r--r--Source/JavaScriptCore/runtime/Structure.cpp69
-rw-r--r--Source/JavaScriptCore/runtime/Structure.h9
-rw-r--r--Source/JavaScriptCore/runtime/StructureTransitionTable.h20
50 files changed, 2204 insertions, 826 deletions
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..e6d37fb02 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"
@@ -116,15 +116,14 @@ const ClassInfo ArrayPrototype::s_info = {"Array", &JSArray::s_info, 0, ExecStat
ArrayPrototype* ArrayPrototype::create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
{
- Butterfly* butterfly = createArrayButterfly(exec->globalData(), 0);
- ArrayPrototype* prototype = new (NotNull, allocateCell<ArrayPrototype>(*exec->heap())) ArrayPrototype(globalObject, structure, butterfly);
+ ArrayPrototype* prototype = new (NotNull, allocateCell<ArrayPrototype>(*exec->heap())) ArrayPrototype(globalObject, structure);
prototype->finishCreation(globalObject);
return prototype;
}
// ECMA 15.4.4
-ArrayPrototype::ArrayPrototype(JSGlobalObject* globalObject, Structure* structure, Butterfly* butterfly)
- : JSArray(globalObject->globalData(), structure, butterfly)
+ArrayPrototype::ArrayPrototype(JSGlobalObject* globalObject, Structure* structure)
+ : JSArray(globalObject->globalData(), structure, 0)
{
}
@@ -456,7 +455,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 +617,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 +732,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 +747,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 +819,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 +879,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..c23bcdec1 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*);
- 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, ArrayClass);
+ }
- protected:
- void finishCreation(JSGlobalObject*);
- };
+protected:
+ void finishCreation(JSGlobalObject*);
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h b/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h
index 610b8d16c..178bf3fe9 100644
--- a/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h
+++ b/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h
@@ -31,25 +31,25 @@
namespace JSC {
- class BatchedTransitionOptimizer {
- WTF_MAKE_NONCOPYABLE(BatchedTransitionOptimizer);
- public:
- BatchedTransitionOptimizer(JSGlobalData& globalData, JSObject* object)
- : m_globalData(&globalData)
- , m_object(object)
- {
- }
-
- ~BatchedTransitionOptimizer()
- {
- if (m_object->structure()->isDictionary())
- m_object->flattenDictionaryObject(*m_globalData);
- }
-
- private:
- JSGlobalData* m_globalData;
- JSObject* m_object;
- };
+class BatchedTransitionOptimizer {
+ WTF_MAKE_NONCOPYABLE(BatchedTransitionOptimizer);
+public:
+ BatchedTransitionOptimizer(JSGlobalData& globalData, JSObject* object)
+ : m_globalData(&globalData)
+ , m_object(object)
+ {
+ }
+
+ ~BatchedTransitionOptimizer()
+ {
+ if (m_object->structure()->isDictionary())
+ m_object->flattenDictionaryObject(*m_globalData);
+ }
+
+private:
+ JSGlobalData* m_globalData;
+ JSObject* m_object;
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/BooleanConstructor.h b/Source/JavaScriptCore/runtime/BooleanConstructor.h
index 2b6bafa2f..f395374ae 100644
--- a/Source/JavaScriptCore/runtime/BooleanConstructor.h
+++ b/Source/JavaScriptCore/runtime/BooleanConstructor.h
@@ -25,37 +25,37 @@
namespace JSC {
- class BooleanPrototype;
+class BooleanPrototype;
- class BooleanConstructor : public InternalFunction {
- public:
- typedef InternalFunction Base;
+class BooleanConstructor : public InternalFunction {
+public:
+ typedef InternalFunction Base;
- static BooleanConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, BooleanPrototype* booleanPrototype)
- {
- BooleanConstructor* constructor = new (NotNull, allocateCell<BooleanConstructor>(*exec->heap())) BooleanConstructor(globalObject, structure);
- constructor->finishCreation(exec, booleanPrototype);
- return constructor;
- }
+ static BooleanConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, BooleanPrototype* booleanPrototype)
+ {
+ BooleanConstructor* constructor = new (NotNull, allocateCell<BooleanConstructor>(*exec->heap())) BooleanConstructor(globalObject, structure);
+ constructor->finishCreation(exec, booleanPrototype);
+ 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*, BooleanPrototype*);
+protected:
+ void finishCreation(ExecState*, BooleanPrototype*);
- private:
- BooleanConstructor(JSGlobalObject*, Structure*);
- static ConstructType getConstructData(JSCell*, ConstructData&);
- static CallType getCallData(JSCell*, CallData&);
- };
+private:
+ BooleanConstructor(JSGlobalObject*, Structure*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+};
- JSObject* constructBooleanFromImmediateBoolean(ExecState*, JSGlobalObject*, JSValue);
- JSObject* constructBoolean(ExecState*, const ArgList&);
+JSObject* constructBooleanFromImmediateBoolean(ExecState*, JSGlobalObject*, JSValue);
+JSObject* constructBoolean(ExecState*, const ArgList&);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/BooleanObject.h b/Source/JavaScriptCore/runtime/BooleanObject.h
index bd0f66944..b6fcccdcf 100644
--- a/Source/JavaScriptCore/runtime/BooleanObject.h
+++ b/Source/JavaScriptCore/runtime/BooleanObject.h
@@ -25,36 +25,36 @@
namespace JSC {
- class BooleanObject : public JSWrapperObject {
- protected:
- JS_EXPORT_PRIVATE BooleanObject(JSGlobalData&, Structure*);
- JS_EXPORT_PRIVATE void finishCreation(JSGlobalData&);
-
- public:
- typedef JSWrapperObject Base;
-
- static BooleanObject* create(JSGlobalData& globalData, Structure* structure)
- {
- BooleanObject* boolean = new (NotNull, allocateCell<BooleanObject>(globalData.heap)) BooleanObject(globalData, structure);
- boolean->finishCreation(globalData);
- return boolean;
- }
-
- static JS_EXPORTDATA const ClassInfo s_info;
-
- static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
- }
- };
+class BooleanObject : public JSWrapperObject {
+protected:
+ JS_EXPORT_PRIVATE BooleanObject(JSGlobalData&, Structure*);
+ JS_EXPORT_PRIVATE void finishCreation(JSGlobalData&);
- BooleanObject* asBooleanObject(JSValue);
+public:
+ typedef JSWrapperObject Base;
- inline BooleanObject* asBooleanObject(JSValue value)
+ static BooleanObject* create(JSGlobalData& globalData, Structure* structure)
+ {
+ BooleanObject* boolean = new (NotNull, allocateCell<BooleanObject>(globalData.heap)) BooleanObject(globalData, structure);
+ boolean->finishCreation(globalData);
+ return boolean;
+ }
+
+ static JS_EXPORTDATA const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
{
- ASSERT(asObject(value)->inherits(&BooleanObject::s_info));
- return static_cast<BooleanObject*>(asObject(value));
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
}
+};
+
+BooleanObject* asBooleanObject(JSValue);
+
+inline BooleanObject* asBooleanObject(JSValue value)
+{
+ ASSERT(asObject(value)->inherits(&BooleanObject::s_info));
+ return static_cast<BooleanObject*>(asObject(value));
+}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/BooleanPrototype.h b/Source/JavaScriptCore/runtime/BooleanPrototype.h
index 3767f76ed..05790a755 100644
--- a/Source/JavaScriptCore/runtime/BooleanPrototype.h
+++ b/Source/JavaScriptCore/runtime/BooleanPrototype.h
@@ -25,34 +25,34 @@
namespace JSC {
- class BooleanPrototype : public BooleanObject {
- public:
- typedef BooleanObject Base;
-
- static BooleanPrototype* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
- {
- BooleanPrototype* prototype = new (NotNull, allocateCell<BooleanPrototype>(*exec->heap())) BooleanPrototype(exec, structure);
- prototype->finishCreation(exec, globalObject);
- return prototype;
- }
+class BooleanPrototype : public BooleanObject {
+public:
+ typedef BooleanObject Base;
+
+ static BooleanPrototype* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
+ {
+ BooleanPrototype* prototype = new (NotNull, allocateCell<BooleanPrototype>(*exec->heap())) BooleanPrototype(exec, structure);
+ prototype->finishCreation(exec, globalObject);
+ return prototype;
+ }
- 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*, JSGlobalObject*);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | BooleanObject::StructureFlags;
+protected:
+ void finishCreation(ExecState*, JSGlobalObject*);
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | BooleanObject::StructureFlags;
- private:
- BooleanPrototype(ExecState*, Structure*);
- static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
+private:
+ BooleanPrototype(ExecState*, Structure*);
+ static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
- static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
- };
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
+};
} // 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/CallData.h b/Source/JavaScriptCore/runtime/CallData.h
index 77478304c..7df36c72a 100644
--- a/Source/JavaScriptCore/runtime/CallData.h
+++ b/Source/JavaScriptCore/runtime/CallData.h
@@ -33,31 +33,31 @@
namespace JSC {
- class ArgList;
- class ExecState;
- class FunctionExecutable;
- class JSObject;
- class JSScope;
+class ArgList;
+class ExecState;
+class FunctionExecutable;
+class JSObject;
+class JSScope;
- enum CallType {
- CallTypeNone,
- CallTypeHost,
- CallTypeJS
- };
+enum CallType {
+ CallTypeNone,
+ CallTypeHost,
+ CallTypeJS
+};
- typedef EncodedJSValue (JSC_HOST_CALL *NativeFunction)(ExecState*);
+typedef EncodedJSValue (JSC_HOST_CALL *NativeFunction)(ExecState*);
- union CallData {
- struct {
- NativeFunction function;
- } native;
- struct {
- FunctionExecutable* functionExecutable;
- JSScope* scope;
- } js;
- };
+union CallData {
+ struct {
+ NativeFunction function;
+ } native;
+ struct {
+ FunctionExecutable* functionExecutable;
+ JSScope* scope;
+ } js;
+};
- JS_EXPORT_PRIVATE JSValue call(ExecState*, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&);
+JS_EXPORT_PRIVATE JSValue call(ExecState*, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ClassInfo.h b/Source/JavaScriptCore/runtime/ClassInfo.h
index c918621fe..af1d71e13 100644
--- a/Source/JavaScriptCore/runtime/ClassInfo.h
+++ b/Source/JavaScriptCore/runtime/ClassInfo.h
@@ -29,90 +29,90 @@
namespace JSC {
- class HashEntry;
- struct HashTable;
+class HashEntry;
+struct HashTable;
- struct MethodTable {
- typedef void (*DestroyFunctionPtr)(JSCell*);
- DestroyFunctionPtr destroy;
+struct MethodTable {
+ typedef void (*DestroyFunctionPtr)(JSCell*);
+ DestroyFunctionPtr destroy;
- typedef void (*VisitChildrenFunctionPtr)(JSCell*, SlotVisitor&);
- VisitChildrenFunctionPtr visitChildren;
+ typedef void (*VisitChildrenFunctionPtr)(JSCell*, SlotVisitor&);
+ VisitChildrenFunctionPtr visitChildren;
- typedef void (*CopyBackingStoreFunctionPtr)(JSCell*, CopyVisitor&);
- CopyBackingStoreFunctionPtr copyBackingStore;
+ typedef void (*CopyBackingStoreFunctionPtr)(JSCell*, CopyVisitor&);
+ CopyBackingStoreFunctionPtr copyBackingStore;
- typedef CallType (*GetCallDataFunctionPtr)(JSCell*, CallData&);
- GetCallDataFunctionPtr getCallData;
+ typedef CallType (*GetCallDataFunctionPtr)(JSCell*, CallData&);
+ GetCallDataFunctionPtr getCallData;
- typedef ConstructType (*GetConstructDataFunctionPtr)(JSCell*, ConstructData&);
- GetConstructDataFunctionPtr getConstructData;
+ typedef ConstructType (*GetConstructDataFunctionPtr)(JSCell*, ConstructData&);
+ GetConstructDataFunctionPtr getConstructData;
- typedef void (*PutFunctionPtr)(JSCell*, ExecState*, PropertyName propertyName, JSValue, PutPropertySlot&);
- PutFunctionPtr put;
+ typedef void (*PutFunctionPtr)(JSCell*, ExecState*, PropertyName propertyName, JSValue, PutPropertySlot&);
+ PutFunctionPtr put;
- typedef void (*PutByIndexFunctionPtr)(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
- PutByIndexFunctionPtr putByIndex;
+ typedef void (*PutByIndexFunctionPtr)(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
+ PutByIndexFunctionPtr putByIndex;
- typedef bool (*DeletePropertyFunctionPtr)(JSCell*, ExecState*, PropertyName);
- DeletePropertyFunctionPtr deleteProperty;
+ typedef bool (*DeletePropertyFunctionPtr)(JSCell*, ExecState*, PropertyName);
+ DeletePropertyFunctionPtr deleteProperty;
- typedef bool (*DeletePropertyByIndexFunctionPtr)(JSCell*, ExecState*, unsigned);
- DeletePropertyByIndexFunctionPtr deletePropertyByIndex;
+ typedef bool (*DeletePropertyByIndexFunctionPtr)(JSCell*, ExecState*, unsigned);
+ DeletePropertyByIndexFunctionPtr deletePropertyByIndex;
- typedef bool (*GetOwnPropertySlotFunctionPtr)(JSCell*, ExecState*, PropertyName, PropertySlot&);
- GetOwnPropertySlotFunctionPtr getOwnPropertySlot;
+ typedef bool (*GetOwnPropertySlotFunctionPtr)(JSCell*, ExecState*, PropertyName, PropertySlot&);
+ GetOwnPropertySlotFunctionPtr getOwnPropertySlot;
- typedef bool (*GetOwnPropertySlotByIndexFunctionPtr)(JSCell*, ExecState*, unsigned, PropertySlot&);
- GetOwnPropertySlotByIndexFunctionPtr getOwnPropertySlotByIndex;
+ typedef bool (*GetOwnPropertySlotByIndexFunctionPtr)(JSCell*, ExecState*, unsigned, PropertySlot&);
+ GetOwnPropertySlotByIndexFunctionPtr getOwnPropertySlotByIndex;
- typedef JSObject* (*ToThisObjectFunctionPtr)(JSCell*, ExecState*);
- ToThisObjectFunctionPtr toThisObject;
+ typedef JSObject* (*ToThisObjectFunctionPtr)(JSCell*, ExecState*);
+ ToThisObjectFunctionPtr toThisObject;
- typedef JSValue (*DefaultValueFunctionPtr)(const JSObject*, ExecState*, PreferredPrimitiveType);
- DefaultValueFunctionPtr defaultValue;
+ typedef JSValue (*DefaultValueFunctionPtr)(const JSObject*, ExecState*, PreferredPrimitiveType);
+ DefaultValueFunctionPtr defaultValue;
- typedef void (*GetOwnPropertyNamesFunctionPtr)(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
- GetOwnPropertyNamesFunctionPtr getOwnPropertyNames;
+ typedef void (*GetOwnPropertyNamesFunctionPtr)(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ GetOwnPropertyNamesFunctionPtr getOwnPropertyNames;
- typedef void (*GetOwnNonIndexPropertyNamesFunctionPtr)(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
- GetOwnNonIndexPropertyNamesFunctionPtr getOwnNonIndexPropertyNames;
+ typedef void (*GetOwnNonIndexPropertyNamesFunctionPtr)(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ GetOwnNonIndexPropertyNamesFunctionPtr getOwnNonIndexPropertyNames;
- typedef void (*GetPropertyNamesFunctionPtr)(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
- GetPropertyNamesFunctionPtr getPropertyNames;
+ typedef void (*GetPropertyNamesFunctionPtr)(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ GetPropertyNamesFunctionPtr getPropertyNames;
- typedef String (*ClassNameFunctionPtr)(const JSObject*);
- ClassNameFunctionPtr className;
+ typedef String (*ClassNameFunctionPtr)(const JSObject*);
+ ClassNameFunctionPtr className;
- typedef bool (*CustomHasInstanceFunctionPtr)(JSObject*, ExecState*, JSValue);
- CustomHasInstanceFunctionPtr customHasInstance;
+ typedef bool (*CustomHasInstanceFunctionPtr)(JSObject*, ExecState*, JSValue);
+ CustomHasInstanceFunctionPtr customHasInstance;
- typedef void (*PutWithAttributesFunctionPtr)(JSObject*, ExecState*, PropertyName propertyName, JSValue, unsigned attributes);
- PutWithAttributesFunctionPtr putDirectVirtual;
+ typedef void (*PutWithAttributesFunctionPtr)(JSObject*, ExecState*, PropertyName propertyName, JSValue, unsigned attributes);
+ PutWithAttributesFunctionPtr putDirectVirtual;
- typedef bool (*DefineOwnPropertyFunctionPtr)(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool);
- DefineOwnPropertyFunctionPtr defineOwnProperty;
+ typedef bool (*DefineOwnPropertyFunctionPtr)(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool);
+ DefineOwnPropertyFunctionPtr defineOwnProperty;
- typedef bool (*GetOwnPropertyDescriptorFunctionPtr)(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
- GetOwnPropertyDescriptorFunctionPtr getOwnPropertyDescriptor;
- };
+ typedef bool (*GetOwnPropertyDescriptorFunctionPtr)(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
+ GetOwnPropertyDescriptorFunctionPtr getOwnPropertyDescriptor;
+};
#define CREATE_MEMBER_CHECKER(member) \
-template <typename T> \
-struct MemberCheck##member { \
- struct Fallback { \
- void member(...); \
- }; \
- struct Derived : T, Fallback { }; \
- template <typename U, U> struct Check; \
- typedef char Yes[2]; \
- typedef char No[1]; \
- template <typename U> \
- static No &func(Check<void (Fallback::*)(...), &U::member>*); \
- template <typename U> \
- static Yes &func(...); \
- enum { has = sizeof(func<Derived>(0)) == sizeof(Yes) }; \
-}
+ template <typename T> \
+ struct MemberCheck##member { \
+ struct Fallback { \
+ void member(...); \
+ }; \
+ struct Derived : T, Fallback { }; \
+ template <typename U, U> struct Check; \
+ typedef char Yes[2]; \
+ typedef char No[1]; \
+ template <typename U> \
+ static No &func(Check<void (Fallback::*)(...), &U::member>*); \
+ template <typename U> \
+ static Yes &func(...); \
+ enum { has = sizeof(func<Derived>(0)) == sizeof(Yes) }; \
+ }
#define HAS_MEMBER_NAMED(klass, name) (MemberCheck##name<klass>::has)
@@ -141,54 +141,54 @@ struct MemberCheck##member { \
}, \
ClassName::TypedArrayStorageType
- struct ClassInfo {
- /**
- * A string denoting the class name. Example: "Window".
- */
- const char* className;
-
- /**
- * Pointer to the class information of the base class.
- * 0L if there is none.
- */
- const ClassInfo* parentClass;
- /**
- * Static hash-table of properties.
- * For classes that can be used from multiple threads, it is accessed via a getter function that would typically return a pointer to thread-specific value.
- */
- const HashTable* propHashTable(ExecState* exec) const
- {
- if (classPropHashTableGetterFunction)
- return classPropHashTableGetterFunction(exec);
- return staticPropHashTable;
- }
+struct ClassInfo {
+ /**
+ * A string denoting the class name. Example: "Window".
+ */
+ const char* className;
+
+ /**
+ * Pointer to the class information of the base class.
+ * 0L if there is none.
+ */
+ const ClassInfo* parentClass;
+ /**
+ * Static hash-table of properties.
+ * For classes that can be used from multiple threads, it is accessed via a getter function that would typically return a pointer to thread-specific value.
+ */
+ const HashTable* propHashTable(ExecState* exec) const
+ {
+ if (classPropHashTableGetterFunction)
+ return classPropHashTableGetterFunction(exec);
+ return staticPropHashTable;
+ }
- bool isSubClassOf(const ClassInfo* other) const
- {
- for (const ClassInfo* ci = this; ci; ci = ci->parentClass) {
- if (ci == other)
- return true;
- }
- return false;
+ bool isSubClassOf(const ClassInfo* other) const
+ {
+ for (const ClassInfo* ci = this; ci; ci = ci->parentClass) {
+ if (ci == other)
+ return true;
}
-
- bool hasStaticProperties() const
- {
- for (const ClassInfo* ci = this; ci; ci = ci->parentClass) {
- if (ci->staticPropHashTable || ci->classPropHashTableGetterFunction)
- return true;
- }
- return false;
+ return false;
+ }
+
+ bool hasStaticProperties() const
+ {
+ for (const ClassInfo* ci = this; ci; ci = ci->parentClass) {
+ if (ci->staticPropHashTable || ci->classPropHashTableGetterFunction)
+ return true;
}
+ return false;
+ }
- const HashTable* staticPropHashTable;
- typedef const HashTable* (*ClassPropHashTableGetterFunction)(ExecState*);
- const ClassPropHashTableGetterFunction classPropHashTableGetterFunction;
+ const HashTable* staticPropHashTable;
+ typedef const HashTable* (*ClassPropHashTableGetterFunction)(ExecState*);
+ const ClassPropHashTableGetterFunction classPropHashTableGetterFunction;
- MethodTable methodTable;
+ MethodTable methodTable;
- TypedArrayType typedArrayStorageType;
- };
+ TypedArrayType typedArrayStorageType;
+};
} // namespace JSC
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..733de42d6 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 CacheMap {
+ typedef typename HashMap<KeyType, unsigned>::iterator iterator;
+public:
+ CacheMap()
+ : m_randomGenerator((static_cast<uint32_t>(randomNumber() * std::numeric_limits<uint32_t>::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;
+ CacheMap<CodeBlockKey, Strong<UnlinkedCodeBlock>, kMaxCodeBlockEntries> m_cachedCodeBlocks;
+ CacheMap<GlobalFunctionKey, Strong<UnlinkedFunctionExecutable>, kMaxGlobalFunctionEntries> m_cachedGlobalFunctions;
+ CacheMap<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..c1c044b0e 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)
{
@@ -752,6 +752,7 @@ namespace JSC {
: Base(globalData, scope->globalObject()->functionStructure())
, m_executable(globalData, this, executable)
, m_scope(globalData, this, scope)
+ , m_inheritorIDWatchpoint(InitializedBlind) // See comment in JSFunction.cpp concerning the reason for using InitializedBlind as opposed to InitializedWatching.
{
}
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/JSBoundFunction.cpp b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp
index d8f611477..bb1af9d20 100644
--- a/Source/JavaScriptCore/runtime/JSBoundFunction.cpp
+++ b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp
@@ -31,8 +31,6 @@
namespace JSC {
-ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSBoundFunction);
-
const ClassInfo JSBoundFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSBoundFunction) };
EncodedJSValue JSC_HOST_CALL boundFunctionCall(ExecState* exec)
@@ -88,6 +86,11 @@ JSBoundFunction* JSBoundFunction::create(ExecState* exec, JSGlobalObject* global
return function;
}
+void JSBoundFunction::destroy(JSCell* cell)
+{
+ static_cast<JSBoundFunction*>(cell)->JSBoundFunction::~JSBoundFunction();
+}
+
bool JSBoundFunction::customHasInstance(JSObject* object, ExecState* exec, JSValue value)
{
return jsCast<JSBoundFunction*>(object)->m_targetFunction->hasInstance(exec, value);
diff --git a/Source/JavaScriptCore/runtime/JSBoundFunction.h b/Source/JavaScriptCore/runtime/JSBoundFunction.h
index 05a6ad8e1..886021940 100644
--- a/Source/JavaScriptCore/runtime/JSBoundFunction.h
+++ b/Source/JavaScriptCore/runtime/JSBoundFunction.h
@@ -38,6 +38,8 @@ public:
typedef JSFunction Base;
static JSBoundFunction* create(ExecState*, JSGlobalObject*, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs, int, const String&);
+
+ static void destroy(JSCell*);
static bool customHasInstance(JSObject*, ExecState*, JSValue);
diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h
index 3b37613d1..b28fedd8d 100644
--- a/Source/JavaScriptCore/runtime/JSCell.h
+++ b/Source/JavaScriptCore/runtime/JSCell.h
@@ -28,9 +28,8 @@
#include "ConstructData.h"
#include "Heap.h"
#include "JSLock.h"
-#include "JSValueInlineMethods.h"
+#include "JSValueInlines.h"
#include "SlotVisitor.h"
-#include "SlotVisitorInlineMethods.h"
#include "TypedArrayDescriptor.h"
#include "WriteBarrier.h"
#include <wtf/Noncopyable.h>
diff --git a/Source/JavaScriptCore/runtime/JSFunction.cpp b/Source/JavaScriptCore/runtime/JSFunction.cpp
index 891a23930..0a98e7c13 100644
--- a/Source/JavaScriptCore/runtime/JSFunction.cpp
+++ b/Source/JavaScriptCore/runtime/JSFunction.cpp
@@ -48,8 +48,6 @@ EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState* exec)
return throwVMError(exec, createNotAConstructorError(exec, exec->callee()));
}
-ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSFunction);
-
const ClassInfo JSFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFunction) };
bool JSFunction::isHostFunctionNonInline() const
@@ -76,10 +74,25 @@ JSFunction* JSFunction::create(ExecState* exec, JSGlobalObject* globalObject, in
return function;
}
+void JSFunction::destroy(JSCell* cell)
+{
+ static_cast<JSFunction*>(cell)->JSFunction::~JSFunction();
+}
+
JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
: Base(exec->globalData(), structure)
, m_executable()
, m_scope(exec->globalData(), this, globalObject)
+ // We initialize blind so that changes to the prototype after function creation but before
+ // the optimizer kicks in don't disable optimizations. Once the optimizer kicks in, the
+ // watchpoint will start watching and any changes will both force deoptimization and disable
+ // future attempts to optimize. This is necessary because we are guaranteed that the
+ // inheritorID is changed exactly once prior to optimizations kicking in. We could be
+ // smarter and count the number of times the prototype is clobbered and only optimize if it
+ // was clobbered exactly once, but that seems like overkill. In almost all cases it will be
+ // clobbered once, and if it's clobbered more than once, that will probably only occur
+ // before we started optimizing, anyway.
+ , m_inheritorIDWatchpoint(InitializedBlind)
{
}
@@ -340,6 +353,7 @@ void JSFunction::put(JSCell* cell, ExecState* exec, PropertyName propertyName, J
PropertySlot slot;
thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot);
thisObject->m_cachedInheritorID.clear();
+ thisObject->m_inheritorIDWatchpoint.notifyWrite();
// Don't allow this to be cached, since a [[Put]] must clear m_cachedInheritorID.
PutPropertySlot dontCache;
Base::put(thisObject, exec, propertyName, value, dontCache);
@@ -386,6 +400,7 @@ bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, PropertyNa
PropertySlot slot;
thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot);
thisObject->m_cachedInheritorID.clear();
+ thisObject->m_inheritorIDWatchpoint.notifyWrite();
return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
}
diff --git a/Source/JavaScriptCore/runtime/JSFunction.h b/Source/JavaScriptCore/runtime/JSFunction.h
index c1f066585..322ee58e3 100644
--- a/Source/JavaScriptCore/runtime/JSFunction.h
+++ b/Source/JavaScriptCore/runtime/JSFunction.h
@@ -25,7 +25,9 @@
#define JSFunction_h
#include "InternalFunction.h"
+#include "JSDestructibleObject.h"
#include "JSScope.h"
+#include "Watchpoint.h"
namespace JSC {
@@ -46,14 +48,14 @@ namespace JSC {
JS_EXPORT_PRIVATE String getCalculatedDisplayName(CallFrame*, JSObject*);
- class JSFunction : public JSNonFinalObject {
+ class JSFunction : public JSDestructibleObject {
friend class JIT;
friend class DFG::SpeculativeJIT;
friend class DFG::JITCompiler;
friend class JSGlobalData;
public:
- typedef JSNonFinalObject Base;
+ typedef JSDestructibleObject Base;
JS_EXPORT_PRIVATE static JSFunction* create(ExecState*, JSGlobalObject*, int length, const String& name, NativeFunction, Intrinsic = NoIntrinsic, NativeFunction nativeConstructor = callHostFunctionAsConstructor);
@@ -66,6 +68,8 @@ namespace JSC {
return function;
}
+ static void destroy(JSCell*);
+
JS_EXPORT_PRIVATE String name(ExecState*);
JS_EXPORT_PRIVATE String displayName(ExecState*);
const String calculatedDisplayName(ExecState*);
@@ -129,6 +133,21 @@ namespace JSC {
return m_cachedInheritorID.get();
}
+ Structure* tryGetKnownInheritorID()
+ {
+ if (!m_cachedInheritorID)
+ return 0;
+ if (m_inheritorIDWatchpoint.hasBeenInvalidated())
+ return 0;
+ return m_cachedInheritorID.get();
+ }
+
+ void addInheritorIDWatchpoint(Watchpoint* watchpoint)
+ {
+ ASSERT(tryGetKnownInheritorID());
+ m_inheritorIDWatchpoint.add(watchpoint);
+ }
+
static size_t offsetOfCachedInheritorID()
{
return OBJECT_OFFSETOF(JSFunction, m_cachedInheritorID);
@@ -169,6 +188,7 @@ namespace JSC {
WriteBarrier<ExecutableBase> m_executable;
WriteBarrier<JSScope> m_scope;
WriteBarrier<Structure> m_cachedInheritorID;
+ InlineWatchpointSet m_inheritorIDWatchpoint;
};
inline bool JSValue::isFunction() const
diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/Source/JavaScriptCore/runtime/JSGlobalData.cpp
index 4dca5b0f6..74429c7a7 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalData.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalData.cpp
@@ -507,17 +507,17 @@ void JSGlobalData::dumpRegExpTrace()
RTTraceList::iterator iter = ++m_rtTraceList->begin();
if (iter != m_rtTraceList->end()) {
- dataLog("\nRegExp Tracing\n");
- dataLog(" match() matches\n");
- dataLog("Regular Expression JIT Address calls found\n");
- dataLog("----------------------------------------+----------------+----------+----------\n");
+ dataLogF("\nRegExp Tracing\n");
+ dataLogF(" match() matches\n");
+ dataLogF("Regular Expression JIT Address calls found\n");
+ dataLogF("----------------------------------------+----------------+----------+----------\n");
unsigned reCount = 0;
for (; iter != m_rtTraceList->end(); ++iter, ++reCount)
(*iter)->printTraceData();
- dataLog("%d Regular Expressions\n", reCount);
+ dataLogF("%d Regular Expressions\n", reCount);
}
m_rtTraceList->clear();
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
index c466a2b04..6f20f0e93 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())));
@@ -252,8 +259,6 @@ void JSGlobalObject::reset(JSValue prototype)
m_regExpPrototype.set(exec->globalData(), this, RegExpPrototype::create(exec, this, RegExpPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get()), emptyRegex));
m_regExpStructure.set(exec->globalData(), this, RegExpObject::createStructure(exec->globalData(), this, m_regExpPrototype.get()));
- m_methodCallDummy.set(exec->globalData(), this, constructEmptyObject(exec));
-
m_errorPrototype.set(exec->globalData(), this, ErrorPrototype::create(exec, this, ErrorPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get())));
m_errorStructure.set(exec->globalData(), this, ErrorInstance::createStructure(exec->globalData(), this, m_errorPrototype.get()));
@@ -360,7 +365,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 +419,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.
@@ -428,6 +435,14 @@ void JSGlobalObject::haveABadTime(JSGlobalData& globalData)
}
}
+bool JSGlobalObject::arrayPrototypeChainIsSane()
+{
+ return !hasIndexedProperties(m_arrayPrototype->structure()->indexingType())
+ && m_arrayPrototype->prototype() == m_objectPrototype.get()
+ && !hasIndexedProperties(m_objectPrototype->structure()->indexingType())
+ && m_objectPrototype->prototype().isNull();
+}
+
void JSGlobalObject::createThrowTypeError(ExecState* exec)
{
JSFunction* thrower = JSFunction::create(exec, this, 0, String(), globalFuncThrowTypeError);
@@ -457,7 +472,6 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
Base::visitChildren(thisObject, visitor);
visitor.append(&thisObject->m_globalThis);
- visitor.append(&thisObject->m_methodCallDummy);
visitor.append(&thisObject->m_regExpConstructor);
visitor.append(&thisObject->m_errorConstructor);
@@ -488,9 +502,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..e6edd0be7 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"
@@ -99,7 +100,6 @@ namespace JSC {
Register m_globalCallFrame[JSStack::CallFrameHeaderSize];
WriteBarrier<JSObject> m_globalThis;
- WriteBarrier<JSObject> m_methodCallDummy;
WriteBarrier<RegExpConstructor> m_regExpConstructor;
WriteBarrier<ErrorConstructor> m_errorConstructor;
@@ -130,9 +130,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;
@@ -268,21 +271,31 @@ namespace JSC {
RegExpPrototype* regExpPrototype() const { return m_regExpPrototype.get(); }
ErrorPrototype* errorPrototype() const { return m_errorPrototype.get(); }
- JSObject* methodCallDummy() const { return m_methodCallDummy.get(); }
-
Structure* withScopeStructure() const { return m_withScopeStructure.get(); }
Structure* strictEvalActivationStructure() const { return m_strictEvalActivationStructure.get(); }
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(); }
@@ -317,6 +330,8 @@ namespace JSC {
}
void haveABadTime(JSGlobalData&);
+
+ bool arrayPrototypeChainIsSane();
void setProfileGroup(unsigned value) { createRareDataIfNeeded(); m_rareData->profileGroup = value; }
unsigned profileGroup() const
@@ -450,22 +465,27 @@ namespace JSC {
return prototypeForLookup(exec->lexicalGlobalObject());
}
- inline StructureChain* Structure::prototypeChain(ExecState* exec) const
+ inline StructureChain* Structure::prototypeChain(JSGlobalData& globalData, JSGlobalObject* globalObject) const
{
// We cache our prototype chain so our clients can share it.
- if (!isValid(exec, m_cachedPrototypeChain.get())) {
- JSValue prototype = prototypeForLookup(exec);
- m_cachedPrototypeChain.set(exec->globalData(), this, StructureChain::create(exec->globalData(), prototype.isNull() ? 0 : asObject(prototype)->structure()));
+ if (!isValid(globalObject, m_cachedPrototypeChain.get())) {
+ JSValue prototype = prototypeForLookup(globalObject);
+ m_cachedPrototypeChain.set(globalData, this, StructureChain::create(globalData, prototype.isNull() ? 0 : asObject(prototype)->structure()));
}
return m_cachedPrototypeChain.get();
}
- inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const
+ inline StructureChain* Structure::prototypeChain(ExecState* exec) const
+ {
+ return prototypeChain(exec->globalData(), exec->lexicalGlobalObject());
+ }
+
+ inline bool Structure::isValid(JSGlobalObject* globalObject, StructureChain* cachedPrototypeChain) const
{
if (!cachedPrototypeChain)
return false;
- JSValue prototype = prototypeForLookup(exec);
+ JSValue prototype = prototypeForLookup(globalObject);
WriteBarrier<Structure>* cachedStructure = cachedPrototypeChain->head();
while(*cachedStructure && !prototype.isNull()) {
if (asObject(prototype)->structure() != cachedStructure->get())
@@ -476,6 +496,11 @@ namespace JSC {
return prototype.isNull() && !*cachedStructure;
}
+ inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const
+ {
+ return isValid(exec->lexicalGlobalObject(), cachedPrototypeChain);
+ }
+
inline JSGlobalObject* ExecState::dynamicGlobalObject()
{
if (this == lexicalGlobalObject()->globalExec())
@@ -497,34 +522,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/JSGlobalObjectFunctions.cpp b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
index 7ac76d350..1010ad2b7 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
@@ -52,7 +52,7 @@ namespace JSC {
static JSValue encode(ExecState* exec, const char* doNotEscape)
{
- CString cstr = exec->argument(0).toString(exec)->value(exec).utf8(true);
+ CString cstr = exec->argument(0).toString(exec)->value(exec).utf8(String::StrictConversion);
if (!cstr.data())
return throwError(exec, createURIError(exec, ASCIILiteral("String contained an illegal UTF-16 sequence.")));
diff --git a/Source/JavaScriptCore/runtime/JSLock.cpp b/Source/JavaScriptCore/runtime/JSLock.cpp
index 85dbdfedb..5e3d12c92 100644
--- a/Source/JavaScriptCore/runtime/JSLock.cpp
+++ b/Source/JavaScriptCore/runtime/JSLock.cpp
@@ -74,7 +74,9 @@ JSLockHolder::~JSLockHolder()
}
JSLock::JSLock()
- : m_lockCount(0)
+ : m_ownerThread(0)
+ , m_lockCount(0)
+ , m_lockDropDepth(0)
{
m_spinLock.Init();
}
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp
index 6a3fb84e4..564093e33 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())
@@ -332,26 +356,30 @@ void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSV
putByIndex(thisObject, exec, i, value, slot.isStrictMode());
return;
}
-
+
// Check if there are any setters or getters in the prototype chain
JSValue prototype;
if (propertyName != exec->propertyNames().underscoreProto) {
for (JSObject* obj = thisObject; !obj->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) {
prototype = obj->prototype();
if (prototype.isNull()) {
- if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getCallableObject(value)) && slot.isStrictMode())
+ ASSERT(!thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->globalData(), propertyName));
+ if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getCallableObject(value))
+ && slot.isStrictMode())
throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
return;
}
}
}
- for (JSObject* obj = thisObject; ; obj = asObject(prototype)) {
+ JSObject* obj;
+ for (obj = thisObject; ; obj = asObject(prototype)) {
unsigned attributes;
JSCell* specificValue;
PropertyOffset offset = obj->structure()->get(globalData, propertyName, attributes, specificValue);
if (isValidOffset(offset)) {
if (attributes & ReadOnly) {
+ ASSERT(thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->globalData(), propertyName) || obj == thisObject);
if (slot.isStrictMode())
throwError(exec, createTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError)));
return;
@@ -359,6 +387,8 @@ void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSV
JSValue gs = obj->getDirectOffset(offset);
if (gs.isGetterSetter()) {
+ ASSERT(attributes & Accessor);
+ ASSERT(thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->globalData(), propertyName) || obj == thisObject);
JSObject* setterFunc = asGetterSetter(gs)->setter();
if (!setterFunc) {
if (slot.isStrictMode())
@@ -374,7 +404,8 @@ void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSV
// If this is WebCore's global object then we need to substitute the shell.
call(exec, setterFunc, callType, callData, thisObject->methodTable()->toThisObject(thisObject, exec), args);
return;
- }
+ } else
+ ASSERT(!(attributes & Accessor));
// If there's an existing property on the object or one of its
// prototypes it should be replaced, so break here.
@@ -386,6 +417,7 @@ void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSV
break;
}
+ ASSERT(!thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->globalData(), propertyName) || obj == thisObject);
if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getCallableObject(value)) && slot.isStrictMode())
throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
return;
@@ -405,6 +437,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 +463,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 +578,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 +608,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 +618,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 +683,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 +728,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 +796,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 +885,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 +1043,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 +1050,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 +1074,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 +1098,7 @@ void JSObject::switchToSlowPutArrayStorage(JSGlobalData& globalData)
}
default:
- ASSERT_NOT_REACHED();
+ CRASH();
break;
}
}
@@ -877,8 +1265,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 +1277,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 +1456,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 +1471,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 +1872,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 +1886,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 +1896,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 +2025,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 +2172,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 +2254,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 +2356,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 +2403,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 +2418,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..4f7f4700b 100644
--- a/Source/JavaScriptCore/runtime/JSObject.h
+++ b/Source/JavaScriptCore/runtime/JSObject.h
@@ -39,6 +39,7 @@
#include "Structure.h"
#include "JSGlobalData.h"
#include "JSString.h"
+#include "SlotVisitorInlines.h"
#include "SparseArrayValueMap.h"
#include <wtf/StdLibExtras.h>
@@ -151,30 +152,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 +201,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 +225,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:
@@ -242,11 +242,21 @@ public:
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_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 +289,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 +311,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 +327,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 +342,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 +378,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 +428,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 +445,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 +645,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 +691,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 +751,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 +805,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 +847,7 @@ protected:
WriteBarrier<Unknown>* currentIndexingData()
{
switch (structure()->indexingType()) {
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return m_butterfly->contiguous();
@@ -732,10 +860,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 +903,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 +930,8 @@ private:
void isObject();
void isString();
+ Butterfly* createInitialIndexedStorage(JSGlobalData&, unsigned length, size_t elementSize);
+
ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(JSGlobalData&, ArrayStorage*);
template<PutMode>
@@ -800,11 +954,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;
@@ -1152,6 +1313,8 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, PropertyName p
// See comment on setNewProperty call below.
if (!specificFunction)
slot.setNewProperty(this, offset);
+ if (attributes & ReadOnly)
+ structure()->setContainsReadOnlyProperties();
return true;
}
@@ -1219,6 +1382,8 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, PropertyName p
// so leave the slot in an uncachable state.
if (!specificFunction)
slot.setNewProperty(this, offset);
+ if (attributes & ReadOnly)
+ structure->setContainsReadOnlyProperties();
return true;
}
diff --git a/Source/JavaScriptCore/runtime/JSValue.cpp b/Source/JavaScriptCore/runtime/JSValue.cpp
index e7f8cad17..d9253730f 100644
--- a/Source/JavaScriptCore/runtime/JSValue.cpp
+++ b/Source/JavaScriptCore/runtime/JSValue.cpp
@@ -214,10 +214,18 @@ char* JSValue::description() const
snprintf(description, size, "Double: %08x:%08x, %lf", u.asTwoInt32s[1], u.asTwoInt32s[0], asDouble());
#endif
} else if (isCell()) {
- snprintf(
- description, size, "Cell: %p (%p: %s, %s)",
- asCell(), asCell()->structure(), asCell()->structure()->classInfo()->className,
- indexingTypeToString(asCell()->structure()->indexingTypeIncludingHistory()));
+ if (asCell()->inherits(&Structure::s_info)) {
+ Structure* structure = jsCast<Structure*>(asCell());
+ snprintf(
+ description, size, "Structure: %p: %s, %s",
+ structure, structure->classInfo()->className,
+ indexingTypeToString(structure->indexingTypeIncludingHistory()));
+ } else {
+ snprintf(
+ 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");
else if (isFalse())
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..7301bf6ec 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 {
@@ -86,6 +86,7 @@ namespace JSC {
if (ropeBuilder.length() < oldLength) // True for overflow
return throwOutOfMemoryError(exec);
+ oldLength = ropeBuilder.length();
}
return ropeBuilder.release();
@@ -105,6 +106,7 @@ namespace JSC {
if (ropeBuilder.length() < oldLength) // True for overflow
return throwOutOfMemoryError(exec);
+ oldLength = ropeBuilder.length();
}
return ropeBuilder.release();
@@ -356,6 +358,23 @@ namespace JSC {
}
}
+ inline bool isPrototypeChainNormalized(JSGlobalObject* globalObject, Structure* structure)
+ {
+ for (;;) {
+ if (structure->typeInfo().type() == ProxyType)
+ return false;
+
+ JSValue v = structure->prototypeForLookup(globalObject);
+ if (v.isNull())
+ return true;
+
+ structure = v.asCell()->structure();
+
+ if (structure->isDictionary())
+ return false;
+ }
+ }
+
} // namespace JSC
#endif // Operations_h
diff --git a/Source/JavaScriptCore/runtime/Options.h b/Source/JavaScriptCore/runtime/Options.h
index d6d8c66c8..99a5f85a2 100644
--- a/Source/JavaScriptCore/runtime/Options.h
+++ b/Source/JavaScriptCore/runtime/Options.h
@@ -66,6 +66,8 @@ namespace JSC {
v(bool, useDFGJIT, true) \
v(bool, useRegExpJIT, true) \
\
+ v(bool, forceDFGCodeBlockLiveness, false) \
+ \
/* showDisassembly implies showDFGDisassembly. */ \
v(bool, showDisassembly, false) \
v(bool, showDFGDisassembly, false) \
diff --git a/Source/JavaScriptCore/runtime/RegExp.cpp b/Source/JavaScriptCore/runtime/RegExp.cpp
index 7757274f1..3229f5207 100644
--- a/Source/JavaScriptCore/runtime/RegExp.cpp
+++ b/Source/JavaScriptCore/runtime/RegExp.cpp
@@ -520,24 +520,24 @@ void RegExp::matchCompareWithInterpreter(const String& s, int startOffset, int*
differences++;
if (differences) {
- dataLog("RegExp Discrepency for /%s/\n string input ", pattern().utf8().data());
+ dataLogF("RegExp Discrepency for /%s/\n string input ", pattern().utf8().data());
unsigned segmentLen = s.length() - static_cast<unsigned>(startOffset);
- dataLog((segmentLen < 150) ? "\"%s\"\n" : "\"%148s...\"\n", s.utf8().data() + startOffset);
+ dataLogF((segmentLen < 150) ? "\"%s\"\n" : "\"%148s...\"\n", s.utf8().data() + startOffset);
if (jitResult != interpreterResult) {
- dataLog(" JIT result = %d, blah interpreted result = %d\n", jitResult, interpreterResult);
+ dataLogF(" JIT result = %d, blah interpreted result = %d\n", jitResult, interpreterResult);
differences--;
} else {
- dataLog(" Correct result = %d\n", jitResult);
+ dataLogF(" Correct result = %d\n", jitResult);
}
if (differences) {
for (unsigned j = 2, i = 0; i < m_numSubpatterns; j +=2, i++) {
if (offsetVector[j] != interpreterOffsetVector[j])
- dataLog(" JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j, offsetVector[j], j, interpreterOffsetVector[j]);
+ dataLogF(" JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j, offsetVector[j], j, interpreterOffsetVector[j]);
if ((offsetVector[j] >= 0) && (offsetVector[j+1] != interpreterOffsetVector[j+1]))
- dataLog(" JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j+1, offsetVector[j+1], j+1, interpreterOffsetVector[j+1]);
+ dataLogF(" JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j+1, offsetVector[j+1], j+1, interpreterOffsetVector[j+1]);
}
}
}
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/SamplingCounter.cpp b/Source/JavaScriptCore/runtime/SamplingCounter.cpp
index abed763ca..9826b88e4 100644
--- a/Source/JavaScriptCore/runtime/SamplingCounter.cpp
+++ b/Source/JavaScriptCore/runtime/SamplingCounter.cpp
@@ -35,10 +35,10 @@ void AbstractSamplingCounter::dump()
{
#if ENABLE(SAMPLING_COUNTERS)
if (s_abstractSamplingCounterChain != &s_abstractSamplingCounterChainEnd) {
- dataLog("\nSampling Counter Values:\n");
+ dataLogF("\nSampling Counter Values:\n");
for (AbstractSamplingCounter* currCounter = s_abstractSamplingCounterChain; (currCounter != &s_abstractSamplingCounterChainEnd); currCounter = currCounter->m_next)
- dataLog("\t%s\t: %lld\n", currCounter->m_name, currCounter->m_counter);
- dataLog("\n\n");
+ dataLogF("\t%s\t: %lld\n", currCounter->m_name, currCounter->m_counter);
+ dataLogF("\n\n");
}
s_completed = true;
#endif
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..9ffe3b060 100644
--- a/Source/JavaScriptCore/runtime/Structure.cpp
+++ b/Source/JavaScriptCore/runtime/Structure.cpp
@@ -135,17 +135,17 @@ void Structure::dumpStatistics()
}
}
- dataLog("Number of live Structures: %d\n", liveStructureSet.size());
- dataLog("Number of Structures using the single item optimization for transition map: %d\n", numberUsingSingleSlot);
- dataLog("Number of Structures that are leaf nodes: %d\n", numberLeaf);
- dataLog("Number of Structures that singletons: %d\n", numberSingletons);
- dataLog("Number of Structures with PropertyMaps: %d\n", numberWithPropertyMaps);
-
- dataLog("Size of a single Structures: %d\n", static_cast<unsigned>(sizeof(Structure)));
- dataLog("Size of sum of all property maps: %d\n", totalPropertyMapsSize);
- dataLog("Size of average of all property maps: %f\n", static_cast<double>(totalPropertyMapsSize) / static_cast<double>(liveStructureSet.size()));
+ dataLogF("Number of live Structures: %d\n", liveStructureSet.size());
+ dataLogF("Number of Structures using the single item optimization for transition map: %d\n", numberUsingSingleSlot);
+ dataLogF("Number of Structures that are leaf nodes: %d\n", numberLeaf);
+ dataLogF("Number of Structures that singletons: %d\n", numberSingletons);
+ dataLogF("Number of Structures with PropertyMaps: %d\n", numberWithPropertyMaps);
+
+ dataLogF("Size of a single Structures: %d\n", static_cast<unsigned>(sizeof(Structure)));
+ dataLogF("Size of sum of all property maps: %d\n", totalPropertyMapsSize);
+ dataLogF("Size of average of all property maps: %f\n", static_cast<double>(totalPropertyMapsSize) / static_cast<double>(liveStructureSet.size()));
#else
- dataLog("Dumping Structure statistics is not enabled.\n");
+ dataLogF("Dumping Structure statistics is not enabled.\n");
#endif
}
@@ -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;
+ }
}
}
@@ -694,11 +695,11 @@ static PropertyMapStatisticsExitLogger logger;
PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger()
{
- dataLog("\nJSC::PropertyMap statistics\n\n");
- dataLog("%d probes\n", numProbes);
- dataLog("%d collisions (%.1f%%)\n", numCollisions, 100.0 * numCollisions / numProbes);
- dataLog("%d rehashes\n", numRehashes);
- dataLog("%d removes\n", numRemoves);
+ dataLogF("\nJSC::PropertyMap statistics\n\n");
+ dataLogF("%d probes\n", numProbes);
+ dataLogF("%d collisions (%.1f%%)\n", numCollisions, 100.0 * numCollisions / numProbes);
+ dataLogF("%d rehashes\n", numRehashes);
+ dataLogF("%d removes\n", numRemoves);
}
#endif
@@ -861,6 +862,32 @@ void Structure::visitChildren(JSCell* cell, SlotVisitor& visitor)
visitor.append(&thisObject->m_objectToStringValue);
}
+bool Structure::prototypeChainMayInterceptStoreTo(JSGlobalData& globalData, PropertyName propertyName)
+{
+ unsigned i = propertyName.asIndex();
+ if (i != PropertyName::NotAnIndex)
+ return anyObjectInChainMayInterceptIndexedAccesses();
+
+ for (Structure* current = this; ;) {
+ JSValue prototype = current->storedPrototype();
+ if (prototype.isNull())
+ return false;
+
+ current = prototype.asCell()->structure();
+
+ unsigned attributes;
+ JSCell* specificValue;
+ PropertyOffset offset = current->get(globalData, propertyName, attributes, specificValue);
+ if (!JSC::isValidOffset(offset))
+ continue;
+
+ if (attributes & (ReadOnly | Accessor))
+ return true;
+
+ return false;
+ }
+}
+
#if DO_PROPERTYMAP_CONSTENCY_CHECK
void PropertyTable::checkConsistency()
diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h
index 2b25803a6..6e4402c52 100644
--- a/Source/JavaScriptCore/runtime/Structure.h
+++ b/Source/JavaScriptCore/runtime/Structure.h
@@ -166,9 +166,15 @@ namespace JSC {
JSValue prototypeForLookup(ExecState*) const;
JSValue prototypeForLookup(JSGlobalObject*) const;
JSValue prototypeForLookup(CodeBlock*) const;
+ StructureChain* prototypeChain(JSGlobalData&, JSGlobalObject*) const;
StructureChain* prototypeChain(ExecState*) const;
static void visitChildren(JSCell*, SlotVisitor&);
-
+
+ // Will just the prototype chain intercept this property access?
+ bool prototypeChainMayInterceptStoreTo(JSGlobalData&, PropertyName);
+
+ bool transitionDidInvolveSpecificValue() const { return !!m_specificValueInPrevious; }
+
Structure* previousID() const
{
ASSERT(structure()->classInfo() == &s_info);
@@ -397,6 +403,7 @@ namespace JSC {
return numberOfSlotsForLastOffset(m_offset, m_typeInfo.type());
}
+ bool isValid(JSGlobalObject*, StructureChain* cachedPrototypeChain) const;
bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
void pin();
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));