summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2012-09-18 15:53:33 +0200
committerSimon Hausmann <simon.hausmann@digia.com>2012-09-18 15:53:33 +0200
commit6bbb7fbbac94d0f511a7bd0cbd50854ab643bfb2 (patch)
treed9c68d1cca0b3e352f1e438561f3e504e641a08f /Source/JavaScriptCore/runtime
parentd0424a769059c84ae20beb3c217812792ea6726b (diff)
downloadqtwebkit-6bbb7fbbac94d0f511a7bd0cbd50854ab643bfb2.tar.gz
Imported WebKit commit c7503cef7ecb236730d1309676ab9fc723fd061d (http://svn.webkit.org/repository/webkit/trunk@128886)
New snapshot with various build fixes
Diffstat (limited to 'Source/JavaScriptCore/runtime')
-rw-r--r--Source/JavaScriptCore/runtime/Arguments.cpp209
-rw-r--r--Source/JavaScriptCore/runtime/Arguments.h164
-rw-r--r--Source/JavaScriptCore/runtime/ArrayPrototype.cpp6
-rw-r--r--Source/JavaScriptCore/runtime/Executable.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/FunctionConstructor.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/IndexingType.h59
-rw-r--r--Source/JavaScriptCore/runtime/InitializeThreading.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/JSActivation.h20
-rw-r--r--Source/JavaScriptCore/runtime/JSArray.cpp25
-rw-r--r--Source/JavaScriptCore/runtime/JSArray.h4
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalData.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.cpp94
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.h23
-rw-r--r--Source/JavaScriptCore/runtime/JSLock.cpp107
-rw-r--r--Source/JavaScriptCore/runtime/JSLock.h17
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.cpp270
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.h111
-rw-r--r--Source/JavaScriptCore/runtime/JSValue.cpp23
-rw-r--r--Source/JavaScriptCore/runtime/JSValue.h3
-rw-r--r--Source/JavaScriptCore/runtime/ObjectPrototype.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp177
-rw-r--r--Source/JavaScriptCore/runtime/SparseArrayValueMap.h3
-rw-r--r--Source/JavaScriptCore/runtime/SparseArrayValueMapInlineMethods.h203
-rw-r--r--Source/JavaScriptCore/runtime/Structure.cpp24
-rw-r--r--Source/JavaScriptCore/runtime/Structure.h11
-rw-r--r--Source/JavaScriptCore/runtime/StructureTransitionTable.h12
-rw-r--r--Source/JavaScriptCore/runtime/SymbolTable.h25
28 files changed, 974 insertions, 625 deletions
diff --git a/Source/JavaScriptCore/runtime/Arguments.cpp b/Source/JavaScriptCore/runtime/Arguments.cpp
index 47795edb2..e5e503ee1 100644
--- a/Source/JavaScriptCore/runtime/Arguments.cpp
+++ b/Source/JavaScriptCore/runtime/Arguments.cpp
@@ -45,10 +45,10 @@ void Arguments::visitChildren(JSCell* cell, SlotVisitor& visitor)
ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
JSObject::visitChildren(thisObject, visitor);
- if (thisObject->d->registerArray)
- visitor.appendValues(thisObject->d->registerArray.get(), thisObject->d->numArguments);
- visitor.append(&thisObject->d->callee);
- visitor.append(&thisObject->d->activation);
+ if (thisObject->m_registerArray)
+ visitor.appendValues(thisObject->m_registerArray.get(), thisObject->m_numArguments);
+ visitor.append(&thisObject->m_callee);
+ visitor.append(&thisObject->m_activation);
}
void Arguments::destroy(JSCell* cell)
@@ -58,7 +58,7 @@ void Arguments::destroy(JSCell* cell)
void Arguments::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t length)
{
- if (UNLIKELY(d->overrodeLength)) {
+ if (UNLIKELY(m_overrodeLength)) {
length = min(get(exec, exec->propertyNames().length).toUInt32(exec), length);
for (unsigned i = 0; i < length; i++)
callFrame->setArgument(i, get(exec, i));
@@ -66,8 +66,8 @@ void Arguments::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t
}
ASSERT(length == this->length(exec));
for (size_t i = 0; i < length; ++i) {
- if (!d->deletedArguments || !d->deletedArguments[i])
- callFrame->setArgument(i, argument(i).get());
+ if (JSValue value = tryGetArgument(i))
+ callFrame->setArgument(i, value);
else
callFrame->setArgument(i, get(exec, i));
}
@@ -75,7 +75,7 @@ void Arguments::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t
void Arguments::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
{
- if (UNLIKELY(d->overrodeLength)) {
+ if (UNLIKELY(m_overrodeLength)) {
unsigned length = get(exec, exec->propertyNames().length).toUInt32(exec);
for (unsigned i = 0; i < length; i++)
args.append(get(exec, i));
@@ -83,8 +83,8 @@ void Arguments::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
}
uint32_t length = this->length(exec);
for (size_t i = 0; i < length; ++i) {
- if (!d->deletedArguments || !d->deletedArguments[i])
- args.append(argument(i).get());
+ if (JSValue value = tryGetArgument(i))
+ args.append(value);
else
args.append(get(exec, i));
}
@@ -93,8 +93,8 @@ void Arguments::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
bool Arguments::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned i, PropertySlot& slot)
{
Arguments* thisObject = jsCast<Arguments*>(cell);
- if (i < thisObject->d->numArguments && (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])) {
- slot.setValue(thisObject->argument(i).get());
+ if (JSValue value = thisObject->tryGetArgument(i)) {
+ slot.setValue(value);
return true;
}
@@ -103,10 +103,10 @@ bool Arguments::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigne
void Arguments::createStrictModeCallerIfNecessary(ExecState* exec)
{
- if (d->overrodeCaller)
+ if (m_overrodeCaller)
return;
- d->overrodeCaller = true;
+ m_overrodeCaller = true;
PropertyDescriptor descriptor;
descriptor.setAccessorDescriptor(globalObject()->throwTypeErrorGetterSetter(exec), DontEnum | DontDelete | Accessor);
methodTable()->defineOwnProperty(this, exec, exec->propertyNames().caller, descriptor, false);
@@ -114,10 +114,10 @@ void Arguments::createStrictModeCallerIfNecessary(ExecState* exec)
void Arguments::createStrictModeCalleeIfNecessary(ExecState* exec)
{
- if (d->overrodeCallee)
+ if (m_overrodeCallee)
return;
- d->overrodeCallee = true;
+ m_overrodeCallee = true;
PropertyDescriptor descriptor;
descriptor.setAccessorDescriptor(globalObject()->throwTypeErrorGetterSetter(exec), DontEnum | DontDelete | Accessor);
methodTable()->defineOwnProperty(this, exec, exec->propertyNames().callee, descriptor, false);
@@ -127,26 +127,26 @@ bool Arguments::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName p
{
Arguments* thisObject = jsCast<Arguments*>(cell);
unsigned i = propertyName.asIndex();
- if (i < thisObject->d->numArguments && (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])) {
+ if (JSValue value = thisObject->tryGetArgument(i)) {
ASSERT(i < PropertyName::NotAnIndex);
- slot.setValue(thisObject->argument(i).get());
+ slot.setValue(value);
return true;
}
- if (propertyName == exec->propertyNames().length && LIKELY(!thisObject->d->overrodeLength)) {
- slot.setValue(jsNumber(thisObject->d->numArguments));
+ if (propertyName == exec->propertyNames().length && LIKELY(!thisObject->m_overrodeLength)) {
+ slot.setValue(jsNumber(thisObject->m_numArguments));
return true;
}
- if (propertyName == exec->propertyNames().callee && LIKELY(!thisObject->d->overrodeCallee)) {
- if (!thisObject->d->isStrictMode) {
- slot.setValue(thisObject->d->callee.get());
+ if (propertyName == exec->propertyNames().callee && LIKELY(!thisObject->m_overrodeCallee)) {
+ if (!thisObject->m_isStrictMode) {
+ slot.setValue(thisObject->m_callee.get());
return true;
}
thisObject->createStrictModeCalleeIfNecessary(exec);
}
- if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
+ if (propertyName == exec->propertyNames().caller && thisObject->m_isStrictMode)
thisObject->createStrictModeCallerIfNecessary(exec);
return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
@@ -156,26 +156,26 @@ bool Arguments::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Prop
{
Arguments* thisObject = jsCast<Arguments*>(object);
unsigned i = propertyName.asIndex();
- if (i < thisObject->d->numArguments && (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])) {
+ if (JSValue value = thisObject->tryGetArgument(i)) {
ASSERT(i < PropertyName::NotAnIndex);
- descriptor.setDescriptor(thisObject->argument(i).get(), None);
+ descriptor.setDescriptor(value, None);
return true;
}
- if (propertyName == exec->propertyNames().length && LIKELY(!thisObject->d->overrodeLength)) {
- descriptor.setDescriptor(jsNumber(thisObject->d->numArguments), DontEnum);
+ if (propertyName == exec->propertyNames().length && LIKELY(!thisObject->m_overrodeLength)) {
+ descriptor.setDescriptor(jsNumber(thisObject->m_numArguments), DontEnum);
return true;
}
- if (propertyName == exec->propertyNames().callee && LIKELY(!thisObject->d->overrodeCallee)) {
- if (!thisObject->d->isStrictMode) {
- descriptor.setDescriptor(thisObject->d->callee.get(), DontEnum);
+ if (propertyName == exec->propertyNames().callee && LIKELY(!thisObject->m_overrodeCallee)) {
+ if (!thisObject->m_isStrictMode) {
+ descriptor.setDescriptor(thisObject->m_callee.get(), DontEnum);
return true;
}
thisObject->createStrictModeCalleeIfNecessary(exec);
}
- if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
+ if (propertyName == exec->propertyNames().caller && thisObject->m_isStrictMode)
thisObject->createStrictModeCallerIfNecessary(exec);
return JSObject::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
@@ -184,9 +184,10 @@ bool Arguments::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Prop
void Arguments::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
Arguments* thisObject = jsCast<Arguments*>(object);
- for (unsigned i = 0; i < thisObject->d->numArguments; ++i) {
- if (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])
- propertyNames.add(Identifier(exec, String::number(i)));
+ for (unsigned i = 0; i < thisObject->m_numArguments; ++i) {
+ if (!thisObject->isArgument(i))
+ continue;
+ propertyNames.add(Identifier(exec, String::number(i)));
}
if (mode == IncludeDontEnumProperties) {
propertyNames.add(exec->propertyNames().callee);
@@ -198,10 +199,8 @@ void Arguments::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyN
void Arguments::putByIndex(JSCell* cell, ExecState* exec, unsigned i, JSValue value, bool shouldThrow)
{
Arguments* thisObject = jsCast<Arguments*>(cell);
- if (i < static_cast<unsigned>(thisObject->d->numArguments) && (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])) {
- thisObject->argument(i).set(exec->globalData(), thisObject, value);
+ if (thisObject->trySetArgument(exec->globalData(), i, value))
return;
- }
PutPropertySlot slot(shouldThrow);
JSObject::put(thisObject, exec, Identifier(exec, String::number(i)), value, slot);
@@ -211,28 +210,25 @@ void Arguments::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JS
{
Arguments* thisObject = jsCast<Arguments*>(cell);
unsigned i = propertyName.asIndex();
- if (i < thisObject->d->numArguments && (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])) {
- ASSERT(i < PropertyName::NotAnIndex);
- thisObject->argument(i).set(exec->globalData(), thisObject, value);
+ if (thisObject->trySetArgument(exec->globalData(), i, value))
return;
- }
- if (propertyName == exec->propertyNames().length && !thisObject->d->overrodeLength) {
- thisObject->d->overrodeLength = true;
+ if (propertyName == exec->propertyNames().length && !thisObject->m_overrodeLength) {
+ thisObject->m_overrodeLength = true;
thisObject->putDirect(exec->globalData(), propertyName, value, DontEnum);
return;
}
- if (propertyName == exec->propertyNames().callee && !thisObject->d->overrodeCallee) {
- if (!thisObject->d->isStrictMode) {
- thisObject->d->overrodeCallee = true;
+ if (propertyName == exec->propertyNames().callee && !thisObject->m_overrodeCallee) {
+ if (!thisObject->m_isStrictMode) {
+ thisObject->m_overrodeCallee = true;
thisObject->putDirect(exec->globalData(), propertyName, value, DontEnum);
return;
}
thisObject->createStrictModeCalleeIfNecessary(exec);
}
- if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
+ if (propertyName == exec->propertyNames().caller && thisObject->m_isStrictMode)
thisObject->createStrictModeCallerIfNecessary(exec);
JSObject::put(thisObject, exec, propertyName, value, slot);
@@ -241,20 +237,12 @@ void Arguments::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JS
bool Arguments::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
{
Arguments* thisObject = jsCast<Arguments*>(cell);
- if (i < thisObject->d->numArguments) {
+ if (i < thisObject->m_numArguments) {
if (!Base::deletePropertyByIndex(cell, exec, i))
return false;
-
- if (!thisObject->d->deletedArguments) {
- thisObject->d->deletedArguments = adoptArrayPtr(new bool[thisObject->d->numArguments]);
- memset(thisObject->d->deletedArguments.get(), 0, sizeof(bool) * thisObject->d->numArguments);
- }
- if (!thisObject->d->deletedArguments[i]) {
- thisObject->d->deletedArguments[i] = true;
+ if (thisObject->tryDeleteArgument(i))
return true;
- }
}
-
return JSObject::deletePropertyByIndex(thisObject, exec, i);
}
@@ -265,35 +253,28 @@ bool Arguments::deleteProperty(JSCell* cell, ExecState* exec, PropertyName prope
Arguments* thisObject = jsCast<Arguments*>(cell);
unsigned i = propertyName.asIndex();
- if (i < thisObject->d->numArguments) {
+ if (i < thisObject->m_numArguments) {
ASSERT(i < PropertyName::NotAnIndex);
if (!Base::deleteProperty(cell, exec, propertyName))
return false;
-
- if (!thisObject->d->deletedArguments) {
- thisObject->d->deletedArguments = adoptArrayPtr(new bool[thisObject->d->numArguments]);
- memset(thisObject->d->deletedArguments.get(), 0, sizeof(bool) * thisObject->d->numArguments);
- }
- if (!thisObject->d->deletedArguments[i]) {
- thisObject->d->deletedArguments[i] = true;
+ if (thisObject->tryDeleteArgument(i))
return true;
- }
}
- if (propertyName == exec->propertyNames().length && !thisObject->d->overrodeLength) {
- thisObject->d->overrodeLength = true;
+ if (propertyName == exec->propertyNames().length && !thisObject->m_overrodeLength) {
+ thisObject->m_overrodeLength = true;
return true;
}
- if (propertyName == exec->propertyNames().callee && !thisObject->d->overrodeCallee) {
- if (!thisObject->d->isStrictMode) {
- thisObject->d->overrodeCallee = true;
+ if (propertyName == exec->propertyNames().callee && !thisObject->m_overrodeCallee) {
+ if (!thisObject->m_isStrictMode) {
+ thisObject->m_overrodeCallee = true;
return true;
}
thisObject->createStrictModeCalleeIfNecessary(exec);
}
- if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
+ if (propertyName == exec->propertyNames().caller && thisObject->m_isStrictMode)
thisObject->createStrictModeCallerIfNecessary(exec);
return JSObject::deleteProperty(thisObject, exec, propertyName);
@@ -303,47 +284,46 @@ bool Arguments::defineOwnProperty(JSObject* object, ExecState* exec, PropertyNam
{
Arguments* thisObject = jsCast<Arguments*>(object);
unsigned i = propertyName.asIndex();
- if (i < thisObject->d->numArguments) {
+ if (i < thisObject->m_numArguments) {
ASSERT(i < PropertyName::NotAnIndex);
// If the property is not yet present on the object, and is not yet marked as deleted, then add it now.
PropertySlot slot;
- if ((!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i]) && !JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot))
- object->putDirectMayBeIndex(exec, propertyName, thisObject->argument(i).get());
+ if (!thisObject->isDeletedArgument(i) && !JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot)) {
+ JSValue value = thisObject->tryGetArgument(i);
+ ASSERT(value);
+ object->putDirectMayBeIndex(exec, propertyName, value);
+ }
if (!Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow))
return false;
- if (!thisObject->d->deletedArguments) {
- thisObject->d->deletedArguments = adoptArrayPtr(new bool[thisObject->d->numArguments]);
- memset(thisObject->d->deletedArguments.get(), 0, sizeof(bool) * thisObject->d->numArguments);
- }
// From ES 5.1, 10.6 Arguments Object
// 5. If the value of isMapped is not undefined, then
- if (!thisObject->d->deletedArguments[i]) {
+ if (thisObject->isArgument(i)) {
// a. If IsAccessorDescriptor(Desc) is true, then
if (descriptor.isAccessorDescriptor()) {
// i. Call the [[Delete]] internal method of map passing P, and false as the arguments.
- thisObject->d->deletedArguments[i] = true;
+ thisObject->tryDeleteArgument(i);
} else { // b. Else
// i. If Desc.[[Value]] is present, then
// 1. Call the [[Put]] internal method of map passing P, Desc.[[Value]], and Throw as the arguments.
if (descriptor.value())
- thisObject->argument(i).set(exec->globalData(), thisObject, descriptor.value());
+ thisObject->trySetArgument(exec->globalData(), i, descriptor.value());
// ii. If Desc.[[Writable]] is present and its value is false, then
// 1. Call the [[Delete]] internal method of map passing P and false as arguments.
if (descriptor.writablePresent() && !descriptor.writable())
- thisObject->d->deletedArguments[i] = true;
+ thisObject->tryDeleteArgument(i);
}
}
return true;
}
- if (propertyName == exec->propertyNames().length && !thisObject->d->overrodeLength) {
- thisObject->putDirect(exec->globalData(), propertyName, jsNumber(thisObject->d->numArguments), DontEnum);
- thisObject->d->overrodeLength = true;
- } else if (propertyName == exec->propertyNames().callee && !thisObject->d->overrodeCallee) {
- thisObject->putDirect(exec->globalData(), propertyName, thisObject->d->callee.get(), DontEnum);
- thisObject->d->overrodeCallee = true;
- } else if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
+ if (propertyName == exec->propertyNames().length && !thisObject->m_overrodeLength) {
+ thisObject->putDirect(exec->globalData(), propertyName, jsNumber(thisObject->m_numArguments), DontEnum);
+ thisObject->m_overrodeLength = true;
+ } else if (propertyName == exec->propertyNames().callee && !thisObject->m_overrodeCallee) {
+ thisObject->putDirect(exec->globalData(), propertyName, thisObject->m_callee.get(), DontEnum);
+ thisObject->m_overrodeCallee = true;
+ } else if (propertyName == exec->propertyNames().caller && thisObject->m_isStrictMode)
thisObject->createStrictModeCallerIfNecessary(exec);
return Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow);
@@ -354,18 +334,18 @@ void Arguments::tearOff(CallFrame* callFrame)
if (isTornOff())
return;
- if (!d->numArguments)
+ if (!m_numArguments)
return;
// Must be called for the same call frame from which it was created.
- ASSERT(bitwise_cast<WriteBarrier<Unknown>*>(callFrame) == d->registers);
+ ASSERT(bitwise_cast<WriteBarrier<Unknown>*>(callFrame) == m_registers);
- d->registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[d->numArguments]);
- d->registers = d->registerArray.get() + CallFrame::offsetFor(d->numArguments + 1);
+ m_registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[m_numArguments]);
+ m_registers = m_registerArray.get() + CallFrame::offsetFor(m_numArguments + 1);
if (!callFrame->isInlineCallFrame()) {
- for (size_t i = 0; i < d->numArguments; ++i)
- argument(i).set(callFrame->globalData(), this, callFrame->argument(i));
+ for (size_t i = 0; i < m_numArguments; ++i)
+ trySetArgument(callFrame->globalData(), i, callFrame->argumentAfterCapture(i));
return;
}
@@ -373,16 +353,41 @@ void Arguments::tearOff(CallFrame* callFrame)
callFrame->globalData(), callFrame->registers(), callFrame->inlineCallFrame());
}
+void Arguments::didTearOffActivation(ExecState* exec, JSActivation* activation)
+{
+ ASSERT(activation);
+ if (isTornOff())
+ return;
+
+ if (!m_numArguments)
+ return;
+
+ tearOff(exec);
+
+ SharedSymbolTable* symbolTable = activation->symbolTable();
+ const SlowArgument* slowArguments = symbolTable->slowArguments();
+ if (!slowArguments)
+ return;
+
+ ASSERT(symbolTable->captureMode() == SharedSymbolTable::AllOfTheThings);
+ m_activation.set(exec->globalData(), this, activation);
+
+ allocateSlowArguments();
+ size_t count = min<unsigned>(m_numArguments, symbolTable->parameterCount());
+ for (size_t i = 0; i < count; ++i)
+ m_slowArguments[i] = slowArguments[i];
+}
+
void Arguments::tearOff(CallFrame* callFrame, InlineCallFrame* inlineCallFrame)
{
if (isTornOff())
return;
- if (!d->numArguments)
+ if (!m_numArguments)
return;
- d->registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[d->numArguments]);
- d->registers = d->registerArray.get() + CallFrame::offsetFor(d->numArguments + 1);
+ m_registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[m_numArguments]);
+ m_registers = m_registerArray.get() + CallFrame::offsetFor(m_numArguments + 1);
tearOffForInlineCallFrame(
callFrame->globalData(), callFrame->registers() + inlineCallFrame->stackOffset,
@@ -391,7 +396,7 @@ void Arguments::tearOff(CallFrame* callFrame, InlineCallFrame* inlineCallFrame)
void Arguments::tearOffForInlineCallFrame(JSGlobalData& globalData, Register* registers, InlineCallFrame* inlineCallFrame)
{
- for (size_t i = 0; i < d->numArguments; ++i) {
+ for (size_t i = 0; i < m_numArguments; ++i) {
ValueRecovery& recovery = inlineCallFrame->arguments[i + 1];
// In the future we'll support displaced recoveries (indicating that the
// argument was flushed to a different location), but for now we don't do
@@ -427,7 +432,7 @@ void Arguments::tearOffForInlineCallFrame(JSGlobalData& globalData, Register* re
ASSERT_NOT_REACHED();
break;
}
- argument(i).set(globalData, this, value);
+ trySetArgument(globalData, i, value);
}
}
diff --git a/Source/JavaScriptCore/runtime/Arguments.h b/Source/JavaScriptCore/runtime/Arguments.h
index c3d25f962..ad0e651ea 100644
--- a/Source/JavaScriptCore/runtime/Arguments.h
+++ b/Source/JavaScriptCore/runtime/Arguments.h
@@ -33,31 +33,9 @@
namespace JSC {
- struct ArgumentsData {
- WTF_MAKE_NONCOPYABLE(ArgumentsData); WTF_MAKE_FAST_ALLOCATED;
- public:
- ArgumentsData() { }
- WriteBarrier<JSActivation> activation;
-
- unsigned 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 overrodeLength;
- bool overrodeCallee;
- bool overrodeCaller;
- bool isStrictMode;
-
- WriteBarrierBase<Unknown>* registers;
- OwnArrayPtr<WriteBarrier<Unknown> > registerArray;
-
- OwnArrayPtr<bool> deletedArguments;
-
- WriteBarrier<JSFunction> callee;
- };
-
class Arguments : public JSNonFinalObject {
+ friend class JIT;
+ friend class DFG::SpeculativeJIT;
public:
typedef JSNonFinalObject Base;
@@ -94,30 +72,22 @@ namespace JSC {
uint32_t length(ExecState* exec) const
{
- if (UNLIKELY(d->overrodeLength))
+ if (UNLIKELY(m_overrodeLength))
return get(exec, exec->propertyNames().length).toUInt32(exec);
- return d->numArguments;
+ return m_numArguments;
}
void copyToArguments(ExecState*, CallFrame*, uint32_t length);
void tearOff(CallFrame*);
void tearOff(CallFrame*, InlineCallFrame*);
- bool isTornOff() const { return d->registerArray; }
- void didTearOffActivation(JSGlobalData& globalData, JSActivation* activation)
- {
- if (isTornOff())
- return;
- d->activation.set(globalData, this, activation);
- d->registers = &activation->registerAt(0);
- }
+ 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);
}
- static ptrdiff_t offsetOfData() { return OBJECT_OFFSETOF(Arguments, d); }
-
protected:
static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
@@ -138,11 +108,34 @@ namespace JSC {
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*);
- OwnPtr<ArgumentsData> d;
+ 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);
@@ -155,19 +148,76 @@ namespace JSC {
inline Arguments::Arguments(CallFrame* callFrame)
: JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
- , d(adoptPtr(new ArgumentsData))
{
}
inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
: JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
- , d(adoptPtr(new ArgumentsData))
{
}
- inline WriteBarrierBase<Unknown>& Arguments::argument(size_t i)
+ inline void Arguments::allocateSlowArguments()
+ {
+ if (m_slowArguments)
+ return;
+ m_slowArguments = adoptArrayPtr(new SlowArgument[m_numArguments]);
+ }
+
+ inline bool Arguments::tryDeleteArgument(size_t argument)
{
- return d->registers[CallFrame::argumentOffset(i)];
+ 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 || m_slowArguments[argument].status == SlowArgument::Normal)
+ return m_registers[CallFrame::argumentOffset(argument)];
+
+ ASSERT(m_slowArguments[argument].status == SlowArgument::Captured);
+ if (!m_activation)
+ return m_registers[m_slowArguments[argument].indexIfCaptured];
+
+ return m_activation->registerAt(m_slowArguments[argument].indexIfCaptured);
}
inline void Arguments::finishCreation(CallFrame* callFrame)
@@ -176,17 +226,17 @@ namespace JSC {
ASSERT(inherits(&s_info));
JSFunction* callee = jsCast<JSFunction*>(callFrame->callee());
- d->numArguments = callFrame->argumentCount();
- d->registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers());
- d->callee.set(callFrame->globalData(), this, callee);
- d->overrodeLength = false;
- d->overrodeCallee = false;
- d->overrodeCaller = false;
- d->isStrictMode = callFrame->codeBlock()->isStrictMode();
+ 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();
// The bytecode generator omits op_tear_off_activation in cases of no
// declared parameters, so we need to tear off immediately.
- if (d->isStrictMode || !callee->jsExecutable()->parameterCount())
+ if (m_isStrictMode || !callee->jsExecutable()->parameterCount())
tearOff(callFrame);
}
@@ -196,17 +246,17 @@ namespace JSC {
ASSERT(inherits(&s_info));
JSFunction* callee = inlineCallFrame->callee.get();
- d->numArguments = inlineCallFrame->arguments.size() - 1;
- d->registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers()) + inlineCallFrame->stackOffset;
- d->callee.set(callFrame->globalData(), this, callee);
- d->overrodeLength = false;
- d->overrodeCallee = false;
- d->overrodeCaller = false;
- d->isStrictMode = jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->isStrictMode();
+ 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();
// The bytecode generator omits op_tear_off_activation in cases of no
// declared parameters, so we need to tear off immediately.
- if (d->isStrictMode || !callee->jsExecutable()->parameterCount())
+ if (m_isStrictMode || !callee->jsExecutable()->parameterCount())
tearOff(callFrame, inlineCallFrame);
}
diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp
index 503aecda8..c70e40d77 100644
--- a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp
@@ -132,8 +132,10 @@ ArrayPrototype::ArrayPrototype(JSGlobalObject* globalObject, Structure* structur
void ArrayPrototype::finishCreation(JSGlobalObject* globalObject)
{
- Base::finishCreation(globalObject->globalData());
+ JSGlobalData& globalData = globalObject->globalData();
+ Base::finishCreation(globalData);
ASSERT(inherits(&s_info));
+ notifyUsedAsPrototype(globalData);
}
bool ArrayPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
@@ -638,7 +640,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec)
CallData callData;
CallType callType = getCallData(function, callData);
- if (thisObj->classInfo() == &JSArray::s_info && !asArray(thisObj)->inSparseIndexingMode()) {
+ if (thisObj->classInfo() == &JSArray::s_info && !asArray(thisObj)->inSparseIndexingMode() && !shouldUseSlowPut(thisObj->structure()->indexingType())) {
if (isNumericCompareFunction(exec, callType, callData))
asArray(thisObj)->sortNumeric(exec, function, callType, callData);
else if (callType != CallTypeNone)
diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp
index b11220bea..2791c65d4 100644
--- a/Source/JavaScriptCore/runtime/Executable.cpp
+++ b/Source/JavaScriptCore/runtime/Executable.cpp
@@ -202,7 +202,7 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, JSScope* scope, JITCo
m_evalCodeBlock = newCodeBlock.release();
} else {
if (!lexicalGlobalObject->evalEnabled())
- return throwError(exec, createEvalError(exec, ASCIILiteral("Eval is disabled")));
+ return throwError(exec, createEvalError(exec, lexicalGlobalObject->evalDisabledErrorMessage()));
RefPtr<EvalNode> evalNode = parse<EvalNode>(globalData, lexicalGlobalObject, m_source, 0, Identifier(), isStrictMode() ? JSParseStrict : JSParseNormal, EvalNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
if (!evalNode) {
ASSERT(exception);
diff --git a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp
index 40507dae1..570444e3c 100644
--- a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp
@@ -82,7 +82,7 @@ CallType FunctionConstructor::getCallData(JSCell*, CallData& callData)
JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, const Identifier& functionName, const String& sourceURL, const TextPosition& position)
{
if (!globalObject->evalEnabled())
- return throwError(exec, createEvalError(exec, ASCIILiteral("Function constructor is disabled")));
+ return throwError(exec, createEvalError(exec, globalObject->evalDisabledErrorMessage()));
return constructFunctionSkippingEvalEnabledCheck(exec, globalObject, args, functionName, sourceURL, position);
}
diff --git a/Source/JavaScriptCore/runtime/IndexingType.h b/Source/JavaScriptCore/runtime/IndexingType.h
index cd8d71dfe..3b97230ea 100644
--- a/Source/JavaScriptCore/runtime/IndexingType.h
+++ b/Source/JavaScriptCore/runtime/IndexingType.h
@@ -33,28 +33,65 @@ typedef uint8_t IndexingType;
// Flags for testing the presence of capabilities.
static const IndexingType IsArray = 1;
static const IndexingType HasArrayStorage = 8;
+static const IndexingType HasSlowPutArrayStorage = 16;
// Additional flags for tracking the history of the type. These are usually
// masked off unless you ask for them directly.
-static const IndexingType HadArrayStorage = 16; // Means that this object did have array storage in the past.
+static const IndexingType HadArrayStorage = 32; // Means that this object did have array storage in the past.
+static const IndexingType MayHaveIndexedAccessors = 64;
// List of acceptable array types.
-static const IndexingType NonArray = 0;
-static const IndexingType NonArrayWithArrayStorage = HasArrayStorage;
-static const IndexingType ArrayClass = IsArray; // I'd want to call this "Array" but this would lead to disastrous namespace pollution.
-static const IndexingType ArrayWithArrayStorage = IsArray | HasArrayStorage;
+static const IndexingType NonArray = 0;
+static const IndexingType NonArrayWithArrayStorage = HasArrayStorage;
+static const IndexingType NonArrayWithSlowPutArrayStorage = HasSlowPutArrayStorage;
+static const IndexingType ArrayClass = IsArray; // I'd want to call this "Array" but this would lead to disastrous namespace pollution.
+static const IndexingType ArrayWithArrayStorage = IsArray | HasArrayStorage;
+static const IndexingType ArrayWithSlowPutArrayStorage = IsArray | HasSlowPutArrayStorage;
-// Mask of all possible types.
-static const IndexingType AllArrayTypes = 15;
+#define ALL_BLANK_INDEXING_TYPES \
+ NonArray: \
+ case ArrayClass
-// Mask of all possible types including the history.
-static const IndexingType AllArrayTypesAndHistory = 31;
+#define ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES \
+ ArrayWithArrayStorage: \
+ case ArrayWithSlowPutArrayStorage
+
+#define ALL_ARRAY_STORAGE_INDEXING_TYPES \
+ NonArrayWithArrayStorage: \
+ case NonArrayWithSlowPutArrayStorage: \
+ case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES
+
+static inline bool hasIndexedProperties(IndexingType indexingType)
+{
+ switch (indexingType) {
+ case ALL_BLANK_INDEXING_TYPES:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static inline bool hasIndexingHeader(IndexingType type)
+{
+ return hasIndexedProperties(type);
+}
-inline bool hasIndexingHeader(IndexingType type)
+static inline bool hasArrayStorage(IndexingType indexingType)
{
- return !!(type & HasArrayStorage);
+ return !!(indexingType & (HasArrayStorage | HasSlowPutArrayStorage));
}
+static inline bool shouldUseSlowPut(IndexingType indexingType)
+{
+ return !!(indexingType & HasSlowPutArrayStorage);
+}
+
+// Mask of all possible types.
+static const IndexingType AllArrayTypes = 31;
+
+// Mask of all possible types including the history.
+static const IndexingType AllArrayTypesAndHistory = 127;
+
} // namespace JSC
#endif // IndexingType_h
diff --git a/Source/JavaScriptCore/runtime/InitializeThreading.cpp b/Source/JavaScriptCore/runtime/InitializeThreading.cpp
index 6e7eddbf1..1a7239f60 100644
--- a/Source/JavaScriptCore/runtime/InitializeThreading.cpp
+++ b/Source/JavaScriptCore/runtime/InitializeThreading.cpp
@@ -35,6 +35,7 @@
#include "Identifier.h"
#include "JSDateMath.h"
#include "JSGlobalObject.h"
+#include "JSLock.h"
#include "LLIntData.h"
#include "WriteBarrier.h"
#include <wtf/dtoa.h>
@@ -53,6 +54,7 @@ static void initializeThreadingOnce()
{
WTF::double_conversion::initialize();
WTF::initializeThreading();
+ GlobalJSLock::initialize();
Options::initialize();
#if ENABLE(WRITE_BARRIER_PROFILING)
WriteBarrierCounters::initialize();
diff --git a/Source/JavaScriptCore/runtime/JSActivation.h b/Source/JavaScriptCore/runtime/JSActivation.h
index df59c3d94..8211e7710 100644
--- a/Source/JavaScriptCore/runtime/JSActivation.h
+++ b/Source/JavaScriptCore/runtime/JSActivation.h
@@ -48,7 +48,7 @@ namespace JSC {
static JSActivation* create(JSGlobalData& globalData, CallFrame* callFrame, FunctionExecutable* functionExecutable)
{
- size_t storageSize = JSActivation::storageSize(callFrame, functionExecutable->symbolTable());
+ size_t storageSize = JSActivation::storageSize(functionExecutable->symbolTable());
JSActivation* activation = new (
NotNull,
allocateCell<JSActivation>(
@@ -98,8 +98,8 @@ namespace JSC {
NEVER_INLINE PropertySlot::GetValueFunc getArgumentsGetter();
static size_t allocationSize(size_t storageSize);
- static size_t storageSize(CallFrame*, SharedSymbolTable*);
- static int captureStart(CallFrame*, SharedSymbolTable*);
+ static size_t storageSize(SharedSymbolTable*);
+ static int captureStart(SharedSymbolTable*);
int registerOffset();
size_t storageSize();
@@ -142,26 +142,26 @@ namespace JSC {
return false;
}
- inline int JSActivation::captureStart(CallFrame* callFrame, SharedSymbolTable* symbolTable)
+ inline int JSActivation::captureStart(SharedSymbolTable* symbolTable)
{
if (symbolTable->captureMode() == SharedSymbolTable::AllOfTheThings)
- return -CallFrame::offsetFor(std::max<size_t>(callFrame->argumentCountIncludingThis(), symbolTable->parameterCountIncludingThis()));
+ return -CallFrame::offsetFor(symbolTable->parameterCountIncludingThis());
return symbolTable->captureStart();
}
- inline size_t JSActivation::storageSize(CallFrame* callFrame, SharedSymbolTable* symbolTable)
+ inline size_t JSActivation::storageSize(SharedSymbolTable* symbolTable)
{
- return symbolTable->captureEnd() - captureStart(callFrame, symbolTable);
+ return symbolTable->captureEnd() - captureStart(symbolTable);
}
inline int JSActivation::registerOffset()
{
- return -captureStart(CallFrame::create(reinterpret_cast<Register*>(m_registers)), symbolTable());
+ return -captureStart(symbolTable());
}
inline size_t JSActivation::storageSize()
{
- return storageSize(CallFrame::create(reinterpret_cast<Register*>(m_registers)), symbolTable());
+ return storageSize(symbolTable());
}
inline void JSActivation::tearOff(JSGlobalData& globalData)
@@ -216,7 +216,7 @@ namespace JSC {
inline bool JSActivation::isValid(const SymbolTableEntry& entry)
{
- if (entry.getIndex() < captureStart(CallFrame::create(reinterpret_cast<Register*>(m_registers)), symbolTable()))
+ if (entry.getIndex() < captureStart(symbolTable()))
return false;
if (entry.getIndex() >= symbolTable()->captureEnd())
return false;
diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp
index 241049dce..ebbbd41aa 100644
--- a/Source/JavaScriptCore/runtime/JSArray.cpp
+++ b/Source/JavaScriptCore/runtime/JSArray.cpp
@@ -34,7 +34,6 @@
#include "IndexingHeaderInlineMethods.h"
#include "PropertyNameArray.h"
#include "Reject.h"
-#include "SparseArrayValueMapInlineMethods.h"
#include <wtf/AVLTree.h>
#include <wtf/Assertions.h>
#include <wtf/OwnPtr.h>
@@ -405,7 +404,7 @@ JSValue JSArray::pop(ExecState* exec)
case ArrayClass:
return jsUndefined();
- case ArrayWithArrayStorage: {
+ case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = m_butterfly->arrayStorage();
unsigned length = storage->length();
@@ -465,6 +464,16 @@ void JSArray::push(ExecState* exec, JSValue value)
break;
}
+ case ArrayWithSlowPutArrayStorage: {
+ unsigned oldLength = length();
+ if (attemptToInterceptPutByIndexOnHole(exec, oldLength, value, true)) {
+ if (!exec->hadException() && oldLength < 0xFFFFFFFFu)
+ setLength(exec, oldLength + 1, true);
+ return;
+ }
+ // Fall through.
+ }
+
case ArrayWithArrayStorage: {
ArrayStorage* storage = m_butterfly->arrayStorage();
@@ -478,8 +487,8 @@ void JSArray::push(ExecState* exec, JSValue value)
return;
}
- // Pushing to an array of length 2^32-1 stores the property, but throws a range error.
- if (UNLIKELY(storage->length() == 0xFFFFFFFFu)) {
+ // Pushing to an array of invalid length (2^31-1) stores the property, but throws a range error.
+ if (storage->length() > MAX_ARRAY_INDEX) {
methodTable()->putByIndex(this, exec, storage->length(), value, true);
// Per ES5.1 15.4.4.7 step 6 & 15.4.5.1 step 3.d.
if (!exec->hadException())
@@ -549,7 +558,9 @@ bool JSArray::unshiftCount(ExecState* exec, unsigned count)
storage = m_butterfly->arrayStorage();
storage->m_indexBias -= count;
storage->setVectorLength(storage->vectorLength() + count);
- } else if (!unshiftCountSlowCase(exec->globalData(), count)) {
+ } else if (unshiftCountSlowCase(exec->globalData(), count))
+ storage = arrayStorage();
+ else {
throwOutOfMemoryError(exec);
return true;
}
@@ -916,7 +927,7 @@ void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
case ArrayClass:
return;
- case ArrayWithArrayStorage: {
+ case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = m_butterfly->arrayStorage();
WriteBarrier<Unknown>* vector = storage->m_vector;
@@ -946,7 +957,7 @@ void JSArray::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t le
case ArrayClass:
return;
- case ArrayWithArrayStorage: {
+ case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = m_butterfly->arrayStorage();
unsigned i = 0;
WriteBarrier<Unknown>* vector = storage->m_vector;
diff --git a/Source/JavaScriptCore/runtime/JSArray.h b/Source/JavaScriptCore/runtime/JSArray.h
index d382f64a9..c46e67863 100644
--- a/Source/JavaScriptCore/runtime/JSArray.h
+++ b/Source/JavaScriptCore/runtime/JSArray.h
@@ -78,9 +78,9 @@ namespace JSC {
void fillArgList(ExecState*, MarkedArgumentBuffer&);
void copyToArguments(ExecState*, CallFrame*, uint32_t length);
- static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, IndexingType indexingType)
{
- return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info, ArrayWithArrayStorage);
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info, indexingType);
}
protected:
diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/Source/JavaScriptCore/runtime/JSGlobalData.cpp
index e409c8219..26f2b8616 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalData.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalData.cpp
@@ -55,7 +55,6 @@
#include "ParserArena.h"
#include "RegExpCache.h"
#include "RegExpObject.h"
-#include "SparseArrayValueMapInlineMethods.h"
#include "StrictEvalActivation.h"
#include "StrongInlines.h"
#include <wtf/RetainPtr.h>
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
index 8ee8e1498..a6993aabc 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
@@ -111,6 +111,7 @@ static const int preferredScriptCheckTimeInterval = 1000;
JSGlobalObject::JSGlobalObject(JSGlobalData& globalData, Structure* structure, const GlobalObjectMethodTable* globalObjectMethodTable)
: Base(globalData, structure, 0)
, m_masqueradesAsUndefinedWatchpoint(adoptRef(new WatchpointSet(InitializedWatching)))
+ , m_havingABadTimeWatchpoint(adoptRef(new WatchpointSet(InitializedWatching)))
, m_weakRandom(Options::forceWeakRandomSeed() ? Options::forcedWeakRandomSeed() : static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
, m_evalEnabled(true)
, m_globalObjectMethodTable(globalObjectMethodTable ? globalObjectMethodTable : &s_globalObjectMethodTable)
@@ -230,7 +231,8 @@ void JSGlobalObject::reset(JSValue prototype)
m_callbackObjectStructure.set(exec->globalData(), this, JSCallbackObject<JSNonFinalObject>::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()));
+ m_arrayStructure.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_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())));
@@ -329,6 +331,96 @@ void JSGlobalObject::reset(JSValue prototype)
resetPrototype(exec->globalData(), prototype);
}
+// Private namespace for helpers for JSGlobalObject::haveABadTime()
+namespace {
+
+class ObjectsWithBrokenIndexingFinder : public MarkedBlock::VoidFunctor {
+public:
+ ObjectsWithBrokenIndexingFinder(MarkedArgumentBuffer&, JSGlobalObject*);
+ void operator()(JSCell*);
+
+private:
+ MarkedArgumentBuffer& m_foundObjects;
+ JSGlobalObject* m_globalObject;
+};
+
+ObjectsWithBrokenIndexingFinder::ObjectsWithBrokenIndexingFinder(
+ MarkedArgumentBuffer& foundObjects, JSGlobalObject* globalObject)
+ : m_foundObjects(foundObjects)
+ , m_globalObject(globalObject)
+{
+}
+
+inline bool hasBrokenIndexing(JSObject* object)
+{
+ // This will change if we have more indexing types.
+ return !!(object->structure()->indexingType() & HasArrayStorage);
+}
+
+void ObjectsWithBrokenIndexingFinder::operator()(JSCell* cell)
+{
+ if (!cell->isObject())
+ return;
+
+ JSObject* object = asObject(cell);
+
+ // Run this filter first, since it's cheap, and ought to filter out a lot of objects.
+ if (!hasBrokenIndexing(object))
+ return;
+
+ // We only want to have a bad time in the affected global object, not in the entire
+ // VM. But we have to be careful, since there may be objects that claim to belong to
+ // a different global object that have prototypes from our global object.
+ bool foundGlobalObject = false;
+ for (JSObject* current = object; ;) {
+ if (current->unwrappedGlobalObject() == m_globalObject) {
+ foundGlobalObject = true;
+ break;
+ }
+
+ JSValue prototypeValue = current->prototype();
+ if (prototypeValue.isNull())
+ break;
+ current = asObject(prototypeValue);
+ }
+ if (!foundGlobalObject)
+ return;
+
+ m_foundObjects.append(object);
+}
+
+} // end private namespace for helpers for JSGlobalObject::haveABadTime()
+
+void JSGlobalObject::haveABadTime(JSGlobalData& globalData)
+{
+ ASSERT(&globalData == &this->globalData());
+
+ if (isHavingABadTime())
+ return;
+
+ // Make sure that all allocations or indexed storage transitions that are inlining
+ // the assumption that it's safe to transition to a non-SlowPut array storage don't
+ // do so anymore.
+ m_havingABadTimeWatchpoint->notifyWrite();
+ ASSERT(isHavingABadTime()); // The watchpoint is what tells us that we're having a bad time.
+
+ // 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());
+
+ // Make sure that all objects that have indexed storage switch to the slow kind of
+ // indexed storage.
+ MarkedArgumentBuffer foundObjects; // Use MarkedArgumentBuffer because switchToSlowPutArrayStorage() may GC.
+ ObjectsWithBrokenIndexingFinder finder(foundObjects, this);
+ globalData.heap.objectSpace().forEachLiveCell(finder);
+ while (!foundObjects.isEmpty()) {
+ JSObject* object = asObject(foundObjects.last());
+ foundObjects.removeLast();
+ ASSERT(hasBrokenIndexing(object));
+ object->switchToSlowPutArrayStorage(globalData);
+ }
+}
+
void JSGlobalObject::createThrowTypeError(ExecState* exec)
{
JSFunction* thrower = JSFunction::create(exec, this, 0, String(), globalFuncThrowTypeError);
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h
index 406a65b51..ad56783cc 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.h
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h
@@ -126,7 +126,8 @@ namespace JSC {
WriteBarrier<Structure> m_activationStructure;
WriteBarrier<Structure> m_nameScopeStructure;
WriteBarrier<Structure> m_argumentsStructure;
- WriteBarrier<Structure> m_arrayStructure;
+ WriteBarrier<Structure> m_arrayStructure; // This gets set to m_arrayStructureForSlowPut as soon as we decide to have a bad time.
+ WriteBarrier<Structure> m_arrayStructureForSlowPut;
WriteBarrier<Structure> m_booleanObjectStructure;
WriteBarrier<Structure> m_callbackConstructorStructure;
WriteBarrier<Structure> m_callbackFunctionStructure;
@@ -149,12 +150,14 @@ namespace JSC {
Debugger* m_debugger;
RefPtr<WatchpointSet> m_masqueradesAsUndefinedWatchpoint;
+ RefPtr<WatchpointSet> m_havingABadTimeWatchpoint;
OwnPtr<JSGlobalObjectRareData> m_rareData;
WeakRandom m_weakRandom;
bool m_evalEnabled;
+ String m_evalDisabledErrorMessage;
bool m_experimentsEnabled;
static JS_EXPORTDATA const GlobalObjectMethodTable s_globalObjectMethodTable;
@@ -259,6 +262,7 @@ namespace JSC {
Structure* nameScopeStructure() const { return m_nameScopeStructure.get(); }
Structure* argumentsStructure() const { return m_argumentsStructure.get(); }
Structure* arrayStructure() const { return m_arrayStructure.get(); }
+ void* addressOfArrayStructure() { return &m_arrayStructure; }
Structure* booleanObjectStructure() const { return m_booleanObjectStructure.get(); }
Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); }
Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); }
@@ -279,6 +283,14 @@ namespace JSC {
Structure* stringObjectStructure() const { return m_stringObjectStructure.get(); }
WatchpointSet* masqueradesAsUndefinedWatchpoint() { return m_masqueradesAsUndefinedWatchpoint.get(); }
+ WatchpointSet* havingABadTimeWatchpoint() { return m_havingABadTimeWatchpoint.get(); }
+
+ bool isHavingABadTime() const
+ {
+ return m_havingABadTimeWatchpoint->hasBeenInvalidated();
+ }
+
+ void haveABadTime(JSGlobalData&);
void setProfileGroup(unsigned value) { createRareDataIfNeeded(); m_rareData->profileGroup = value; }
unsigned profileGroup() const
@@ -304,8 +316,13 @@ namespace JSC {
bool isDynamicScope(bool& requiresDynamicChecks) const;
- void setEvalEnabled(bool enabled) { m_evalEnabled = enabled; }
- bool evalEnabled() { return m_evalEnabled; }
+ bool evalEnabled() const { return m_evalEnabled; }
+ const String& evalDisabledErrorMessage() const { return m_evalDisabledErrorMessage; }
+ void setEvalEnabled(bool enabled, const String& errorMessage = String())
+ {
+ m_evalEnabled = enabled;
+ m_evalDisabledErrorMessage = errorMessage;
+ }
void resetPrototype(JSGlobalData&, JSValue prototype);
diff --git a/Source/JavaScriptCore/runtime/JSLock.cpp b/Source/JavaScriptCore/runtime/JSLock.cpp
index c57c9cdc5..9f02b69b8 100644
--- a/Source/JavaScriptCore/runtime/JSLock.cpp
+++ b/Source/JavaScriptCore/runtime/JSLock.cpp
@@ -33,21 +33,21 @@
namespace JSC {
-// JSLock is only needed to support an obsolete execution model where JavaScriptCore
-// automatically protected against concurrent access from multiple threads.
-// So it's safe to disable it on non-mac platforms where we don't have native pthreads.
-#if (OS(DARWIN) || USE(PTHREADS))
-
-static pthread_mutex_t sharedInstanceLock = PTHREAD_MUTEX_INITIALIZER;
+Mutex* GlobalJSLock::s_sharedInstanceLock = 0;
GlobalJSLock::GlobalJSLock()
{
- pthread_mutex_lock(&sharedInstanceLock);
+ s_sharedInstanceLock->lock();
}
GlobalJSLock::~GlobalJSLock()
{
- pthread_mutex_unlock(&sharedInstanceLock);
+ s_sharedInstanceLock->unlock();
+}
+
+void GlobalJSLock::initialize()
+{
+ s_sharedInstanceLock = new Mutex();
}
JSLockHolder::JSLockHolder(ExecState* exec)
@@ -216,95 +216,4 @@ JSLock::DropAllLocks::~DropAllLocks()
m_globalData->apiLock().grabAllLocks(m_lockCount);
}
-#else // (OS(DARWIN) || USE(PTHREADS))
-
-GlobalJSLock::GlobalJSLock()
-{
-}
-
-GlobalJSLock::~GlobalJSLock()
-{
-}
-
-JSLockHolder::JSLockHolder(JSGlobalData*)
-{
-}
-
-JSLockHolder::JSLockHolder(JSGlobalData&)
-{
-}
-
-JSLockHolder::JSLockHolder(ExecState*)
-{
-}
-
-JSLockHolder::~JSLockHolder()
-{
-}
-
-JSLock::JSLock()
-{
-}
-
-JSLock::~JSLock()
-{
-}
-
-bool JSLock::currentThreadIsHoldingLock()
-{
- return true;
-}
-
-void JSLock::lock()
-{
-}
-
-void JSLock::unlock()
-{
-}
-
-void JSLock::lock(ExecState*)
-{
-}
-
-void JSLock::unlock(ExecState*)
-{
-}
-
-void JSLock::lock(JSGlobalData&)
-{
-}
-
-void JSLock::unlock(JSGlobalData&)
-{
-}
-
-unsigned JSLock::dropAllLocks()
-{
- return 0;
-}
-
-unsigned JSLock::dropAllLocksUnconditionally()
-{
- return 0;
-}
-
-void JSLock::grabAllLocks(unsigned)
-{
-}
-
-JSLock::DropAllLocks::DropAllLocks(ExecState*)
-{
-}
-
-JSLock::DropAllLocks::DropAllLocks(JSGlobalData*)
-{
-}
-
-JSLock::DropAllLocks::~DropAllLocks()
-{
-}
-
-#endif // (OS(DARWIN) || USE(PTHREADS))
-
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSLock.h b/Source/JavaScriptCore/runtime/JSLock.h
index 94108d013..4c42dc0ae 100644
--- a/Source/JavaScriptCore/runtime/JSLock.h
+++ b/Source/JavaScriptCore/runtime/JSLock.h
@@ -58,6 +58,10 @@ namespace JSC {
public:
JS_EXPORT_PRIVATE GlobalJSLock();
JS_EXPORT_PRIVATE ~GlobalJSLock();
+
+ static void initialize();
+ private:
+ static Mutex* s_sharedInstanceLock;
};
class JSLockHolder {
@@ -91,12 +95,6 @@ namespace JSC {
unsigned dropAllLocksUnconditionally();
void grabAllLocks(unsigned lockCount);
- SpinLock m_spinLock;
- Mutex m_lock;
- ThreadIdentifier m_ownerThread;
- intptr_t m_lockCount;
- unsigned m_lockDropDepth;
-
class DropAllLocks {
WTF_MAKE_NONCOPYABLE(DropAllLocks);
public:
@@ -108,6 +106,13 @@ namespace JSC {
intptr_t m_lockCount;
RefPtr<JSGlobalData> m_globalData;
};
+
+ private:
+ SpinLock m_spinLock;
+ Mutex m_lock;
+ ThreadIdentifier m_ownerThread;
+ intptr_t m_lockCount;
+ unsigned m_lockDropDepth;
};
} // namespace
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp
index 6eac0d1cb..229d1aea6 100644
--- a/Source/JavaScriptCore/runtime/JSObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSObject.cpp
@@ -42,7 +42,6 @@
#include "PropertyNameArray.h"
#include "Reject.h"
#include "SlotVisitorInlineMethods.h"
-#include "SparseArrayValueMapInlineMethods.h"
#include <math.h>
#include <wtf/Assertions.h>
@@ -50,7 +49,8 @@ namespace JSC {
// We keep track of the size of the last array after it was grown. We use this
// as a simple heuristic for as the value to grow the next array from size 0.
-// This value is capped by the constant FIRST_VECTOR_GROW defined above.
+// This value is capped by the constant FIRST_VECTOR_GROW defined in
+// ArrayConventions.h.
static unsigned lastArraySize = 0;
JSCell* getCallableObjectSlow(JSCell* cell)
@@ -133,8 +133,7 @@ ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* but
// Mark and copy the array if appropriate.
switch (structure->indexingType()) {
- case ArrayWithArrayStorage:
- case NonArrayWithArrayStorage: {
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
newButterfly->arrayStorage()->copyHeaderFromDuringGC(*butterfly->arrayStorage());
WriteBarrier<Unknown>* currentTarget = newButterfly->arrayStorage()->m_vector;
WriteBarrier<Unknown>* currentSource = butterfly->arrayStorage()->m_vector;
@@ -160,8 +159,7 @@ ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* but
// Mark the array if appropriate.
switch (structure->indexingType()) {
- case ArrayWithArrayStorage:
- case NonArrayWithArrayStorage:
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
visitor.appendValues(butterfly->arrayStorage()->m_vector, butterfly->arrayStorage()->vectorLength());
if (butterfly->arrayStorage()->m_sparseMap)
visitor.append(&butterfly->arrayStorage()->m_sparseMap);
@@ -234,12 +232,10 @@ bool JSObject::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned
return thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, Identifier::from(exec, i), slot);
switch (thisObject->structure()->indexingType()) {
- case NonArray:
- case ArrayClass:
+ case ALL_BLANK_INDEXING_TYPES:
break;
- case NonArrayWithArrayStorage:
- case ArrayWithArrayStorage: {
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
if (i >= storage->length())
return false;
@@ -301,7 +297,7 @@ void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSV
unsigned attributes;
JSCell* specificValue;
PropertyOffset offset = obj->structure()->get(globalData, propertyName, attributes, specificValue);
- if (offset != invalidOffset) {
+ if (isValidOffset(offset)) {
if (attributes & ReadOnly) {
if (slot.isStrictMode())
throwError(exec, createTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError)));
@@ -347,15 +343,14 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName,
JSObject* thisObject = jsCast<JSObject*>(cell);
thisObject->checkIndexingConsistency();
- if (UNLIKELY(propertyName > MAX_ARRAY_INDEX)) {
+ if (propertyName > MAX_ARRAY_INDEX) {
PutPropertySlot slot(shouldThrow);
thisObject->methodTable()->put(thisObject, exec, Identifier::from(exec, propertyName), value, slot);
return;
}
switch (thisObject->structure()->indexingType()) {
- case NonArray:
- case ArrayClass:
+ case ALL_BLANK_INDEXING_TYPES:
break;
case NonArrayWithArrayStorage:
@@ -381,6 +376,34 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName,
return;
}
+ case NonArrayWithSlowPutArrayStorage:
+ case ArrayWithSlowPutArrayStorage: {
+ ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
+
+ if (propertyName >= storage->vectorLength())
+ break;
+
+ WriteBarrier<Unknown>& valueSlot = storage->m_vector[propertyName];
+ unsigned length = storage->length();
+
+ // Update length & m_numValuesInVector as necessary.
+ if (propertyName >= length) {
+ if (thisObject->attemptToInterceptPutByIndexOnHole(exec, propertyName, value, shouldThrow))
+ return;
+ length = propertyName + 1;
+ storage->setLength(length);
+ ++storage->m_numValuesInVector;
+ } else if (!valueSlot) {
+ if (thisObject->attemptToInterceptPutByIndexOnHole(exec, propertyName, value, shouldThrow))
+ return;
+ ++storage->m_numValuesInVector;
+ }
+
+ valueSlot.set(exec->globalData(), thisObject, value);
+ thisObject->checkIndexingConsistency();
+ return;
+ }
+
default:
ASSERT_NOT_REACHED();
}
@@ -425,8 +448,7 @@ ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists
void JSObject::enterDictionaryIndexingMode(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
- case ArrayWithArrayStorage:
- case NonArrayWithArrayStorage:
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage());
break;
@@ -435,10 +457,23 @@ void JSObject::enterDictionaryIndexingMode(JSGlobalData& globalData)
}
}
+void JSObject::notifyPresenceOfIndexedAccessors(JSGlobalData& globalData)
+{
+ if (mayInterceptIndexedAccesses())
+ return;
+
+ setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AddIndexedAccessors));
+
+ if (!mayBeUsedAsPrototype(globalData))
+ return;
+
+ globalObject()->haveABadTime(globalData);
+}
+
ArrayStorage* JSObject::createArrayStorage(JSGlobalData& globalData, unsigned length, unsigned vectorLength)
{
IndexingType oldType = structure()->indexingType();
- ASSERT_UNUSED(oldType, oldType == NonArray || oldType == ArrayClass);
+ ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
Butterfly* newButterfly = m_butterfly->growArrayRight(
globalData, structure(), structure()->outOfLineCapacity(), false, 0,
ArrayStorage::sizeFor(vectorLength));
@@ -454,7 +489,7 @@ ArrayStorage* JSObject::createArrayStorage(JSGlobalData& globalData, unsigned le
result->m_initializationIndex = 0;
result->m_inCompactInitialization = 0;
#endif
- Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateArrayStorage);
+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), structure()->suggestedIndexingTransition());
setButterfly(globalData, newButterfly, newStructure);
return result;
}
@@ -467,12 +502,10 @@ ArrayStorage* JSObject::createInitialArrayStorage(JSGlobalData& globalData)
ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
- case ArrayWithArrayStorage:
- case NonArrayWithArrayStorage:
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage());
- case ArrayClass:
- case NonArray: {
+ case ALL_BLANK_INDEXING_TYPES: {
createArrayStorage(globalData, 0, 0);
SparseArrayValueMap* map = allocateSparseIndexMap(globalData);
map->setSparseMode();
@@ -485,6 +518,22 @@ ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(J
}
}
+void JSObject::switchToSlowPutArrayStorage(JSGlobalData& globalData)
+{
+ switch (structure()->indexingType()) {
+ case NonArrayWithArrayStorage:
+ case ArrayWithArrayStorage: {
+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), SwitchToSlowPutArrayStorage);
+ setStructure(globalData, newStructure);
+ break;
+ }
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+}
+
void JSObject::putDirectVirtual(JSObject* object, ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes)
{
ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
@@ -492,6 +541,33 @@ void JSObject::putDirectVirtual(JSObject* object, ExecState* exec, PropertyName
object->putDirectInternal<PutModeDefineOwnProperty>(exec->globalData(), propertyName, value, attributes, slot, getCallableObject(value));
}
+void JSObject::setPrototype(JSGlobalData& globalData, JSValue prototype)
+{
+ ASSERT(prototype);
+ if (prototype.isObject())
+ asObject(prototype)->notifyUsedAsPrototype(globalData);
+
+ Structure* newStructure = Structure::changePrototypeTransition(globalData, structure(), prototype);
+ setStructure(globalData, newStructure);
+
+ if (!newStructure->anyObjectInChainMayInterceptIndexedAccesses())
+ return;
+
+ if (mayBeUsedAsPrototype(globalData)) {
+ newStructure->globalObject()->haveABadTime(globalData);
+ return;
+ }
+
+ if (!hasIndexingHeader(structure()->indexingType()))
+ return;
+
+ if (shouldUseSlowPut(structure()->indexingType()))
+ return;
+
+ newStructure = Structure::nonPropertyTransition(globalData, newStructure, SwitchToSlowPutArrayStorage);
+ setStructure(globalData, newStructure);
+}
+
bool JSObject::setPrototypeWithCycleCheck(JSGlobalData& globalData, JSValue prototype)
{
JSValue checkFor = this;
@@ -508,9 +584,32 @@ bool JSObject::setPrototypeWithCycleCheck(JSGlobalData& globalData, JSValue prot
return true;
}
+void JSObject::resetInheritorID(JSGlobalData& globalData)
+{
+ PropertyOffset offset = structure()->get(globalData, globalData.m_inheritorIDKey);
+ if (!isValidOffset(offset))
+ return;
+
+ putDirectOffset(globalData, offset, jsUndefined());
+}
+
+Structure* JSObject::inheritorID(JSGlobalData& globalData)
+{
+ if (WriteBarrierBase<Unknown>* location = getDirectLocation(globalData, globalData.m_inheritorIDKey)) {
+ JSValue value = location->get();
+ if (value.isCell()) {
+ Structure* inheritorID = jsCast<Structure*>(value);
+ ASSERT(inheritorID->isEmpty());
+ return inheritorID;
+ }
+ ASSERT(value.isUndefined());
+ }
+ return createInheritorID(globalData);
+}
+
bool JSObject::allowsAccessFrom(ExecState* exec)
{
- JSGlobalObject* globalObject = isGlobalThis() ? jsCast<JSGlobalThis*>(this)->unwrappedObject() : this->globalObject();
+ JSGlobalObject* globalObject = unwrappedGlobalObject();
return globalObject->globalObjectMethodTable()->allowsAccessFrom(globalObject, exec);
}
@@ -597,12 +696,10 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
return thisObject->methodTable()->deleteProperty(thisObject, exec, Identifier::from(exec, i));
switch (thisObject->structure()->indexingType()) {
- case ArrayClass:
- case NonArray:
+ case ALL_BLANK_INDEXING_TYPES:
return true;
- case ArrayWithArrayStorage:
- case NonArrayWithArrayStorage: {
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
if (i < storage->vectorLength()) {
@@ -762,12 +859,10 @@ void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNa
// is incredibly inefficient for large arrays. We need a different approach,
// which almost certainly means a different structure for PropertyNameArray.
switch (object->structure()->indexingType()) {
- case NonArray:
- case ArrayClass:
+ case ALL_BLANK_INDEXING_TYPES:
break;
- case NonArrayWithArrayStorage:
- case ArrayWithArrayStorage: {
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = object->m_butterfly->arrayStorage();
unsigned usedVectorLength = std::min(storage->length(), storage->vectorLength());
@@ -857,6 +952,13 @@ void JSObject::preventExtensions(JSGlobalData& globalData)
setStructure(globalData, Structure::preventExtensionsTransition(globalData, structure()));
}
+JSGlobalObject* JSObject::unwrappedGlobalObject()
+{
+ if (isGlobalThis())
+ return jsCast<JSGlobalThis*>(this)->unwrappedObject();
+ return structure()->globalObject();
+}
+
// This presently will flatten to an uncachable dictionary; this is suitable
// for use in delete, we may want to do something different elsewhere.
void JSObject::reifyStaticFunctionsForDelete(ExecState* exec)
@@ -920,18 +1022,35 @@ NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, PropertyO
slot.setUndefined();
}
-Structure* JSObject::createInheritorID(JSGlobalData& globalData)
+void JSObject::notifyUsedAsPrototype(JSGlobalData& globalData)
{
- ASSERT(!getDirectLocation(globalData, globalData.m_inheritorIDKey));
-
- JSGlobalObject* globalObject;
- if (isGlobalThis())
- globalObject = static_cast<JSGlobalThis*>(this)->unwrappedObject();
- else
- globalObject = structure()->globalObject();
- ASSERT(globalObject);
+ PropertyOffset offset = structure()->get(globalData, globalData.m_inheritorIDKey);
+ if (isValidOffset(offset))
+ return;
+
+ PutPropertySlot slot;
+ putDirectInternal<PutModeDefineOwnProperty>(globalData, globalData.m_inheritorIDKey, jsUndefined(), DontEnum, slot, 0);
+
+ // Note that this method makes the somewhat odd decision to not check if this
+ // object currently has indexed accessors. We could do that check here, and if
+ // indexed accessors were found, we could tell the global object to have a bad
+ // time. But we avoid this, to allow the following to be always fast:
+ //
+ // 1) Create an object.
+ // 2) Give it a setter or read-only property that happens to have a numeric name.
+ // 3) Allocate objects that use this object as a prototype.
+ //
+ // This avoids anyone having a bad time. Even if the instance objects end up
+ // having indexed storage, the creation of indexed storage leads to a prototype
+ // chain walk that detects the presence of indexed setters and then does the
+ // right thing. As a result, having a bad time only happens if you add an
+ // indexed setter (or getter, or read-only field) to an object that is already
+ // used as a prototype.
+}
- Structure* inheritorID = createEmptyObjectStructure(globalData, globalObject, this);
+Structure* JSObject::createInheritorID(JSGlobalData& globalData)
+{
+ Structure* inheritorID = createEmptyObjectStructure(globalData, unwrappedGlobalObject(), this);
ASSERT(inheritorID->isEmpty());
PutPropertySlot slot;
@@ -980,7 +1099,10 @@ void JSObject::putIndexedDescriptor(ExecState* exec, SparseArrayEntry* entryInMa
// Defined in ES5.1 8.12.9
bool JSObject::defineOwnIndexedProperty(ExecState* exec, unsigned index, PropertyDescriptor& descriptor, bool throwException)
{
- ASSERT(index != 0xFFFFFFFF);
+ ASSERT(index <= MAX_ARRAY_INDEX);
+
+ if (descriptor.attributes() & (ReadOnly | Accessor))
+ notifyPresenceOfIndexedAccessors(exec->globalData());
if (!inSparseIndexingMode()) {
// Fast case: we're putting a regular property to a regular array
@@ -1109,6 +1231,40 @@ void JSObject::deallocateSparseIndexMap()
arrayStorage->m_sparseMap.clear();
}
+bool JSObject::attemptToInterceptPutByIndexOnHoleForPrototype(ExecState* exec, JSValue thisValue, unsigned i, JSValue value, bool shouldThrow)
+{
+ for (JSObject* current = this; ;) {
+ // This has the same behavior with respect to prototypes as JSObject::put(). It only
+ // allows a prototype to intercept a put if (a) the prototype declares the property
+ // we're after rather than intercepting it via an override of JSObject::put(), and
+ // (b) that property is declared as ReadOnly or Accessor.
+
+ ArrayStorage* storage = current->arrayStorageOrNull();
+ if (storage && storage->m_sparseMap) {
+ SparseArrayValueMap::iterator iter = storage->m_sparseMap->find(i);
+ if (iter != storage->m_sparseMap->notFound() && (iter->second.attributes & (Accessor | ReadOnly))) {
+ iter->second.put(exec, thisValue, storage->m_sparseMap.get(), value, shouldThrow);
+ return true;
+ }
+ }
+
+ JSValue prototypeValue = current->prototype();
+ if (prototypeValue.isNull())
+ return false;
+
+ current = asObject(prototypeValue);
+ }
+}
+
+bool JSObject::attemptToInterceptPutByIndexOnHole(ExecState* exec, unsigned i, JSValue value, bool shouldThrow)
+{
+ JSValue prototypeValue = prototype();
+ if (prototypeValue.isNull())
+ return false;
+
+ return asObject(prototypeValue)->attemptToInterceptPutByIndexOnHoleForPrototype(exec, this, i, value, shouldThrow);
+}
+
void JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, bool shouldThrow, ArrayStorage* storage)
{
JSGlobalData& globalData = exec->globalData();
@@ -1189,8 +1345,7 @@ void JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue
ASSERT(i <= MAX_ARRAY_INDEX);
switch (structure()->indexingType()) {
- case NonArray:
- case ArrayClass: {
+ case ALL_BLANK_INDEXING_TYPES: {
if (indexingShouldBeSparse()) {
putByIndexBeyondVectorLengthWithArrayStorage(exec, i, value, shouldThrow, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData));
break;
@@ -1205,6 +1360,12 @@ void JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue
storage->m_numValuesInVector = 1;
break;
}
+
+ case NonArrayWithSlowPutArrayStorage:
+ case ArrayWithSlowPutArrayStorage:
+ if (attemptToInterceptPutByIndexOnHole(exec, i, value, shouldThrow))
+ return;
+ // Otherwise, fall though.
case NonArrayWithArrayStorage:
case ArrayWithArrayStorage:
@@ -1297,9 +1458,11 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV
// i should be a valid array index that is outside of the current vector.
ASSERT(i <= MAX_ARRAY_INDEX);
+ if (attributes & (ReadOnly | Accessor))
+ notifyPresenceOfIndexedAccessors(globalData);
+
switch (structure()->indexingType()) {
- case NonArray:
- case ArrayClass: {
+ case ALL_BLANK_INDEXING_TYPES: {
if (indexingShouldBeSparse() || attributes)
return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData));
if (!isDenseEnoughForVector(i, 0) || i >= MAX_STORAGE_VECTOR_LENGTH)
@@ -1311,8 +1474,7 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV
return true;
}
- case NonArrayWithArrayStorage:
- case ArrayWithArrayStorage:
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, arrayStorage());
default:
@@ -1354,13 +1516,11 @@ ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned desiredLength)
unsigned length;
switch (structure()->indexingType()) {
- case NonArray:
- case ArrayClass:
+ case ALL_BLANK_INDEXING_TYPES:
vectorLength = 0;
length = 0;
break;
- case NonArrayWithArrayStorage:
- case ArrayWithArrayStorage:
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
vectorLength = m_butterfly->arrayStorage()->vectorLength();
length = m_butterfly->arrayStorage()->length();
break;
@@ -1478,12 +1638,10 @@ bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Prope
return false;
switch (object->structure()->indexingType()) {
- case NonArray:
- case ArrayClass:
+ case ALL_BLANK_INDEXING_TYPES:
return false;
- case NonArrayWithArrayStorage:
- case ArrayWithArrayStorage: {
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = object->m_butterfly->arrayStorage();
if (i >= storage->length())
return false;
diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h
index 8df521b75..8b52915b6 100644
--- a/Source/JavaScriptCore/runtime/JSObject.h
+++ b/Source/JavaScriptCore/runtime/JSObject.h
@@ -118,7 +118,18 @@ namespace JSC {
bool setPrototypeWithCycleCheck(JSGlobalData&, JSValue prototype);
Structure* inheritorID(JSGlobalData&);
-
+ void notifyUsedAsPrototype(JSGlobalData&);
+
+ bool mayBeUsedAsPrototype(JSGlobalData& globalData)
+ {
+ return isValidOffset(structure()->get(globalData, globalData.m_inheritorIDKey));
+ }
+
+ bool mayInterceptIndexedAccesses()
+ {
+ return structure()->mayInterceptIndexedAccesses();
+ }
+
JSValue get(ExecState*, PropertyName) const;
JSValue get(ExecState*, unsigned propertyName) const;
@@ -135,11 +146,9 @@ namespace JSC {
unsigned getArrayLength() const
{
switch (structure()->indexingType()) {
- case NonArray:
- case ArrayClass:
+ case ALL_BLANK_INDEXING_TYPES:
return 0;
- case NonArrayWithArrayStorage:
- case ArrayWithArrayStorage:
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return m_butterfly->arrayStorage()->length();
default:
ASSERT_NOT_REACHED();
@@ -150,11 +159,9 @@ namespace JSC {
unsigned getVectorLength()
{
switch (structure()->indexingType()) {
- case NonArray:
- case ArrayClass:
+ case ALL_BLANK_INDEXING_TYPES:
return 0;
- case NonArrayWithArrayStorage:
- case ArrayWithArrayStorage:
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return m_butterfly->arrayStorage()->vectorLength();
default:
ASSERT_NOT_REACHED();
@@ -189,11 +196,9 @@ namespace JSC {
bool canGetIndexQuickly(unsigned i)
{
switch (structure()->indexingType()) {
- case NonArray:
- case ArrayClass:
+ case ALL_BLANK_INDEXING_TYPES:
return false;
- case NonArrayWithArrayStorage:
- case ArrayWithArrayStorage:
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return i < m_butterfly->arrayStorage()->vectorLength() && m_butterfly->arrayStorage()->m_vector[i];
default:
ASSERT_NOT_REACHED();
@@ -204,8 +209,7 @@ namespace JSC {
JSValue getIndexQuickly(unsigned i)
{
switch (structure()->indexingType()) {
- case NonArrayWithArrayStorage:
- case ArrayWithArrayStorage:
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return m_butterfly->arrayStorage()->m_vector[i].get();
default:
ASSERT_NOT_REACHED();
@@ -216,12 +220,15 @@ namespace JSC {
bool canSetIndexQuickly(unsigned i)
{
switch (structure()->indexingType()) {
- case NonArray:
- case ArrayClass:
+ case ALL_BLANK_INDEXING_TYPES:
return false;
case NonArrayWithArrayStorage:
case ArrayWithArrayStorage:
return i < m_butterfly->arrayStorage()->vectorLength();
+ case NonArrayWithSlowPutArrayStorage:
+ case ArrayWithSlowPutArrayStorage:
+ return i < m_butterfly->arrayStorage()->vectorLength()
+ && !!m_butterfly->arrayStorage()->m_vector[i];
default:
ASSERT_NOT_REACHED();
return false;
@@ -231,8 +238,7 @@ namespace JSC {
void setIndexQuickly(JSGlobalData& globalData, unsigned i, JSValue v)
{
switch (structure()->indexingType()) {
- case NonArrayWithArrayStorage:
- case ArrayWithArrayStorage: {
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
WriteBarrier<Unknown>& x = m_butterfly->arrayStorage()->m_vector[i];
if (!x) {
ArrayStorage* storage = m_butterfly->arrayStorage();
@@ -251,8 +257,7 @@ namespace JSC {
void initializeIndex(JSGlobalData& globalData, unsigned i, JSValue v)
{
switch (structure()->indexingType()) {
- case NonArrayWithArrayStorage:
- case ArrayWithArrayStorage: {
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = m_butterfly->arrayStorage();
#if CHECK_ARRAY_CONSISTENCY
ASSERT(storage->m_inCompactInitialization);
@@ -276,8 +281,7 @@ namespace JSC {
void completeInitialization(unsigned newLength)
{
switch (structure()->indexingType()) {
- case NonArrayWithArrayStorage:
- case ArrayWithArrayStorage: {
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = m_butterfly->arrayStorage();
// Check that we have initialized as meny properties as we think we have.
UNUSED_PARAM(storage);
@@ -298,11 +302,9 @@ namespace JSC {
bool inSparseIndexingMode()
{
switch (structure()->indexingType()) {
- case NonArray:
- case ArrayClass:
+ case ALL_BLANK_INDEXING_TYPES:
return false;
- case NonArrayWithArrayStorage:
- case ArrayWithArrayStorage:
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return m_butterfly->arrayStorage()->inSparseMode();
default:
ASSERT_NOT_REACHED();
@@ -487,6 +489,22 @@ namespace JSC {
return structure()->globalObject();
}
+ // Does everything possible to return the global object. If it encounters an object
+ // that does not have a global object, it returns 0 instead (for example
+ // JSNotAnObject).
+ JSGlobalObject* unwrappedGlobalObject();
+
+ void switchToSlowPutArrayStorage(JSGlobalData&);
+
+ // The receiver is the prototype in this case. The following:
+ //
+ // asObject(foo->structure()->storedPrototype())->attemptToInterceptPutByIndexOnHoleForPrototype(...)
+ //
+ // is equivalent to:
+ //
+ // foo->attemptToInterceptPutByIndexOnHole(...);
+ bool attemptToInterceptPutByIndexOnHoleForPrototype(ExecState*, JSValue thisValue, unsigned propertyName, JSValue, bool shouldThrow);
+
static size_t offsetOfInlineStorage();
static ptrdiff_t butterflyOffset()
@@ -522,10 +540,7 @@ namespace JSC {
// To create derived types you likely want JSNonFinalObject, below.
JSObject(JSGlobalData&, Structure*, Butterfly* = 0);
- void resetInheritorID(JSGlobalData& globalData)
- {
- removeDirect(globalData, globalData.m_inheritorIDKey);
- }
+ void resetInheritorID(JSGlobalData&);
void visitButterfly(SlotVisitor&, Butterfly*, size_t storageSize);
@@ -533,7 +548,7 @@ namespace JSC {
// storage. This will assert otherwise.
ArrayStorage* arrayStorage()
{
- ASSERT(structure()->indexingType() | HasArrayStorage);
+ ASSERT(hasArrayStorage(structure()->indexingType()));
return m_butterfly->arrayStorage();
}
@@ -542,8 +557,7 @@ namespace JSC {
ArrayStorage* arrayStorageOrNull()
{
switch (structure()->indexingType()) {
- case ArrayWithArrayStorage:
- case NonArrayWithArrayStorage:
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return m_butterfly->arrayStorage();
default:
@@ -558,12 +572,10 @@ namespace JSC {
ArrayStorage* ensureArrayStorage(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
- case ArrayWithArrayStorage:
- case NonArrayWithArrayStorage:
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return m_butterfly->arrayStorage();
- case NonArray:
- case ArrayClass:
+ case ALL_BLANK_INDEXING_TYPES:
return createInitialArrayStorage(globalData);
default:
@@ -592,6 +604,10 @@ namespace JSC {
void deallocateSparseIndexMap();
bool defineOwnIndexedProperty(ExecState*, unsigned, PropertyDescriptor&, bool throwException);
SparseArrayValueMap* allocateSparseIndexMap(JSGlobalData&);
+
+ void notifyPresenceOfIndexedAccessors(JSGlobalData&);
+
+ bool attemptToInterceptPutByIndexOnHole(ExecState*, unsigned index, JSValue, bool shouldThrow);
private:
friend class LLIntOffsetsExtractor;
@@ -824,22 +840,6 @@ inline JSValue JSObject::prototype() const
return structure()->storedPrototype();
}
-inline void JSObject::setPrototype(JSGlobalData& globalData, JSValue prototype)
-{
- ASSERT(prototype);
- setStructure(globalData, Structure::changePrototypeTransition(globalData, structure(), prototype));
-}
-
-inline Structure* JSObject::inheritorID(JSGlobalData& globalData)
-{
- if (WriteBarrierBase<Unknown>* location = getDirectLocation(globalData, globalData.m_inheritorIDKey)) {
- Structure* inheritorID = jsCast<Structure*>(location->get());
- ASSERT(inheritorID->isEmpty());
- return inheritorID;
- }
- return createInheritorID(globalData);
-}
-
inline bool JSCell::inherits(const ClassInfo* info) const
{
return classInfo()->isSubClassOf(info);
@@ -1190,8 +1190,7 @@ inline void JSValue::put(ExecState* exec, PropertyName propertyName, JSValue val
inline void JSValue::putByIndex(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
{
if (UNLIKELY(!isCell())) {
- PutPropertySlot slot(shouldThrow);
- putToPrimitive(exec, Identifier::from(exec, propertyName), value, slot);
+ putToPrimitiveByIndex(exec, propertyName, value, shouldThrow);
return;
}
asCell()->methodTable()->putByIndex(asCell(), exec, propertyName, value, shouldThrow);
diff --git a/Source/JavaScriptCore/runtime/JSValue.cpp b/Source/JavaScriptCore/runtime/JSValue.cpp
index caff9973b..ac00fad3d 100644
--- a/Source/JavaScriptCore/runtime/JSValue.cpp
+++ b/Source/JavaScriptCore/runtime/JSValue.cpp
@@ -1,7 +1,7 @@
/*
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2007, 2008, 2012 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -113,6 +113,12 @@ void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue
{
JSGlobalData& globalData = exec->globalData();
+ unsigned index = propertyName.asIndex();
+ if (index != PropertyName::NotAnIndex) {
+ putToPrimitiveByIndex(exec, index, value, slot.isStrictMode());
+ return;
+ }
+
// Check if there are any setters or getters in the prototype chain
JSObject* obj = synthesizePrototype(exec);
JSValue prototype;
@@ -172,6 +178,21 @@ void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue
return;
}
+void JSValue::putToPrimitiveByIndex(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
+{
+ if (propertyName > MAX_ARRAY_INDEX) {
+ PutPropertySlot slot(shouldThrow);
+ putToPrimitive(exec, Identifier::from(exec, propertyName), value, slot);
+ return;
+ }
+
+ if (synthesizePrototype(exec)->attemptToInterceptPutByIndexOnHoleForPrototype(exec, *this, propertyName, value, shouldThrow))
+ return;
+
+ if (shouldThrow)
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
+}
+
char* JSValue::description() const
{
static const size_t size = 128;
diff --git a/Source/JavaScriptCore/runtime/JSValue.h b/Source/JavaScriptCore/runtime/JSValue.h
index ce9405817..6e01d8d2d 100644
--- a/Source/JavaScriptCore/runtime/JSValue.h
+++ b/Source/JavaScriptCore/runtime/JSValue.h
@@ -1,7 +1,7 @@
/*
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -240,6 +240,7 @@ namespace JSC {
JSValue get(ExecState*, unsigned propertyName, PropertySlot&) const;
void put(ExecState*, PropertyName, JSValue, PutPropertySlot&);
void putToPrimitive(ExecState*, PropertyName, JSValue, PutPropertySlot&);
+ void putToPrimitiveByIndex(ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
void putByIndex(ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
JSObject* toThisObject(ExecState*) const;
diff --git a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp
index 84c60a69c..b1a5b9fb3 100644
--- a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp
@@ -74,6 +74,7 @@ void ObjectPrototype::finishCreation(JSGlobalData& globalData, JSGlobalObject*)
{
Base::finishCreation(globalData);
ASSERT(inherits(&s_info));
+ notifyUsedAsPrototype(globalData);
}
bool ObjectPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
diff --git a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp
index ed8aace66..04fea60e8 100644
--- a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp
@@ -27,7 +27,6 @@
#include "RegExpMatchesArray.h"
#include "ButterflyInlineMethods.h"
-#include "SparseArrayValueMapInlineMethods.h"
namespace JSC {
diff --git a/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp b/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp
index 40c4ed26e..3f709b0a7 100644
--- a/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp
+++ b/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp
@@ -27,11 +27,186 @@
#include "SparseArrayValueMap.h"
#include "ClassInfo.h"
-#include "SparseArrayValueMapInlineMethods.h"
+#include "GetterSetter.h"
+#include "JSObject.h"
+#include "PropertySlot.h"
+#include "Reject.h"
+#include "SlotVisitor.h"
+#include "Structure.h"
namespace JSC {
const ClassInfo SparseArrayValueMap::s_info = { "SparseArrayValueMap", 0, 0, 0, CREATE_METHOD_TABLE(SparseArrayValueMap) };
+SparseArrayValueMap::SparseArrayValueMap(JSGlobalData& globalData)
+ : Base(globalData, globalData.sparseArrayValueMapStructure.get())
+ , m_flags(Normal)
+ , m_reportedCapacity(0)
+{
+}
+
+SparseArrayValueMap::~SparseArrayValueMap()
+{
+}
+
+void SparseArrayValueMap::finishCreation(JSGlobalData& globalData)
+{
+ Base::finishCreation(globalData);
+}
+
+SparseArrayValueMap* SparseArrayValueMap::create(JSGlobalData& globalData)
+{
+ SparseArrayValueMap* result = new (NotNull, allocateCell<SparseArrayValueMap>(globalData.heap)) SparseArrayValueMap(globalData);
+ result->finishCreation(globalData);
+ return result;
+}
+
+void SparseArrayValueMap::destroy(JSCell* cell)
+{
+ static_cast<SparseArrayValueMap*>(cell)->SparseArrayValueMap::~SparseArrayValueMap();
+}
+
+Structure* SparseArrayValueMap::createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(CompoundType, StructureFlags), &s_info);
+}
+
+SparseArrayValueMap::AddResult SparseArrayValueMap::add(JSObject* array, unsigned i)
+{
+ SparseArrayEntry entry;
+ entry.setWithoutWriteBarrier(jsUndefined());
+
+ AddResult result = m_map.add(i, entry);
+ size_t capacity = m_map.capacity();
+ if (capacity != m_reportedCapacity) {
+ Heap::heap(array)->reportExtraMemoryCost((capacity - m_reportedCapacity) * (sizeof(unsigned) + sizeof(WriteBarrier<Unknown>)));
+ m_reportedCapacity = capacity;
+ }
+ return result;
+}
+
+void SparseArrayValueMap::putEntry(ExecState* exec, JSObject* array, unsigned i, JSValue value, bool shouldThrow)
+{
+ AddResult result = add(array, i);
+ SparseArrayEntry& entry = result.iterator->second;
+
+ // To save a separate find & add, we first always add to the sparse map.
+ // In the uncommon case that this is a new property, and the array is not
+ // extensible, this is not the right thing to have done - so remove again.
+ if (result.isNewEntry && !array->isExtensible()) {
+ remove(result.iterator);
+ if (shouldThrow)
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
+ return;
+ }
+
+ entry.put(exec, array, this, value, shouldThrow);
+}
+
+bool SparseArrayValueMap::putDirect(ExecState* exec, JSObject* array, unsigned i, JSValue value, unsigned attributes, PutDirectIndexMode mode)
+{
+ AddResult result = add(array, i);
+ SparseArrayEntry& entry = result.iterator->second;
+
+ // To save a separate find & add, we first always add to the sparse map.
+ // In the uncommon case that this is a new property, and the array is not
+ // extensible, this is not the right thing to have done - so remove again.
+ if (mode != PutDirectIndexLikePutDirect && result.isNewEntry && !array->isExtensible()) {
+ remove(result.iterator);
+ return reject(exec, mode == PutDirectIndexShouldThrow, "Attempting to define property on object that is not extensible.");
+ }
+
+ entry.attributes = attributes;
+ entry.set(exec->globalData(), this, value);
+ return true;
+}
+
+void SparseArrayEntry::get(PropertySlot& slot) const
+{
+ JSValue value = Base::get();
+ ASSERT(value);
+
+ if (LIKELY(!value.isGetterSetter())) {
+ slot.setValue(value);
+ return;
+ }
+
+ JSObject* getter = asGetterSetter(value)->getter();
+ if (!getter) {
+ slot.setUndefined();
+ return;
+ }
+
+ slot.setGetterSlot(getter);
+}
+
+void SparseArrayEntry::get(PropertyDescriptor& descriptor) const
+{
+ descriptor.setDescriptor(Base::get(), attributes);
+}
+
+JSValue SparseArrayEntry::get(ExecState* exec, JSObject* array) const
+{
+ JSValue result = Base::get();
+ ASSERT(result);
+
+ if (LIKELY(!result.isGetterSetter()))
+ return result;
+
+ JSObject* getter = asGetterSetter(result)->getter();
+ if (!getter)
+ return jsUndefined();
+
+ CallData callData;
+ CallType callType = getter->methodTable()->getCallData(getter, callData);
+ return call(exec, getter, callType, callData, array, exec->emptyList());
+}
+
+void SparseArrayEntry::put(ExecState* exec, JSValue thisValue, SparseArrayValueMap* map, JSValue value, bool shouldThrow)
+{
+ if (!(attributes & Accessor)) {
+ if (attributes & ReadOnly) {
+ if (shouldThrow)
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
+ return;
+ }
+
+ set(exec->globalData(), map, value);
+ return;
+ }
+
+ JSValue accessor = Base::get();
+ ASSERT(accessor.isGetterSetter());
+ JSObject* setter = asGetterSetter(accessor)->setter();
+
+ if (!setter) {
+ if (shouldThrow)
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
+ return;
+ }
+
+ CallData callData;
+ CallType callType = setter->methodTable()->getCallData(setter, callData);
+ MarkedArgumentBuffer args;
+ args.append(value);
+ call(exec, setter, callType, callData, thisValue, args);
+}
+
+JSValue SparseArrayEntry::getNonSparseMode() const
+{
+ ASSERT(!attributes);
+ return Base::get();
+}
+
+void SparseArrayValueMap::visitChildren(JSCell* thisObject, SlotVisitor& visitor)
+{
+ Base::visitChildren(thisObject, visitor);
+
+ SparseArrayValueMap* thisMap = jsCast<SparseArrayValueMap*>(thisObject);
+ iterator end = thisMap->m_map.end();
+ for (iterator it = thisMap->m_map.begin(); it != end; ++it)
+ visitor.append(&it->second);
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/SparseArrayValueMap.h b/Source/JavaScriptCore/runtime/SparseArrayValueMap.h
index aafdf974f..5d8d0577a 100644
--- a/Source/JavaScriptCore/runtime/SparseArrayValueMap.h
+++ b/Source/JavaScriptCore/runtime/SparseArrayValueMap.h
@@ -36,6 +36,8 @@
namespace JSC {
+class SparseArrayValueMap;
+
struct SparseArrayEntry : public WriteBarrier<Unknown> {
typedef WriteBarrier<Unknown> Base;
@@ -44,6 +46,7 @@ struct SparseArrayEntry : public WriteBarrier<Unknown> {
JSValue get(ExecState*, JSObject*) const;
void get(PropertySlot&) const;
void get(PropertyDescriptor&) const;
+ void put(ExecState*, JSValue thisValue, SparseArrayValueMap*, JSValue, bool shouldThrow);
JSValue getNonSparseMode() const;
unsigned attributes;
diff --git a/Source/JavaScriptCore/runtime/SparseArrayValueMapInlineMethods.h b/Source/JavaScriptCore/runtime/SparseArrayValueMapInlineMethods.h
deleted file mode 100644
index f3ef32f46..000000000
--- a/Source/JavaScriptCore/runtime/SparseArrayValueMapInlineMethods.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef SparseArrayValueMapInlineMethods_h
-#define SparseArrayValueMapInlineMethods_h
-
-#include "GetterSetter.h"
-#include "Reject.h"
-#include "SparseArrayValueMap.h"
-
-namespace JSC {
-
-inline SparseArrayValueMap::SparseArrayValueMap(JSGlobalData& globalData)
- : Base(globalData, globalData.sparseArrayValueMapStructure.get())
- , m_flags(Normal)
- , m_reportedCapacity(0)
-{
-}
-
-inline SparseArrayValueMap::~SparseArrayValueMap()
-{
-}
-
-inline void SparseArrayValueMap::finishCreation(JSGlobalData& globalData)
-{
- Base::finishCreation(globalData);
-}
-
-inline SparseArrayValueMap* SparseArrayValueMap::create(JSGlobalData& globalData)
-{
- SparseArrayValueMap* result = new (NotNull, allocateCell<SparseArrayValueMap>(globalData.heap)) SparseArrayValueMap(globalData);
- result->finishCreation(globalData);
- return result;
-}
-
-inline void SparseArrayValueMap::destroy(JSCell* cell)
-{
- static_cast<SparseArrayValueMap*>(cell)->SparseArrayValueMap::~SparseArrayValueMap();
-}
-
-inline Structure* SparseArrayValueMap::createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
-{
- return Structure::create(globalData, globalObject, prototype, TypeInfo(CompoundType, StructureFlags), &s_info);
-}
-
-inline SparseArrayValueMap::AddResult SparseArrayValueMap::add(JSObject* array, unsigned i)
-{
- SparseArrayEntry entry;
- entry.setWithoutWriteBarrier(jsUndefined());
-
- AddResult result = m_map.add(i, entry);
- size_t capacity = m_map.capacity();
- if (capacity != m_reportedCapacity) {
- Heap::heap(array)->reportExtraMemoryCost((capacity - m_reportedCapacity) * (sizeof(unsigned) + sizeof(WriteBarrier<Unknown>)));
- m_reportedCapacity = capacity;
- }
- return result;
-}
-
-inline void SparseArrayValueMap::putEntry(ExecState* exec, JSObject* array, unsigned i, JSValue value, bool shouldThrow)
-{
- AddResult result = add(array, i);
- SparseArrayEntry& entry = result.iterator->second;
-
- // To save a separate find & add, we first always add to the sparse map.
- // In the uncommon case that this is a new property, and the array is not
- // extensible, this is not the right thing to have done - so remove again.
- if (result.isNewEntry && !array->isExtensible()) {
- remove(result.iterator);
- if (shouldThrow)
- throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
- return;
- }
-
- if (!(entry.attributes & Accessor)) {
- if (entry.attributes & ReadOnly) {
- if (shouldThrow)
- throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
- return;
- }
-
- entry.set(exec->globalData(), this, value);
- return;
- }
-
- JSValue accessor = entry.SparseArrayEntry::Base::get();
- ASSERT(accessor.isGetterSetter());
- JSObject* setter = asGetterSetter(accessor)->setter();
-
- if (!setter) {
- if (shouldThrow)
- throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
- return;
- }
-
- CallData callData;
- CallType callType = setter->methodTable()->getCallData(setter, callData);
- MarkedArgumentBuffer args;
- args.append(value);
- call(exec, setter, callType, callData, array, args);
-}
-
-inline bool SparseArrayValueMap::putDirect(ExecState* exec, JSObject* array, unsigned i, JSValue value, unsigned attributes, PutDirectIndexMode mode)
-{
- AddResult result = add(array, i);
- SparseArrayEntry& entry = result.iterator->second;
-
- // To save a separate find & add, we first always add to the sparse map.
- // In the uncommon case that this is a new property, and the array is not
- // extensible, this is not the right thing to have done - so remove again.
- if (mode != PutDirectIndexLikePutDirect && result.isNewEntry && !array->isExtensible()) {
- remove(result.iterator);
- return reject(exec, mode == PutDirectIndexShouldThrow, "Attempting to define property on object that is not extensible.");
- }
-
- entry.attributes = attributes;
- entry.set(exec->globalData(), this, value);
- return true;
-}
-
-inline void SparseArrayEntry::get(PropertySlot& slot) const
-{
- JSValue value = Base::get();
- ASSERT(value);
-
- if (LIKELY(!value.isGetterSetter())) {
- slot.setValue(value);
- return;
- }
-
- JSObject* getter = asGetterSetter(value)->getter();
- if (!getter) {
- slot.setUndefined();
- return;
- }
-
- slot.setGetterSlot(getter);
-}
-
-inline void SparseArrayEntry::get(PropertyDescriptor& descriptor) const
-{
- descriptor.setDescriptor(Base::get(), attributes);
-}
-
-inline JSValue SparseArrayEntry::get(ExecState* exec, JSObject* array) const
-{
- JSValue result = Base::get();
- ASSERT(result);
-
- if (LIKELY(!result.isGetterSetter()))
- return result;
-
- JSObject* getter = asGetterSetter(result)->getter();
- if (!getter)
- return jsUndefined();
-
- CallData callData;
- CallType callType = getter->methodTable()->getCallData(getter, callData);
- return call(exec, getter, callType, callData, array, exec->emptyList());
-}
-
-inline JSValue SparseArrayEntry::getNonSparseMode() const
-{
- ASSERT(!attributes);
- return Base::get();
-}
-
-inline void SparseArrayValueMap::visitChildren(JSCell* thisObject, SlotVisitor& visitor)
-{
- Base::visitChildren(thisObject, visitor);
-
- SparseArrayValueMap* thisMap = jsCast<SparseArrayValueMap*>(thisObject);
- iterator end = thisMap->m_map.end();
- for (iterator it = thisMap->m_map.begin(); it != end; ++it)
- visitor.append(&it->second);
-}
-
-} // namespace JSC
-
-#endif // SparseArrayValueMapInlineMethods_h
-
diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp
index c99c6dda4..a59a0860d 100644
--- a/Source/JavaScriptCore/runtime/Structure.cpp
+++ b/Source/JavaScriptCore/runtime/Structure.cpp
@@ -309,6 +309,30 @@ Structure* Structure::addPropertyTransitionToExistingStructure(Structure* struct
return 0;
}
+bool Structure::anyObjectInChainMayInterceptIndexedAccesses() const
+{
+ for (const Structure* current = this; ;) {
+ if (current->mayInterceptIndexedAccesses())
+ return true;
+
+ JSValue prototype = current->storedPrototype();
+ if (prototype.isNull())
+ return false;
+
+ current = asObject(prototype)->structure();
+ }
+}
+
+NonPropertyTransition Structure::suggestedIndexingTransition() const
+{
+ ASSERT(!hasIndexedProperties(indexingType()));
+
+ if (anyObjectInChainMayInterceptIndexedAccesses() || globalObject()->isHavingABadTime())
+ return AllocateSlowPutArrayStorage;
+
+ return AllocateArrayStorage;
+}
+
Structure* Structure::addPropertyTransition(JSGlobalData& globalData, Structure* structure, PropertyName propertyName, unsigned attributes, JSCell* specificValue, PropertyOffset& offset)
{
// If we have a specific function, we may have got to this point if there is
diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h
index 9303a0dbb..e77287b20 100644
--- a/Source/JavaScriptCore/runtime/Structure.h
+++ b/Source/JavaScriptCore/runtime/Structure.h
@@ -144,7 +144,16 @@ namespace JSC {
IndexingType indexingType() const { return m_indexingType & AllArrayTypes; }
IndexingType indexingTypeIncludingHistory() const { return m_indexingType; }
-
+
+ bool mayInterceptIndexedAccesses() const
+ {
+ return !!(indexingTypeIncludingHistory() & MayHaveIndexedAccessors);
+ }
+
+ bool anyObjectInChainMayInterceptIndexedAccesses() const;
+
+ NonPropertyTransition suggestedIndexingTransition() const;
+
JSGlobalObject* globalObject() const { return m_globalObject.get(); }
void setGlobalObject(JSGlobalData& globalData, JSGlobalObject* globalObject) { m_globalObject.set(globalData, this, globalObject); }
diff --git a/Source/JavaScriptCore/runtime/StructureTransitionTable.h b/Source/JavaScriptCore/runtime/StructureTransitionTable.h
index 59e7e94f3..90cb6a4db 100644
--- a/Source/JavaScriptCore/runtime/StructureTransitionTable.h
+++ b/Source/JavaScriptCore/runtime/StructureTransitionTable.h
@@ -43,7 +43,10 @@ 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 {
- AllocateArrayStorage
+ AllocateArrayStorage,
+ AllocateSlowPutArrayStorage,
+ SwitchToSlowPutArrayStorage,
+ AddIndexedAccessors
};
inline unsigned toAttributes(NonPropertyTransition transition)
@@ -56,6 +59,13 @@ inline IndexingType newIndexingType(IndexingType oldType, NonPropertyTransition
switch (transition) {
case AllocateArrayStorage:
return oldType | HasArrayStorage;
+ case AllocateSlowPutArrayStorage:
+ return oldType | HasSlowPutArrayStorage;
+ case SwitchToSlowPutArrayStorage:
+ ASSERT(oldType & HasArrayStorage);
+ return (oldType & ~HasArrayStorage) | HasSlowPutArrayStorage;
+ case AddIndexedAccessors:
+ return oldType | MayHaveIndexedAccessors;
default:
ASSERT_NOT_REACHED();
return oldType;
diff --git a/Source/JavaScriptCore/runtime/SymbolTable.h b/Source/JavaScriptCore/runtime/SymbolTable.h
index f6f70c6b9..5427a009b 100644
--- a/Source/JavaScriptCore/runtime/SymbolTable.h
+++ b/Source/JavaScriptCore/runtime/SymbolTable.h
@@ -40,6 +40,23 @@ namespace JSC {
class Watchpoint;
class WatchpointSet;
+ struct SlowArgument {
+ enum Status {
+ Normal = 0,
+ Captured = 1,
+ Deleted = 2
+ };
+
+ SlowArgument()
+ : status(Normal)
+ , indexIfCaptured(0)
+ {
+ }
+
+ Status status;
+ int indexIfCaptured; // If status is 'Captured', indexIfCaptured is our index in the CallFrame.
+ };
+
static ALWAYS_INLINE int missingSymbolMarker() { return std::numeric_limits<int>::max(); }
// The bit twiddling in this class assumes that every register index is a
@@ -357,9 +374,14 @@ namespace JSC {
int captureEnd() { return m_captureEnd; }
void setCaptureEnd(int captureEnd) { m_captureEnd = captureEnd; }
+ int parameterCount() { return m_parameterCountIncludingThis - 1; }
int parameterCountIncludingThis() { return m_parameterCountIncludingThis; }
void setParameterCountIncludingThis(int parameterCountIncludingThis) { m_parameterCountIncludingThis = parameterCountIncludingThis; }
+ // 0 if we don't capture any arguments; parameterCount() in length if we do.
+ const SlowArgument* slowArguments() { return m_slowArguments.get(); }
+ void setSlowArguments(PassOwnArrayPtr<SlowArgument> slowArguments) { m_slowArguments = slowArguments; }
+
static JS_EXPORTDATA const ClassInfo s_info;
private:
@@ -379,8 +401,9 @@ namespace JSC {
CaptureMode m_captureMode;
int m_captureStart;
int m_captureEnd;
+
+ OwnArrayPtr<SlowArgument> m_slowArguments;
};
-
} // namespace JSC
#endif // SymbolTable_h