summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2012-10-17 16:21:14 +0200
committerSimon Hausmann <simon.hausmann@digia.com>2012-10-17 16:21:14 +0200
commit8995b83bcbfbb68245f779b64e5517627c6cc6ea (patch)
tree17985605dab9263cc2444bd4d45f189e142cca7c /Source/JavaScriptCore/runtime
parentb9c9652036d5e9f1e29c574f40bc73a35c81ace6 (diff)
downloadqtwebkit-8995b83bcbfbb68245f779b64e5517627c6cc6ea.tar.gz
Imported WebKit commit cf4f8fc6f19b0629f51860cb2d4b25e139d07e00 (http://svn.webkit.org/repository/webkit/trunk@131592)
New snapshot that includes the build fixes for Mac OS X 10.6 and earlier as well as the previously cherry-picked changes
Diffstat (limited to 'Source/JavaScriptCore/runtime')
-rw-r--r--Source/JavaScriptCore/runtime/Arguments.cpp14
-rw-r--r--Source/JavaScriptCore/runtime/Arguments.h9
-rw-r--r--Source/JavaScriptCore/runtime/ArrayConstructor.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/ArrayConventions.h2
-rw-r--r--Source/JavaScriptCore/runtime/ArrayPrototype.cpp33
-rw-r--r--Source/JavaScriptCore/runtime/ArrayStorage.h2
-rw-r--r--Source/JavaScriptCore/runtime/BooleanConstructor.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/BooleanObject.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/BooleanPrototype.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/Butterfly.h25
-rw-r--r--Source/JavaScriptCore/runtime/ButterflyInlineMethods.h8
-rw-r--r--Source/JavaScriptCore/runtime/ClassInfo.h4
-rw-r--r--Source/JavaScriptCore/runtime/CommonSlowPaths.h6
-rw-r--r--Source/JavaScriptCore/runtime/DateConstructor.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/DatePrototype.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/Error.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/ErrorConstructor.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/ErrorPrototype.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/Executable.h2
-rw-r--r--Source/JavaScriptCore/runtime/FunctionConstructor.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/FunctionPrototype.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/Identifier.cpp9
-rw-r--r--Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h13
-rw-r--r--Source/JavaScriptCore/runtime/IndexingType.cpp76
-rw-r--r--Source/JavaScriptCore/runtime/IndexingType.h53
-rw-r--r--Source/JavaScriptCore/runtime/InitializeThreading.cpp5
-rw-r--r--Source/JavaScriptCore/runtime/InternalFunction.cpp5
-rw-r--r--Source/JavaScriptCore/runtime/InternalFunction.h6
-rw-r--r--Source/JavaScriptCore/runtime/JSActivation.cpp12
-rw-r--r--Source/JavaScriptCore/runtime/JSArray.cpp914
-rw-r--r--Source/JavaScriptCore/runtime/JSArray.h130
-rw-r--r--Source/JavaScriptCore/runtime/JSBoundFunction.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/JSCell.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/JSCell.h59
-rw-r--r--Source/JavaScriptCore/runtime/JSDestructibleObject.h43
-rw-r--r--Source/JavaScriptCore/runtime/JSFunction.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalData.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalData.h48
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.cpp22
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.h33
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalThis.cpp58
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalThis.h76
-rw-r--r--Source/JavaScriptCore/runtime/JSLock.cpp8
-rw-r--r--Source/JavaScriptCore/runtime/JSNameScope.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/JSNotAnObject.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/JSONObject.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.cpp473
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.h212
-rw-r--r--Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/JSPropertyNameIterator.h14
-rw-r--r--Source/JavaScriptCore/runtime/JSProxy.cpp129
-rw-r--r--Source/JavaScriptCore/runtime/JSProxy.h95
-rw-r--r--Source/JavaScriptCore/runtime/JSScope.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/JSString.h2
-rw-r--r--Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/JSSymbolTableObject.h12
-rw-r--r--Source/JavaScriptCore/runtime/JSType.h2
-rw-r--r--Source/JavaScriptCore/runtime/JSValue.cpp11
-rw-r--r--Source/JavaScriptCore/runtime/JSVariableObject.h2
-rw-r--r--Source/JavaScriptCore/runtime/JSWithScope.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/JSWrapperObject.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/JSWrapperObject.h10
-rw-r--r--Source/JavaScriptCore/runtime/MathObject.cpp6
-rw-r--r--Source/JavaScriptCore/runtime/MemoryStatistics.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/NameConstructor.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/NameInstance.h6
-rw-r--r--Source/JavaScriptCore/runtime/NamePrototype.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/NumberConstructor.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/NumberObject.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/NumberPrototype.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/ObjectConstructor.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/ObjectPrototype.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/Options.cpp18
-rw-r--r--Source/JavaScriptCore/runtime/Options.h16
-rw-r--r--Source/JavaScriptCore/runtime/PropertyMapHashTable.h11
-rw-r--r--Source/JavaScriptCore/runtime/PropertyOffset.h52
-rw-r--r--Source/JavaScriptCore/runtime/RegExp.h2
-rw-r--r--Source/JavaScriptCore/runtime/RegExpCache.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/RegExpConstructor.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/RegExpObject.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/RegExpPrototype.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp6
-rw-r--r--Source/JavaScriptCore/runtime/SparseArrayValueMap.h2
-rw-r--r--Source/JavaScriptCore/runtime/StringConstructor.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/StringObject.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/StringPrototype.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/Structure.cpp33
-rw-r--r--Source/JavaScriptCore/runtime/Structure.h82
-rw-r--r--Source/JavaScriptCore/runtime/StructureChain.h5
-rw-r--r--Source/JavaScriptCore/runtime/StructureTransitionTable.h14
-rw-r--r--Source/JavaScriptCore/runtime/SymbolTable.h5
-rw-r--r--Source/JavaScriptCore/runtime/TypedArrayDescriptor.h76
-rw-r--r--Source/JavaScriptCore/runtime/WeakGCMap.h6
96 files changed, 2051 insertions, 1001 deletions
diff --git a/Source/JavaScriptCore/runtime/Arguments.cpp b/Source/JavaScriptCore/runtime/Arguments.cpp
index fdf202192..ba73b2cf2 100644
--- a/Source/JavaScriptCore/runtime/Arguments.cpp
+++ b/Source/JavaScriptCore/runtime/Arguments.cpp
@@ -33,9 +33,7 @@ using namespace std;
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(Arguments);
-
-const ClassInfo Arguments::s_info = { "Arguments", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(Arguments) };
+const ClassInfo Arguments::s_info = { "Arguments", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(Arguments) };
void Arguments::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
@@ -406,19 +404,19 @@ void Arguments::tearOffForInlineCallFrame(JSGlobalData& globalData, Register* re
JSValue value;
Register* location = &registers[CallFrame::argumentOffset(i)];
switch (recovery.technique()) {
- case AlreadyInRegisterFile:
+ case AlreadyInJSStack:
value = location->jsValue();
break;
- case AlreadyInRegisterFileAsUnboxedInt32:
+ case AlreadyInJSStackAsUnboxedInt32:
value = jsNumber(location->unboxedInt32());
break;
- case AlreadyInRegisterFileAsUnboxedCell:
+ case AlreadyInJSStackAsUnboxedCell:
value = location->unboxedCell();
break;
- case AlreadyInRegisterFileAsUnboxedBoolean:
+ case AlreadyInJSStackAsUnboxedBoolean:
value = jsBoolean(location->unboxedBoolean());
break;
- case AlreadyInRegisterFileAsUnboxedDouble:
+ case AlreadyInJSStackAsUnboxedDouble:
#if USE(JSVALUE64)
value = jsNumber(*bitwise_cast<double*>(location));
#else
diff --git a/Source/JavaScriptCore/runtime/Arguments.h b/Source/JavaScriptCore/runtime/Arguments.h
index 40063bead..7c8b69bd1 100644
--- a/Source/JavaScriptCore/runtime/Arguments.h
+++ b/Source/JavaScriptCore/runtime/Arguments.h
@@ -26,6 +26,7 @@
#include "CodeOrigin.h"
#include "JSActivation.h"
+#include "JSDestructibleObject.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "Interpreter.h"
@@ -33,11 +34,11 @@
namespace JSC {
- class Arguments : public JSNonFinalObject {
+ class Arguments : public JSDestructibleObject {
friend class JIT;
friend class DFG::SpeculativeJIT;
public:
- typedef JSNonFinalObject Base;
+ typedef JSDestructibleObject Base;
static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame)
{
@@ -147,12 +148,12 @@ namespace JSC {
}
inline Arguments::Arguments(CallFrame* callFrame)
- : JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
+ : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
{
}
inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
- : JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
+ : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
{
}
diff --git a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp
index eda35e146..a13648442 100644
--- a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp
@@ -53,8 +53,6 @@ const ClassInfo ArrayConstructor::s_info = { "Function", &InternalFunction::s_in
@end
*/
-ASSERT_CLASS_FITS_IN_CELL(ArrayConstructor);
-
ArrayConstructor::ArrayConstructor(JSGlobalObject* globalObject, Structure* structure)
: InternalFunction(globalObject, structure)
{
diff --git a/Source/JavaScriptCore/runtime/ArrayConventions.h b/Source/JavaScriptCore/runtime/ArrayConventions.h
index 3ea6b0471..a557b1ef9 100644
--- a/Source/JavaScriptCore/runtime/ArrayConventions.h
+++ b/Source/JavaScriptCore/runtime/ArrayConventions.h
@@ -79,7 +79,7 @@ static const unsigned minDensityMultiplier = 8;
inline bool isDenseEnoughForVector(unsigned length, unsigned numValues)
{
- return length <= MIN_SPARSE_ARRAY_INDEX || length / minDensityMultiplier <= numValues;
+ return length / minDensityMultiplier <= numValues;
}
inline IndexingHeader indexingHeaderForArray(unsigned length, unsigned vectorLength)
diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp
index 1eacd1179..6975dc778 100644
--- a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp
@@ -42,8 +42,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(ArrayPrototype);
-
static EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState*);
static EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState*);
static EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState*);
@@ -194,7 +192,8 @@ static unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument
// currentCount) will be shifted to the left or right as appropriate; in the
// case of shift this must be removing values, in the case of unshift this
// must be introducing new values.
-static inline void shift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length)
+template<JSArray::ShiftCountMode shiftCountMode>
+void shift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length)
{
ASSERT(currentCount > resultCount);
unsigned count = currentCount - resultCount;
@@ -202,9 +201,9 @@ static inline void shift(ExecState* exec, JSObject* thisObj, unsigned header, un
ASSERT(header <= length);
ASSERT(currentCount <= (length - header));
- if (!header && isJSArray(thisObj)) {
+ if (isJSArray(thisObj)) {
JSArray* array = asArray(thisObj);
- if (array->length() == length && asArray(thisObj)->shiftCount(exec, count))
+ if (array->length() == length && asArray(thisObj)->shiftCount<shiftCountMode>(exec, header, count))
return;
}
@@ -231,7 +230,8 @@ static inline void shift(ExecState* exec, JSObject* thisObj, unsigned header, un
}
}
}
-static inline void unshift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length)
+template<JSArray::ShiftCountMode shiftCountMode>
+void unshift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length)
{
ASSERT(resultCount > currentCount);
unsigned count = resultCount - currentCount;
@@ -245,12 +245,12 @@ static inline void unshift(ExecState* exec, JSObject* thisObj, unsigned header,
return;
}
- if (!header && isJSArray(thisObj)) {
+ if (isJSArray(thisObj)) {
JSArray* array = asArray(thisObj);
- if (array->length() == length && asArray(thisObj)->unshiftCount(exec, count))
+ if (array->length() == length && array->unshiftCount<shiftCountMode>(exec, header, count))
return;
}
-
+
for (unsigned k = length - currentCount; k > header; --k) {
unsigned from = k + currentCount - 1;
unsigned to = k + resultCount - 1;
@@ -526,7 +526,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec)
array->push(exec, exec->argument(0));
return JSValue::encode(jsNumber(array->length()));
}
-
+
JSObject* thisObj = thisValue.toObject(exec);
unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
if (exec->hadException())
@@ -544,6 +544,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec)
if (exec->hadException())
return JSValue::encode(jsUndefined());
}
+
JSValue newLength(static_cast<int64_t>(length) + static_cast<int64_t>(exec->argumentCount()));
putProperty(exec, thisObj, exec->propertyNames().length, newLength);
return JSValue::encode(newLength);
@@ -600,7 +601,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState* exec)
result = jsUndefined();
} else {
result = thisObj->get(exec, 0);
- shift(exec, thisObj, 0, 1, 0, length);
+ shift<JSArray::ShiftCountForShift>(exec, thisObj, 0, 1, 0, length);
if (exec->hadException())
return JSValue::encode(jsUndefined());
putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - 1));
@@ -655,7 +656,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec)
CallData callData;
CallType callType = getCallData(function, callData);
- if (thisObj->classInfo() == &JSArray::s_info && !asArray(thisObj)->inSparseIndexingMode() && !shouldUseSlowPut(thisObj->structure()->indexingType())) {
+ if (thisObj->classInfo() == &JSArray::s_info && !asArray(thisObj)->hasSparseMap() && !shouldUseSlowPut(thisObj->structure()->indexingType())) {
if (isNumericCompareFunction(exec, callType, callData))
asArray(thisObj)->sortNumeric(exec, function, callType, callData);
else if (callType != CallTypeNone)
@@ -730,7 +731,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
if (exec->hadException())
return JSValue::encode(jsUndefined());
-
+
if (!exec->argumentCount())
return JSValue::encode(constructEmptyArray(exec));
@@ -762,11 +763,11 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
unsigned additionalArgs = std::max<int>(exec->argumentCount() - 2, 0);
if (additionalArgs < deleteCount) {
- shift(exec, thisObj, begin, deleteCount, additionalArgs, length);
+ shift<JSArray::ShiftCountForSplice>(exec, thisObj, begin, deleteCount, additionalArgs, length);
if (exec->hadException())
return JSValue::encode(jsUndefined());
} else if (additionalArgs > deleteCount) {
- unshift(exec, thisObj, begin, deleteCount, additionalArgs, length);
+ unshift<JSArray::ShiftCountForSplice>(exec, thisObj, begin, deleteCount, additionalArgs, length);
if (exec->hadException())
return JSValue::encode(jsUndefined());
}
@@ -791,7 +792,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState* exec)
unsigned nrArgs = exec->argumentCount();
if (nrArgs) {
- unshift(exec, thisObj, 0, 0, nrArgs, length);
+ unshift<JSArray::ShiftCountForShift>(exec, thisObj, 0, 0, nrArgs, length);
if (exec->hadException())
return JSValue::encode(jsUndefined());
}
diff --git a/Source/JavaScriptCore/runtime/ArrayStorage.h b/Source/JavaScriptCore/runtime/ArrayStorage.h
index 1ab936335..ffd84b281 100644
--- a/Source/JavaScriptCore/runtime/ArrayStorage.h
+++ b/Source/JavaScriptCore/runtime/ArrayStorage.h
@@ -41,6 +41,8 @@ namespace JSC {
// setStorage() methods. It is important to note that there may be space before the ArrayStorage that
// is used to quick unshift / shift operation. The actual allocated pointer is available by using:
// getStorage() - m_indexBias * sizeof(JSValue)
+// All slots in ArrayStorage (slots from 0 to vectorLength) are expected to be initialized to a JSValue or,
+// for hole slots, JSValue().
struct ArrayStorage {
WTF_MAKE_NONCOPYABLE(ArrayStorage);
private:
diff --git a/Source/JavaScriptCore/runtime/BooleanConstructor.cpp b/Source/JavaScriptCore/runtime/BooleanConstructor.cpp
index 9b666292c..0485350ce 100644
--- a/Source/JavaScriptCore/runtime/BooleanConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/BooleanConstructor.cpp
@@ -26,7 +26,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(BooleanConstructor);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(BooleanConstructor);
const ClassInfo BooleanConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(BooleanConstructor) };
diff --git a/Source/JavaScriptCore/runtime/BooleanObject.cpp b/Source/JavaScriptCore/runtime/BooleanObject.cpp
index bf2655bbb..355993864 100644
--- a/Source/JavaScriptCore/runtime/BooleanObject.cpp
+++ b/Source/JavaScriptCore/runtime/BooleanObject.cpp
@@ -25,7 +25,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(BooleanObject);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(BooleanObject);
const ClassInfo BooleanObject::s_info = { "Boolean", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(BooleanObject) };
diff --git a/Source/JavaScriptCore/runtime/BooleanPrototype.cpp b/Source/JavaScriptCore/runtime/BooleanPrototype.cpp
index c8c77220a..a331c6c15 100644
--- a/Source/JavaScriptCore/runtime/BooleanPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/BooleanPrototype.cpp
@@ -47,7 +47,6 @@ const ClassInfo BooleanPrototype::s_info = { "Boolean", &BooleanObject::s_info,
@end
*/
-ASSERT_CLASS_FITS_IN_CELL(BooleanPrototype);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(BooleanPrototype);
BooleanPrototype::BooleanPrototype(ExecState* exec, Structure* structure)
diff --git a/Source/JavaScriptCore/runtime/Butterfly.h b/Source/JavaScriptCore/runtime/Butterfly.h
index 1926169ba..cb93aea8a 100644
--- a/Source/JavaScriptCore/runtime/Butterfly.h
+++ b/Source/JavaScriptCore/runtime/Butterfly.h
@@ -35,7 +35,7 @@
namespace JSC {
class JSGlobalData;
-class SlotVisitor;
+class CopyVisitor;
struct ArrayStorage;
class Butterfly {
@@ -56,6 +56,15 @@ public:
return reinterpret_cast<Butterfly*>(static_cast<EncodedJSValue*>(base) + preCapacity + propertyCapacity + 1);
}
+ // This method is here not just because it's handy, but to remind you that
+ // the whole point of butterflies is to do evil pointer arithmetic.
+ static Butterfly* fromPointer(char* ptr)
+ {
+ return reinterpret_cast<Butterfly*>(ptr);
+ }
+
+ char* pointer() { return reinterpret_cast<char*>(this); }
+
static ptrdiff_t offsetOfIndexingHeader() { return IndexingHeader::offsetOfIndexingHeader(); }
static ptrdiff_t offsetOfPublicLength() { return offsetOfIndexingHeader() + IndexingHeader::offsetOfPublicLength(); }
static ptrdiff_t offsetOfVectorLength() { return offsetOfIndexingHeader() + IndexingHeader::offsetOfVectorLength(); }
@@ -64,15 +73,27 @@ public:
static Butterfly* create(JSGlobalData&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader&, size_t indexingPayloadSizeInBytes);
static Butterfly* create(JSGlobalData&, Structure*);
- static Butterfly* createUninitializedDuringCollection(SlotVisitor&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes);
+ static Butterfly* createUninitializedDuringCollection(CopyVisitor&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes);
IndexingHeader* indexingHeader() { return IndexingHeader::from(this); }
const IndexingHeader* indexingHeader() const { return IndexingHeader::from(this); }
PropertyStorage propertyStorage() { return indexingHeader()->propertyStorage(); }
ConstPropertyStorage propertyStorage() const { return indexingHeader()->propertyStorage(); }
+
+ uint32_t publicLength() { return indexingHeader()->publicLength(); }
+ uint32_t vectorLength() { return indexingHeader()->vectorLength(); }
+ void setPublicLength(uint32_t value) { indexingHeader()->setPublicLength(value); }
+ void setVectorLength(uint32_t value) { indexingHeader()->setVectorLength(value); }
+
template<typename T>
T* indexingPayload() { return reinterpret_cast<T*>(this); }
ArrayStorage* arrayStorage() { return indexingPayload<ArrayStorage>(); }
+ WriteBarrier<Unknown>* contiguous() { return indexingPayload<WriteBarrier<Unknown> >(); }
+
+ static Butterfly* fromContiguous(WriteBarrier<Unknown>* contiguous)
+ {
+ return reinterpret_cast<Butterfly*>(contiguous);
+ }
static ptrdiff_t offsetOfPropertyStorage() { return -static_cast<ptrdiff_t>(sizeof(IndexingHeader)); }
static int indexOfPropertyStorage()
diff --git a/Source/JavaScriptCore/runtime/ButterflyInlineMethods.h b/Source/JavaScriptCore/runtime/ButterflyInlineMethods.h
index 049350342..86a836bef 100644
--- a/Source/JavaScriptCore/runtime/ButterflyInlineMethods.h
+++ b/Source/JavaScriptCore/runtime/ButterflyInlineMethods.h
@@ -29,8 +29,8 @@
#include "ArrayStorage.h"
#include "Butterfly.h"
#include "CopiedSpaceInlineMethods.h"
+#include "CopyVisitor.h"
#include "JSGlobalData.h"
-#include "SlotVisitor.h"
#include "Structure.h"
namespace JSC {
@@ -59,7 +59,7 @@ inline Butterfly* Butterfly::create(JSGlobalData& globalData, Structure* structu
return create(globalData, 0, structure->outOfLineCapacity(), hasIndexingHeader(structure->indexingType()), IndexingHeader(), 0);
}
-inline Butterfly* Butterfly::createUninitializedDuringCollection(SlotVisitor& visitor, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes)
+inline Butterfly* Butterfly::createUninitializedDuringCollection(CopyVisitor& visitor, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes)
{
Butterfly* result = fromBase(
visitor.allocateNewSpace(totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes)),
@@ -144,7 +144,7 @@ inline Butterfly* Butterfly::resizeArray(JSGlobalData& globalData, Structure* st
inline Butterfly* Butterfly::unshift(Structure* structure, size_t numberOfSlots)
{
- ASSERT(hasIndexingHeader(structure->indexingType()));
+ ASSERT(hasArrayStorage(structure->indexingType()));
ASSERT(numberOfSlots <= indexingHeader()->preCapacity(structure));
unsigned propertyCapacity = structure->outOfLineCapacity();
// FIXME: It would probably be wise to rewrite this as a loop since (1) we know in which
@@ -163,7 +163,7 @@ inline Butterfly* Butterfly::unshift(Structure* structure, size_t numberOfSlots)
inline Butterfly* Butterfly::shift(Structure* structure, size_t numberOfSlots)
{
- ASSERT(hasIndexingHeader(structure->indexingType()));
+ ASSERT(hasArrayStorage(structure->indexingType()));
unsigned propertyCapacity = structure->outOfLineCapacity();
// FIXME: See comment in unshift(), above.
memmove(
diff --git a/Source/JavaScriptCore/runtime/ClassInfo.h b/Source/JavaScriptCore/runtime/ClassInfo.h
index e8823d571..c918621fe 100644
--- a/Source/JavaScriptCore/runtime/ClassInfo.h
+++ b/Source/JavaScriptCore/runtime/ClassInfo.h
@@ -39,6 +39,9 @@ namespace JSC {
typedef void (*VisitChildrenFunctionPtr)(JSCell*, SlotVisitor&);
VisitChildrenFunctionPtr visitChildren;
+ typedef void (*CopyBackingStoreFunctionPtr)(JSCell*, CopyVisitor&);
+ CopyBackingStoreFunctionPtr copyBackingStore;
+
typedef CallType (*GetCallDataFunctionPtr)(JSCell*, CallData&);
GetCallDataFunctionPtr getCallData;
@@ -116,6 +119,7 @@ struct MemberCheck##member { \
#define CREATE_METHOD_TABLE(ClassName) { \
&ClassName::destroy, \
&ClassName::visitChildren, \
+ &ClassName::copyBackingStore, \
&ClassName::getCallData, \
&ClassName::getConstructData, \
&ClassName::put, \
diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.h b/Source/JavaScriptCore/runtime/CommonSlowPaths.h
index 7edd9091c..2f5159461 100644
--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.h
+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.h
@@ -43,7 +43,7 @@ namespace JSC {
namespace CommonSlowPaths {
-ALWAYS_INLINE ExecState* arityCheckFor(ExecState* exec, RegisterFile* registerFile, CodeSpecializationKind kind)
+ALWAYS_INLINE ExecState* arityCheckFor(ExecState* exec, JSStack* stack, CodeSpecializationKind kind)
{
JSFunction* callee = jsCast<JSFunction*>(exec->callee());
ASSERT(!callee->isHostFunction());
@@ -51,7 +51,7 @@ ALWAYS_INLINE ExecState* arityCheckFor(ExecState* exec, RegisterFile* registerFi
int argumentCountIncludingThis = exec->argumentCountIncludingThis();
// This ensures enough space for the worst case scenario of zero arguments passed by the caller.
- if (!registerFile->grow(exec->registers() + newCodeBlock->numParameters() + newCodeBlock->m_numCalleeRegisters))
+ if (!stack->grow(exec->registers() + newCodeBlock->numParameters() + newCodeBlock->m_numCalleeRegisters))
return 0;
ASSERT(argumentCountIncludingThis < newCodeBlock->numParameters());
@@ -71,7 +71,7 @@ ALWAYS_INLINE ExecState* arityCheckFor(ExecState* exec, RegisterFile* registerFi
dst[i] = jsUndefined();
ExecState* newExec = ExecState::create(dst);
- ASSERT((void*)newExec <= registerFile->end());
+ ASSERT((void*)newExec <= stack->end());
return newExec;
}
diff --git a/Source/JavaScriptCore/runtime/DateConstructor.cpp b/Source/JavaScriptCore/runtime/DateConstructor.cpp
index e4f89dd37..f78e8bf55 100644
--- a/Source/JavaScriptCore/runtime/DateConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/DateConstructor.cpp
@@ -71,7 +71,6 @@ const ClassInfo DateConstructor::s_info = { "Function", &InternalFunction::s_inf
@end
*/
-ASSERT_CLASS_FITS_IN_CELL(DateConstructor);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(DateConstructor);
DateConstructor::DateConstructor(JSGlobalObject* globalObject, Structure* structure)
diff --git a/Source/JavaScriptCore/runtime/DatePrototype.cpp b/Source/JavaScriptCore/runtime/DatePrototype.cpp
index 9b2cb164f..75da466fb 100644
--- a/Source/JavaScriptCore/runtime/DatePrototype.cpp
+++ b/Source/JavaScriptCore/runtime/DatePrototype.cpp
@@ -70,8 +70,6 @@ using namespace WTF;
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(DatePrototype);
-
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*);
diff --git a/Source/JavaScriptCore/runtime/Error.cpp b/Source/JavaScriptCore/runtime/Error.cpp
index 27a729d0a..68ae12d90 100644
--- a/Source/JavaScriptCore/runtime/Error.cpp
+++ b/Source/JavaScriptCore/runtime/Error.cpp
@@ -177,8 +177,6 @@ JSObject* throwSyntaxError(ExecState* exec)
return throwError(exec, createSyntaxError(exec, ASCIILiteral("Syntax error")));
}
-ASSERT_CLASS_FITS_IN_CELL(StrictModeTypeErrorFunction);
-
const ClassInfo StrictModeTypeErrorFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(StrictModeTypeErrorFunction) };
void StrictModeTypeErrorFunction::destroy(JSCell* cell)
diff --git a/Source/JavaScriptCore/runtime/ErrorConstructor.cpp b/Source/JavaScriptCore/runtime/ErrorConstructor.cpp
index 96272d0cf..f2578a497 100644
--- a/Source/JavaScriptCore/runtime/ErrorConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/ErrorConstructor.cpp
@@ -27,7 +27,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(ErrorConstructor);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(ErrorConstructor);
const ClassInfo ErrorConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ErrorConstructor) };
diff --git a/Source/JavaScriptCore/runtime/ErrorPrototype.cpp b/Source/JavaScriptCore/runtime/ErrorPrototype.cpp
index 6c9d6df04..a30efdc31 100644
--- a/Source/JavaScriptCore/runtime/ErrorPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/ErrorPrototype.cpp
@@ -30,7 +30,7 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(ErrorPrototype);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(ErrorPrototype);
static EncodedJSValue JSC_HOST_CALL errorProtoFuncToString(ExecState*);
@@ -48,8 +48,6 @@ const ClassInfo ErrorPrototype::s_info = { "Error", &ErrorInstance::s_info, 0, E
@end
*/
-ASSERT_CLASS_FITS_IN_CELL(ErrorPrototype);
-
ErrorPrototype::ErrorPrototype(ExecState* exec, Structure* structure)
: ErrorInstance(exec->globalData(), structure)
{
diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h
index 6eeda3a82..76a537da3 100644
--- a/Source/JavaScriptCore/runtime/Executable.h
+++ b/Source/JavaScriptCore/runtime/Executable.h
@@ -81,6 +81,8 @@ namespace JSC {
typedef JSCell Base;
#if ENABLE(JIT)
+ static const bool needsDestruction = true;
+ static const bool hasImmortalStructure = true;
static void destroy(JSCell*);
#endif
diff --git a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp
index 570444e3c..bf74c0a97 100644
--- a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp
@@ -34,7 +34,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(FunctionConstructor);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(FunctionConstructor);
const ClassInfo FunctionConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionConstructor) };
diff --git a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp
index dd1628b29..a4b2202c1 100644
--- a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp
@@ -32,7 +32,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(FunctionPrototype);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(FunctionPrototype);
const ClassInfo FunctionPrototype::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionPrototype) };
diff --git a/Source/JavaScriptCore/runtime/Identifier.cpp b/Source/JavaScriptCore/runtime/Identifier.cpp
index a9a2a66bf..45dd0bbde 100644
--- a/Source/JavaScriptCore/runtime/Identifier.cpp
+++ b/Source/JavaScriptCore/runtime/Identifier.cpp
@@ -30,6 +30,7 @@
#include <wtf/Assertions.h>
#include <wtf/FastMalloc.h>
#include <wtf/HashSet.h>
+#include <wtf/text/ASCIIFastPath.h>
#include <wtf/text/StringHash.h>
using WTF::ThreadSpecific;
@@ -80,11 +81,7 @@ struct IdentifierLCharFromUCharTranslator {
{
LChar* d;
StringImpl* r = StringImpl::createUninitialized(buf.length, d).leakRef();
- for (unsigned i = 0; i != buf.length; i++) {
- UChar c = buf.s[i];
- ASSERT(c <= 0xff);
- d[i] = c;
- }
+ WTF::copyLCharsFromUCharSource(d, buf.s, buf.length);
r->setHash(hash);
location = r;
}
@@ -102,7 +99,7 @@ PassRefPtr<StringImpl> Identifier::add(JSGlobalData* globalData, const char* c)
const LiteralIdentifierTable::iterator& iter = literalIdentifierTable.find(c);
if (iter != literalIdentifierTable.end())
- return iter->second;
+ return iter->value;
HashSet<StringImpl*>::AddResult addResult = identifierTable.add<const LChar*, IdentifierASCIIStringTranslator>(reinterpret_cast<const LChar*>(c));
diff --git a/Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h b/Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h
index e1d893b0b..22785ce24 100644
--- a/Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h
+++ b/Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h
@@ -42,10 +42,17 @@ inline size_t IndexingHeader::preCapacity(Structure* structure)
inline size_t IndexingHeader::indexingPayloadSizeInBytes(Structure* structure)
{
- if (LIKELY(!hasArrayStorage(structure->indexingType())))
+ switch (structure->indexingType()) {
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ return vectorLength() * sizeof(EncodedJSValue);
+
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ return ArrayStorage::sizeFor(arrayStorage()->vectorLength());
+
+ default:
+ ASSERT(!hasIndexedProperties(structure->indexingType()));
return 0;
-
- return ArrayStorage::sizeFor(arrayStorage()->vectorLength());
+ }
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/IndexingType.cpp b/Source/JavaScriptCore/runtime/IndexingType.cpp
new file mode 100644
index 000000000..7261847a2
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IndexingType.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "config.h"
+#include "IndexingType.h"
+
+#include <stdio.h>
+#include <wtf/StringExtras.h>
+
+namespace JSC {
+
+const char* indexingTypeToString(IndexingType indexingType)
+{
+ static char result[128];
+ const char* basicName;
+ switch (indexingType & AllArrayTypes) {
+ case NonArray:
+ basicName = "NonArray";
+ break;
+ case NonArrayWithContiguous:
+ basicName = "NonArrayWithContiguous";
+ break;
+ case NonArrayWithArrayStorage:
+ basicName = "NonArrayWithArrayStorage";
+ break;
+ case NonArrayWithSlowPutArrayStorage:
+ basicName = "NonArrayWithSlowPutArrayStorage";
+ break;
+ case ArrayClass:
+ basicName = "ArrayClass";
+ break;
+ case ArrayWithContiguous:
+ basicName = "ArrayWithContiguous";
+ break;
+ case ArrayWithArrayStorage:
+ basicName = "ArrayWithArrayStorage";
+ break;
+ case ArrayWithSlowPutArrayStorage:
+ basicName = "ArrayWithSlowPutArrayStorage";
+ break;
+ default:
+ basicName = "Unknown!";
+ break;
+ }
+
+ snprintf(
+ result, sizeof(result), "%s%s", basicName,
+ (indexingType & MayHaveIndexedAccessors) ? "|MayHaveIndexedAccessors" : "");
+
+ return result;
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/runtime/IndexingType.h b/Source/JavaScriptCore/runtime/IndexingType.h
index 3b97230ea..4bbe3cfa0 100644
--- a/Source/JavaScriptCore/runtime/IndexingType.h
+++ b/Source/JavaScriptCore/runtime/IndexingType.h
@@ -26,32 +26,44 @@
#ifndef IndexingType_h
#define IndexingType_h
+#include <wtf/StdLibExtras.h>
+
namespace JSC {
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;
+
+// The shape of the indexed property storage.
+static const IndexingType IndexingShapeMask = 30;
+static const IndexingType NoIndexingShape = 0;
+static const IndexingType ContiguousShape = 26;
+static const IndexingType ArrayStorageShape = 28;
+static const IndexingType SlowPutArrayStorageShape = 30;
// Additional flags for tracking the history of the type. These are usually
// masked off unless you ask for them directly.
-static const IndexingType HadArrayStorage = 32; // Means that this object did have array storage in the past.
-static const IndexingType MayHaveIndexedAccessors = 64;
+static const IndexingType MayHaveIndexedAccessors = 32;
// List of acceptable array types.
static const IndexingType NonArray = 0;
-static const IndexingType NonArrayWithArrayStorage = HasArrayStorage;
-static const IndexingType NonArrayWithSlowPutArrayStorage = HasSlowPutArrayStorage;
+static const IndexingType NonArrayWithContiguous = ContiguousShape;
+static const IndexingType NonArrayWithArrayStorage = ArrayStorageShape;
+static const IndexingType NonArrayWithSlowPutArrayStorage = SlowPutArrayStorageShape;
static const IndexingType ArrayClass = IsArray; // I'd want to call this "Array" but this would lead to disastrous namespace pollution.
-static const IndexingType ArrayWithArrayStorage = IsArray | HasArrayStorage;
-static const IndexingType ArrayWithSlowPutArrayStorage = IsArray | HasSlowPutArrayStorage;
+static const IndexingType ArrayWithContiguous = IsArray | ContiguousShape;
+static const IndexingType ArrayWithArrayStorage = IsArray | ArrayStorageShape;
+static const IndexingType ArrayWithSlowPutArrayStorage = IsArray | SlowPutArrayStorageShape;
#define ALL_BLANK_INDEXING_TYPES \
NonArray: \
case ArrayClass
+#define ALL_CONTIGUOUS_INDEXING_TYPES \
+ NonArrayWithContiguous: \
+ case ArrayWithContiguous
+
#define ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES \
ArrayWithArrayStorage: \
case ArrayWithSlowPutArrayStorage
@@ -63,12 +75,7 @@ static const IndexingType ArrayWithSlowPutArrayStorage = IsArray | HasSlowPut
static inline bool hasIndexedProperties(IndexingType indexingType)
{
- switch (indexingType) {
- case ALL_BLANK_INDEXING_TYPES:
- return false;
- default:
- return true;
- }
+ return (indexingType & IndexingShapeMask) != NoIndexingShape;
}
static inline bool hasIndexingHeader(IndexingType type)
@@ -76,16 +83,30 @@ static inline bool hasIndexingHeader(IndexingType type)
return hasIndexedProperties(type);
}
+static inline bool hasContiguous(IndexingType indexingType)
+{
+ return (indexingType & IndexingShapeMask) == ContiguousShape;
+}
+
+// FIXME: This is an awkward name. This should really be called hasArrayStorage()
+// and then next method down should be called hasAnyArrayStorage().
+static inline bool hasFastArrayStorage(IndexingType indexingType)
+{
+ return (indexingType & IndexingShapeMask) == ArrayStorageShape;
+}
+
static inline bool hasArrayStorage(IndexingType indexingType)
{
- return !!(indexingType & (HasArrayStorage | HasSlowPutArrayStorage));
+ return static_cast<uint8_t>((indexingType & IndexingShapeMask) - ArrayStorageShape) <= static_cast<uint8_t>(SlowPutArrayStorageShape - ArrayStorageShape);
}
static inline bool shouldUseSlowPut(IndexingType indexingType)
{
- return !!(indexingType & HasSlowPutArrayStorage);
+ return (indexingType & IndexingShapeMask) == SlowPutArrayStorageShape;
}
+const char* indexingTypeToString(IndexingType);
+
// Mask of all possible types.
static const IndexingType AllArrayTypes = 31;
diff --git a/Source/JavaScriptCore/runtime/InitializeThreading.cpp b/Source/JavaScriptCore/runtime/InitializeThreading.cpp
index 1a7239f60..1a6c84514 100644
--- a/Source/JavaScriptCore/runtime/InitializeThreading.cpp
+++ b/Source/JavaScriptCore/runtime/InitializeThreading.cpp
@@ -31,6 +31,7 @@
#include "ExecutableAllocator.h"
#include "Heap.h"
+#include "HeapStatistics.h"
#include "Options.h"
#include "Identifier.h"
#include "JSDateMath.h"
@@ -56,13 +57,15 @@ static void initializeThreadingOnce()
WTF::initializeThreading();
GlobalJSLock::initialize();
Options::initialize();
+ if (Options::recordGCPauseTimes())
+ HeapStatistics::initialize();
#if ENABLE(WRITE_BARRIER_PROFILING)
WriteBarrierCounters::initialize();
#endif
#if ENABLE(ASSEMBLER)
ExecutableAllocator::initializeAllocator();
#endif
- RegisterFile::initializeThreading();
+ JSStack::initializeThreading();
#if ENABLE(LLINT)
LLInt::initialize();
#endif
diff --git a/Source/JavaScriptCore/runtime/InternalFunction.cpp b/Source/JavaScriptCore/runtime/InternalFunction.cpp
index e2de03d92..afb5e6317 100644
--- a/Source/JavaScriptCore/runtime/InternalFunction.cpp
+++ b/Source/JavaScriptCore/runtime/InternalFunction.cpp
@@ -29,13 +29,12 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(InternalFunction);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(InternalFunction);
-const ClassInfo InternalFunction::s_info = { "Function", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(InternalFunction) };
+const ClassInfo InternalFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(InternalFunction) };
InternalFunction::InternalFunction(JSGlobalObject* globalObject, Structure* structure)
- : JSNonFinalObject(globalObject->globalData(), structure)
+ : JSDestructibleObject(globalObject->globalData(), structure)
{
}
diff --git a/Source/JavaScriptCore/runtime/InternalFunction.h b/Source/JavaScriptCore/runtime/InternalFunction.h
index e26b9f953..daeebc34d 100644
--- a/Source/JavaScriptCore/runtime/InternalFunction.h
+++ b/Source/JavaScriptCore/runtime/InternalFunction.h
@@ -24,16 +24,16 @@
#ifndef InternalFunction_h
#define InternalFunction_h
-#include "JSObject.h"
#include "Identifier.h"
+#include "JSDestructibleObject.h"
namespace JSC {
class FunctionPrototype;
- class InternalFunction : public JSNonFinalObject {
+ class InternalFunction : public JSDestructibleObject {
public:
- typedef JSNonFinalObject Base;
+ typedef JSDestructibleObject Base;
static JS_EXPORTDATA const ClassInfo s_info;
diff --git a/Source/JavaScriptCore/runtime/JSActivation.cpp b/Source/JavaScriptCore/runtime/JSActivation.cpp
index c34e10bc8..3b665962f 100644
--- a/Source/JavaScriptCore/runtime/JSActivation.cpp
+++ b/Source/JavaScriptCore/runtime/JSActivation.cpp
@@ -37,8 +37,6 @@ using namespace std;
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(JSActivation);
-
const ClassInfo JSActivation::s_info = { "JSActivation", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSActivation) };
void JSActivation::visitChildren(JSCell* cell, SlotVisitor& visitor)
@@ -49,7 +47,7 @@ void JSActivation::visitChildren(JSCell* cell, SlotVisitor& visitor)
ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
Base::visitChildren(thisObject, visitor);
- // No need to mark our registers if they're still in the RegisterFile.
+ // No need to mark our registers if they're still in the JSStack.
if (!thisObject->isTornOff())
return;
@@ -116,11 +114,11 @@ void JSActivation::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec
SymbolTable::const_iterator end = thisObject->symbolTable()->end();
for (SymbolTable::const_iterator it = thisObject->symbolTable()->begin(); it != end; ++it) {
- if (it->second.getAttributes() & DontEnum && mode != IncludeDontEnumProperties)
+ if (it->value.getAttributes() & DontEnum && mode != IncludeDontEnumProperties)
continue;
- if (!thisObject->isValid(it->second))
+ if (!thisObject->isValid(it->value))
continue;
- propertyNames.add(Identifier(exec, it->first.get()));
+ propertyNames.add(Identifier(exec, it->key.get()));
}
// Skip the JSVariableObject implementation of getOwnNonIndexPropertyNames
JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode);
@@ -133,7 +131,7 @@ inline bool JSActivation::symbolTablePutWithAttributes(JSGlobalData& globalData,
SymbolTable::iterator iter = symbolTable()->find(propertyName.publicName());
if (iter == symbolTable()->end())
return false;
- SymbolTableEntry& entry = iter->second;
+ SymbolTableEntry& entry = iter->value;
ASSERT(!entry.isNull());
if (!isValid(entry))
return false;
diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp
index 8398ae77d..7028c3b95 100644
--- a/Source/JavaScriptCore/runtime/JSArray.cpp
+++ b/Source/JavaScriptCore/runtime/JSArray.cpp
@@ -44,8 +44,6 @@ using namespace WTF;
namespace JSC {
-
-ASSERT_CLASS_FITS_IN_CELL(JSArray);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSArray);
const ClassInfo JSArray::s_info = {"Array", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSArray)};
@@ -245,8 +243,8 @@ void JSArray::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, Pro
JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode);
}
-// This method makes room in the vector, but leaves the new space uncleared.
-bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, unsigned count)
+// This method makes room in the vector, but leaves the new space for count slots uncleared.
+bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, bool addToFront, unsigned count)
{
ArrayStorage* storage = ensureArrayStorage(globalData);
Butterfly* butterfly = storage->butterfly();
@@ -254,7 +252,7 @@ bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, unsigned count)
unsigned propertySize = structure()->outOfLineSize();
// If not, we should have handled this on the fast path.
- ASSERT(count > storage->m_indexBias);
+ ASSERT(!addToFront || count > storage->m_indexBias);
// Step 1:
// Gather 4 key metrics:
@@ -278,7 +276,7 @@ bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, unsigned count)
unsigned desiredCapacity = min(MAX_STORAGE_VECTOR_LENGTH, max(BASE_VECTOR_LEN, requiredVectorLength) << 1);
// Step 2:
- // We're either going to choose to allocate a new ArrayStorage, or we're going to reuse the existing on.
+ // We're either going to choose to allocate a new ArrayStorage, or we're going to reuse the existing one.
void* newAllocBase = 0;
unsigned newStorageCapacity;
@@ -297,36 +295,48 @@ bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, unsigned count)
// Work out where we're going to move things to.
// Determine how much of the vector to use as pre-capacity, and how much as post-capacity.
+ // If we're adding to the end, we'll add all the new space to the end.
// If the vector had no free post-capacity (length >= m_vectorLength), don't give it any.
// If it did, we calculate the amount that will remain based on an atomic decay - leave the
// vector with half the post-capacity it had previously.
unsigned postCapacity = 0;
- if (length < storage->vectorLength()) {
+ if (!addToFront)
+ postCapacity = max(newStorageCapacity - requiredVectorLength, count);
+ else if (length < storage->vectorLength()) {
// Atomic decay, + the post-capacity cannot be greater than what is available.
postCapacity = min((storage->vectorLength() - length) >> 1, newStorageCapacity - requiredVectorLength);
// If we're moving contents within the same allocation, the post-capacity is being reduced.
ASSERT(newAllocBase != butterfly->base(structure()) || postCapacity < storage->vectorLength() - length);
}
-
+
unsigned newVectorLength = requiredVectorLength + postCapacity;
unsigned newIndexBias = newStorageCapacity - newVectorLength;
Butterfly* newButterfly = Butterfly::fromBase(newAllocBase, newIndexBias, propertyCapacity);
-
- memmove(newButterfly->arrayStorage()->m_vector + count, storage->m_vector, sizeof(JSValue) * usedVectorLength);
- memmove(newButterfly->propertyStorage() - propertySize, butterfly->propertyStorage() - propertySize, sizeof(JSValue) * propertySize + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0));
-
+
+ if (addToFront) {
+ ASSERT(count + usedVectorLength <= newVectorLength);
+ memmove(newButterfly->arrayStorage()->m_vector + count, storage->m_vector, sizeof(JSValue) * usedVectorLength);
+ memmove(newButterfly->propertyStorage() - propertySize, butterfly->propertyStorage() - propertySize, sizeof(JSValue) * propertySize + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0));
+ } else if ((newAllocBase != butterfly->base(structure())) || (newIndexBias != storage->m_indexBias)) {
+ memmove(newButterfly->propertyStorage() - propertySize, butterfly->propertyStorage() - propertySize, sizeof(JSValue) * propertySize + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0));
+ memmove(newButterfly->arrayStorage()->m_vector, storage->m_vector, sizeof(JSValue) * usedVectorLength);
+
+ WriteBarrier<Unknown>* newVector = newButterfly->arrayStorage()->m_vector;
+ for (unsigned i = requiredVectorLength; i < newVectorLength; i++)
+ newVector[i].clear();
+ }
+
newButterfly->arrayStorage()->setVectorLength(newVectorLength);
newButterfly->arrayStorage()->m_indexBias = newIndexBias;
-
+
m_butterfly = newButterfly;
return true;
}
-bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException)
+bool JSArray::setLengthWithArrayStorage(ExecState* exec, unsigned newLength, bool throwException, ArrayStorage* storage)
{
- ArrayStorage* storage = ensureArrayStorage(exec->globalData());
unsigned length = storage->length();
// If the length is read only then we enter sparse mode, so should enter the following 'if'.
@@ -343,7 +353,7 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException
keys.reserveCapacity(min(map->size(), static_cast<size_t>(length - newLength)));
SparseArrayValueMap::const_iterator end = map->end();
for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) {
- unsigned index = static_cast<unsigned>(it->first);
+ unsigned index = static_cast<unsigned>(it->key);
if (index < length && index >= newLength)
keys.append(index);
}
@@ -358,7 +368,7 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException
unsigned index = keys[--i];
SparseArrayValueMap::iterator it = map->find(index);
ASSERT(it != map->notFound());
- if (it->second.attributes & DontDelete) {
+ if (it->value.attributes & DontDelete) {
storage->setLength(index + 1);
return reject(exec, throwException, "Unable to delete property.");
}
@@ -389,12 +399,71 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException
return true;
}
+bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException)
+{
+ switch (structure()->indexingType()) {
+ case ArrayClass:
+ if (!newLength)
+ return true;
+ if (newLength >= MIN_SPARSE_ARRAY_INDEX) {
+ return setLengthWithArrayStorage(
+ exec, newLength, throwException,
+ convertContiguousToArrayStorage(exec->globalData()));
+ }
+ createInitialContiguous(exec->globalData(), newLength);
+ return true;
+
+ case ArrayWithContiguous:
+ if (newLength == m_butterfly->publicLength())
+ return true;
+ if (newLength >= MAX_ARRAY_INDEX // This case ensures that we can do fast push.
+ || (newLength >= MIN_SPARSE_ARRAY_INDEX
+ && !isDenseEnoughForVector(newLength, countElementsInContiguous(m_butterfly)))) {
+ return setLengthWithArrayStorage(
+ exec, newLength, throwException,
+ convertContiguousToArrayStorage(exec->globalData()));
+ }
+ if (newLength > m_butterfly->publicLength()) {
+ ensureContiguousLength(exec->globalData(), newLength);
+ return true;
+ }
+ for (unsigned i = m_butterfly->publicLength(); i-- > newLength;)
+ m_butterfly->contiguous()[i].clear();
+ m_butterfly->setPublicLength(newLength);
+ return true;
+
+ case ArrayWithArrayStorage:
+ case ArrayWithSlowPutArrayStorage:
+ return setLengthWithArrayStorage(exec, newLength, throwException, arrayStorage());
+
+ default:
+ CRASH();
+ return false;
+ }
+}
+
JSValue JSArray::pop(ExecState* exec)
{
switch (structure()->indexingType()) {
case ArrayClass:
return jsUndefined();
+ case ArrayWithContiguous: {
+ unsigned length = m_butterfly->publicLength();
+
+ if (!length--)
+ return jsUndefined();
+
+ ASSERT(length < m_butterfly->vectorLength());
+ JSValue value = m_butterfly->contiguous()[length].get();
+ if (value) {
+ m_butterfly->contiguous()[length].clear();
+ m_butterfly->setPublicLength(length);
+ return value;
+ }
+ break;
+ }
+
case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = m_butterfly->arrayStorage();
@@ -418,26 +487,28 @@ JSValue JSArray::pop(ExecState* exec)
return element;
}
}
-
- // Let element be the result of calling the [[Get]] internal method of O with argument indx.
- JSValue element = get(exec, index);
- if (exec->hadException())
- return jsUndefined();
- // Call the [[Delete]] internal method of O with arguments indx and true.
- if (!deletePropertyByIndex(this, exec, index)) {
- throwTypeError(exec, "Unable to delete property.");
- return jsUndefined();
- }
- // Call the [[Put]] internal method of O with arguments "length", indx, and true.
- setLength(exec, index, true);
- // Return element.
- return element;
+ break;
}
default:
- ASSERT_NOT_REACHED();
+ CRASH();
return JSValue();
}
+
+ unsigned index = getArrayLength() - 1;
+ // Let element be the result of calling the [[Get]] internal method of O with argument indx.
+ JSValue element = get(exec, index);
+ if (exec->hadException())
+ return jsUndefined();
+ // Call the [[Delete]] internal method of O with arguments indx and true.
+ if (!deletePropertyByIndex(this, exec, index)) {
+ throwTypeError(exec, "Unable to delete property.");
+ return jsUndefined();
+ }
+ // Call the [[Put]] internal method of O with arguments "length", indx, and true.
+ setLength(exec, index, true);
+ // Return element.
+ return element;
}
// Push & putIndex are almost identical, with two small differences.
@@ -451,6 +522,26 @@ void JSArray::push(ExecState* exec, JSValue value)
break;
}
+ case ArrayWithContiguous: {
+ unsigned length = m_butterfly->publicLength();
+ ASSERT(length <= m_butterfly->vectorLength());
+ if (length < m_butterfly->vectorLength()) {
+ m_butterfly->contiguous()[length].set(exec->globalData(), this, value);
+ m_butterfly->setPublicLength(length + 1);
+ return;
+ }
+
+ if (length > MAX_ARRAY_INDEX) {
+ methodTable()->putByIndex(this, exec, length, value, true);
+ if (!exec->hadException())
+ throwError(exec, createRangeError(exec, "Invalid array length"));
+ return;
+ }
+
+ putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, length, value);
+ return;
+ }
+
case ArrayWithSlowPutArrayStorage: {
unsigned oldLength = length();
if (attemptToInterceptPutByIndexOnHole(exec, oldLength, value, true)) {
@@ -492,59 +583,139 @@ void JSArray::push(ExecState* exec, JSValue value)
}
}
-bool JSArray::shiftCount(ExecState* exec, unsigned count)
+bool JSArray::shiftCountWithArrayStorage(unsigned startIndex, unsigned count, ArrayStorage* storage)
{
- ASSERT(count > 0);
-
- ArrayStorage* storage = ensureArrayStorage(exec->globalData());
-
unsigned oldLength = storage->length();
ASSERT(count <= oldLength);
// If the array contains holes or is otherwise in an abnormal state,
// use the generic algorithm in ArrayPrototype.
- if (oldLength != storage->m_numValuesInVector || inSparseIndexingMode())
+ if (oldLength != storage->m_numValuesInVector || inSparseIndexingMode() || shouldUseSlowPut(structure()->indexingType()))
return false;
if (!oldLength)
return true;
+ unsigned length = oldLength - count;
+
storage->m_numValuesInVector -= count;
- storage->setLength(oldLength - count);
+ storage->setLength(length);
unsigned vectorLength = storage->vectorLength();
+ if (!vectorLength)
+ return true;
+
+ if (startIndex >= vectorLength)
+ return true;
+
+ if (startIndex + count > vectorLength)
+ count = vectorLength - startIndex;
+
+ unsigned usedVectorLength = min(vectorLength, oldLength);
+
+ vectorLength -= count;
+ storage->setVectorLength(vectorLength);
+
if (vectorLength) {
- count = min(vectorLength, (unsigned)count);
-
- vectorLength -= count;
- storage->setVectorLength(vectorLength);
-
- if (vectorLength) {
+ if (startIndex < usedVectorLength - (startIndex + count)) {
+ if (startIndex) {
+ memmove(
+ storage->m_vector + count,
+ storage->m_vector,
+ sizeof(JSValue) * startIndex);
+ }
m_butterfly = m_butterfly->shift(structure(), count);
storage = m_butterfly->arrayStorage();
storage->m_indexBias += count;
+ } else {
+ memmove(
+ storage->m_vector + startIndex,
+ storage->m_vector + startIndex + count,
+ sizeof(JSValue) * (usedVectorLength - (startIndex + count)));
+ for (unsigned i = usedVectorLength - count; i < usedVectorLength; ++i)
+ storage->m_vector[i].clear();
}
}
return true;
}
+bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex, unsigned count)
+{
+ ASSERT(count > 0);
+
+ switch (structure()->indexingType()) {
+ case ArrayClass:
+ return true;
+
+ case ArrayWithContiguous: {
+ unsigned oldLength = m_butterfly->publicLength();
+ ASSERT(count <= oldLength);
+
+ // We may have to walk the entire array to do the shift. We're willing to do
+ // so only if it's not horribly slow.
+ if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX)
+ return shiftCountWithArrayStorage(startIndex, count, convertContiguousToArrayStorage(exec->globalData()));
+
+ unsigned end = oldLength - count;
+ for (unsigned i = startIndex; i < end; ++i) {
+ // Storing to a hole is fine since we're still having a good time. But reading
+ // from a hole is totally not fine, since we might have to read from the proto
+ // chain.
+ JSValue v = m_butterfly->contiguous()[i + count].get();
+ if (UNLIKELY(!v)) {
+ // The purpose of this path is to ensure that we don't make the same
+ // mistake in the future: shiftCountWithArrayStorage() can't do anything
+ // about holes (at least for now), but it can detect them quickly. So
+ // we convert to array storage and then allow the array storage path to
+ // figure it out.
+ return shiftCountWithArrayStorage(startIndex, count, convertContiguousToArrayStorage(exec->globalData()));
+ }
+ // No need for a barrier since we're just moving data around in the same vector.
+ // This is in line with our standing assumption that we won't have a deletion
+ // barrier.
+ m_butterfly->contiguous()[i].setWithoutWriteBarrier(v);
+ }
+ for (unsigned i = end; i < oldLength; ++i)
+ m_butterfly->contiguous()[i].clear();
+
+ m_butterfly->setPublicLength(oldLength - count);
+ return true;
+ }
+
+ case ArrayWithArrayStorage:
+ case ArrayWithSlowPutArrayStorage:
+ return shiftCountWithArrayStorage(startIndex, count, arrayStorage());
+
+ default:
+ CRASH();
+ return false;
+ }
+}
+
// Returns true if the unshift can be handled, false to fallback.
-bool JSArray::unshiftCount(ExecState* exec, unsigned count)
+bool JSArray::unshiftCountWithArrayStorage(ExecState* exec, unsigned startIndex, unsigned count, ArrayStorage* storage)
{
- ArrayStorage* storage = ensureArrayStorage(exec->globalData());
unsigned length = storage->length();
+ ASSERT(startIndex <= length);
+
// If the array contains holes or is otherwise in an abnormal state,
// use the generic algorithm in ArrayPrototype.
- if (length != storage->m_numValuesInVector || storage->inSparseMode())
+ if (length != storage->m_numValuesInVector || storage->inSparseMode() || shouldUseSlowPut(structure()->indexingType()))
return false;
- if (storage->m_indexBias >= count) {
+ bool moveFront = !startIndex || startIndex < length / 2;
+
+ unsigned vectorLength = storage->vectorLength();
+
+ if (moveFront && storage->m_indexBias >= count) {
m_butterfly = storage->butterfly()->unshift(structure(), count);
storage = m_butterfly->arrayStorage();
storage->m_indexBias -= count;
- storage->setVectorLength(storage->vectorLength() + count);
- } else if (unshiftCountSlowCase(exec->globalData(), count))
+ storage->setVectorLength(vectorLength + count);
+ } else if (!moveFront && vectorLength - length >= count)
+ storage = storage->butterfly()->arrayStorage();
+ else if (unshiftCountSlowCase(exec->globalData(), moveFront, count))
storage = arrayStorage();
else {
throwOutOfMemoryError(exec);
@@ -552,11 +723,61 @@ bool JSArray::unshiftCount(ExecState* exec, unsigned count)
}
WriteBarrier<Unknown>* vector = storage->m_vector;
+
+ if (startIndex) {
+ if (moveFront)
+ memmove(vector, vector + count, startIndex * sizeof(JSValue));
+ else if (length - startIndex)
+ memmove(vector + startIndex + count, vector + startIndex, (length - startIndex) * sizeof(JSValue));
+ }
+
for (unsigned i = 0; i < count; i++)
- vector[i].clear();
+ vector[i + startIndex].clear();
return true;
}
+bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex, unsigned count)
+{
+ switch (structure()->indexingType()) {
+ case ArrayClass:
+ // We could handle this. But it shouldn't ever come up, so we won't.
+ return false;
+
+ case ArrayWithContiguous: {
+ unsigned oldLength = m_butterfly->publicLength();
+
+ // We may have to walk the entire array to do the unshift. We're willing to do so
+ // only if it's not horribly slow.
+ if (oldLength - startIndex >= MIN_SPARSE_ARRAY_INDEX)
+ return unshiftCountWithArrayStorage(exec, startIndex, count, convertContiguousToArrayStorage(exec->globalData()));
+
+ ensureContiguousLength(exec->globalData(), oldLength + count);
+
+ for (unsigned i = oldLength; i-- > startIndex;) {
+ JSValue v = m_butterfly->contiguous()[i].get();
+ if (UNLIKELY(!v))
+ return unshiftCountWithArrayStorage(exec, startIndex, count, convertContiguousToArrayStorage(exec->globalData()));
+ m_butterfly->contiguous()[i + count].setWithoutWriteBarrier(v);
+ }
+
+ // NOTE: we're leaving being garbage in the part of the array that we shifted out
+ // of. This is fine because the caller is required to store over that area, and
+ // in contiguous mode storing into a hole is guaranteed to behave exactly the same
+ // as storing over an existing element.
+
+ return true;
+ }
+
+ case ArrayWithArrayStorage:
+ case ArrayWithSlowPutArrayStorage:
+ return unshiftCountWithArrayStorage(exec, startIndex, count, arrayStorage());
+
+ default:
+ CRASH();
+ return false;
+ }
+}
+
static int compareNumbersForQSort(const void* a, const void* b)
{
double da = static_cast<const JSValue*>(a)->asNumber();
@@ -571,6 +792,45 @@ static int compareByStringPairForQSort(const void* a, const void* b)
return codePointCompare(va->second, vb->second);
}
+template<IndexingType indexingType>
+void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
+{
+ ASSERT(indexingType == ArrayWithContiguous || indexingType == ArrayWithArrayStorage);
+
+ unsigned lengthNotIncludingUndefined;
+ unsigned newRelevantLength;
+ compactForSorting<indexingType>(
+ lengthNotIncludingUndefined,
+ newRelevantLength);
+
+ WriteBarrier<Unknown>* data = indexingData<indexingType>();
+
+ if (indexingType == ArrayWithArrayStorage && arrayStorage()->m_sparseMap.get()) {
+ throwOutOfMemoryError(exec);
+ return;
+ }
+
+ if (!lengthNotIncludingUndefined)
+ return;
+
+ bool allValuesAreNumbers = true;
+ for (size_t i = 0; i < newRelevantLength; ++i) {
+ if (!data[i].isNumber()) {
+ allValuesAreNumbers = false;
+ break;
+ }
+ }
+
+ if (!allValuesAreNumbers)
+ return sort(exec, compareFunction, callType, callData);
+
+ // For numeric comparison, which is fast, qsort is faster than mergesort. We
+ // also don't require mergesort's stability, since there's no user visible
+ // side-effect from swapping the order of equal primitive values.
+ qsort(data, newRelevantLength, sizeof(WriteBarrier<Unknown>), compareNumbersForQSort);
+ return;
+}
+
void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
{
ASSERT(!inSparseIndexingMode());
@@ -579,123 +839,129 @@ void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType cal
case ArrayClass:
return;
- case ArrayWithArrayStorage: {
- unsigned lengthNotIncludingUndefined = compactForSorting(exec->globalData());
- ArrayStorage* storage = m_butterfly->arrayStorage();
-
- if (storage->m_sparseMap.get()) {
- throwOutOfMemoryError(exec);
- return;
- }
-
- if (!lengthNotIncludingUndefined)
- return;
-
- bool allValuesAreNumbers = true;
- size_t size = storage->m_numValuesInVector;
- for (size_t i = 0; i < size; ++i) {
- if (!storage->m_vector[i].isNumber()) {
- allValuesAreNumbers = false;
- break;
- }
- }
-
- if (!allValuesAreNumbers)
- return sort(exec, compareFunction, callType, callData);
-
- // For numeric comparison, which is fast, qsort is faster than mergesort. We
- // also don't require mergesort's stability, since there's no user visible
- // side-effect from swapping the order of equal primitive values.
- qsort(storage->m_vector, size, sizeof(WriteBarrier<Unknown>), compareNumbersForQSort);
-
+ case ArrayWithContiguous:
+ sortNumericVector<ArrayWithContiguous>(exec, compareFunction, callType, callData);
+ return;
+
+ case ArrayWithArrayStorage:
+ sortNumericVector<ArrayWithArrayStorage>(exec, compareFunction, callType, callData);
return;
- }
default:
- ASSERT_NOT_REACHED();
+ CRASH();
+ return;
}
}
-void JSArray::sort(ExecState* exec)
+template<IndexingType indexingType>
+void JSArray::sortCompactedVector(ExecState* exec, WriteBarrier<Unknown>* begin, unsigned relevantLength)
{
- ASSERT(!inSparseIndexingMode());
-
- switch (structure()->indexingType()) {
- case ArrayClass:
+ if (!relevantLength)
return;
+
+ JSGlobalData& globalData = exec->globalData();
+
+ // Converting JavaScript values to strings can be expensive, so we do it once up front and sort based on that.
+ // This is a considerable improvement over doing it twice per comparison, though it requires a large temporary
+ // buffer. Besides, this protects us from crashing if some objects have custom toString methods that return
+ // random or otherwise changing results, effectively making compare function inconsistent.
- case ArrayWithArrayStorage: {
- unsigned lengthNotIncludingUndefined = compactForSorting(exec->globalData());
- ArrayStorage* storage = m_butterfly->arrayStorage();
- if (storage->m_sparseMap.get()) {
- throwOutOfMemoryError(exec);
- return;
- }
-
- if (!lengthNotIncludingUndefined)
- return;
-
- // Converting JavaScript values to strings can be expensive, so we do it once up front and sort based on that.
- // This is a considerable improvement over doing it twice per comparison, though it requires a large temporary
- // buffer. Besides, this protects us from crashing if some objects have custom toString methods that return
- // random or otherwise changing results, effectively making compare function inconsistent.
-
- Vector<ValueStringPair> values(lengthNotIncludingUndefined);
- if (!values.begin()) {
- throwOutOfMemoryError(exec);
- return;
- }
+ Vector<ValueStringPair> values(relevantLength);
+ if (!values.begin()) {
+ throwOutOfMemoryError(exec);
+ return;
+ }
- Heap::heap(this)->pushTempSortVector(&values);
+ Heap::heap(this)->pushTempSortVector(&values);
- bool isSortingPrimitiveValues = true;
- for (size_t i = 0; i < lengthNotIncludingUndefined; i++) {
- JSValue value = storage->m_vector[i].get();
- ASSERT(!value.isUndefined());
- values[i].first = value;
- isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive();
- }
+ bool isSortingPrimitiveValues = true;
+ for (size_t i = 0; i < relevantLength; i++) {
+ JSValue value = begin[i].get();
+ ASSERT(!value.isUndefined());
+ values[i].first = value;
+ isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive();
+ }
- // FIXME: The following loop continues to call toString on subsequent values even after
- // a toString call raises an exception.
+ // FIXME: The following loop continues to call toString on subsequent values even after
+ // a toString call raises an exception.
- for (size_t i = 0; i < lengthNotIncludingUndefined; i++)
- values[i].second = values[i].first.toWTFStringInline(exec);
+ for (size_t i = 0; i < relevantLength; i++)
+ values[i].second = values[i].first.toWTFStringInline(exec);
- if (exec->hadException()) {
- Heap::heap(this)->popTempSortVector(&values);
- return;
- }
+ if (exec->hadException()) {
+ Heap::heap(this)->popTempSortVector(&values);
+ return;
+ }
- // FIXME: Since we sort by string value, a fast algorithm might be to use a radix sort. That would be O(N) rather
- // than O(N log N).
+ // FIXME: Since we sort by string value, a fast algorithm might be to use a radix sort. That would be O(N) rather
+ // than O(N log N).
#if HAVE(MERGESORT)
- if (isSortingPrimitiveValues)
- qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
- else
- mergesort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
-#else
- // FIXME: The qsort library function is likely to not be a stable sort.
- // ECMAScript-262 does not specify a stable sort, but in practice, browsers perform a stable sort.
+ if (isSortingPrimitiveValues)
qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
+ else
+ mergesort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
+#else
+ // FIXME: The qsort library function is likely to not be a stable sort.
+ // ECMAScript-262 does not specify a stable sort, but in practice, browsers perform a stable sort.
+ qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
#endif
+
+ // If the toString function changed the length of the array or vector storage,
+ // increase the length to handle the orignal number of actual values.
+ switch (indexingType) {
+ case ArrayWithContiguous:
+ ensureContiguousLength(globalData, relevantLength);
+ break;
- // If the toString function changed the length of the array or vector storage,
- // increase the length to handle the orignal number of actual values.
- if (storage->vectorLength() < lengthNotIncludingUndefined) {
- increaseVectorLength(exec->globalData(), lengthNotIncludingUndefined);
- storage = m_butterfly->arrayStorage();
+ case ArrayWithArrayStorage:
+ if (arrayStorage()->vectorLength() < relevantLength) {
+ increaseVectorLength(exec->globalData(), relevantLength);
+ begin = arrayStorage()->m_vector;
}
- if (storage->length() < lengthNotIncludingUndefined)
- storage->setLength(lengthNotIncludingUndefined);
+ if (arrayStorage()->length() < relevantLength)
+ arrayStorage()->setLength(relevantLength);
+ break;
+
+ default:
+ CRASH();
+ }
+
+ for (size_t i = 0; i < relevantLength; i++)
+ begin[i].set(globalData, this, values[i].first);
+
+ Heap::heap(this)->popTempSortVector(&values);
+}
+
+void JSArray::sort(ExecState* exec)
+{
+ ASSERT(!inSparseIndexingMode());
+
+ switch (structure()->indexingType()) {
+ case ArrayClass:
+ return;
- JSGlobalData& globalData = exec->globalData();
- for (size_t i = 0; i < lengthNotIncludingUndefined; i++)
- storage->m_vector[i].set(globalData, this, values[i].first);
+ case ArrayWithContiguous: {
+ unsigned lengthNotIncludingUndefined;
+ unsigned newRelevantLength;
+ compactForSorting<ArrayWithContiguous>(
+ lengthNotIncludingUndefined, newRelevantLength);
- Heap::heap(this)->popTempSortVector(&values);
+ sortCompactedVector<ArrayWithContiguous>(
+ exec, m_butterfly->contiguous(), lengthNotIncludingUndefined);
+ return;
+ }
+
+ case ArrayWithArrayStorage: {
+ unsigned lengthNotIncludingUndefined;
+ unsigned newRelevantLength;
+ compactForSorting<ArrayWithArrayStorage>(
+ lengthNotIncludingUndefined, newRelevantLength);
+ ArrayStorage* storage = m_butterfly->arrayStorage();
+ ASSERT(!storage->m_sparseMap);
+ sortCompactedVector<ArrayWithArrayStorage>(
+ exec, storage->m_vector, lengthNotIncludingUndefined);
return;
}
@@ -781,122 +1047,116 @@ struct AVLTreeAbstractorForArrayCompare {
static handle null() { return 0x7FFFFFFF; }
};
-void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
+template<IndexingType indexingType>
+void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
{
ASSERT(!inSparseIndexingMode());
+ ASSERT(indexingType == structure()->indexingType());
- switch (structure()->indexingType()) {
- case ArrayClass:
- return;
-
- case ArrayWithArrayStorage: {
- ArrayStorage* storage = m_butterfly->arrayStorage();
-
- // FIXME: This ignores exceptions raised in the compare function or in toNumber.
+ // FIXME: This ignores exceptions raised in the compare function or in toNumber.
- // The maximum tree depth is compiled in - but the caller is clearly up to no good
- // if a larger array is passed.
- ASSERT(storage->length() <= static_cast<unsigned>(std::numeric_limits<int>::max()));
- if (storage->length() > static_cast<unsigned>(std::numeric_limits<int>::max()))
- return;
-
- unsigned usedVectorLength = min(storage->length(), storage->vectorLength());
- unsigned nodeCount = usedVectorLength + (storage->m_sparseMap ? storage->m_sparseMap->size() : 0);
-
- if (!nodeCount)
- return;
-
- AVLTree<AVLTreeAbstractorForArrayCompare, 44> tree; // Depth 44 is enough for 2^31 items
- tree.abstractor().m_exec = exec;
- tree.abstractor().m_compareFunction = compareFunction;
- tree.abstractor().m_compareCallType = callType;
- tree.abstractor().m_compareCallData = &callData;
- tree.abstractor().m_nodes.grow(nodeCount);
+ // The maximum tree depth is compiled in - but the caller is clearly up to no good
+ // if a larger array is passed.
+ ASSERT(m_butterfly->publicLength() <= static_cast<unsigned>(std::numeric_limits<int>::max()));
+ if (m_butterfly->publicLength() > static_cast<unsigned>(std::numeric_limits<int>::max()))
+ return;
- if (callType == CallTypeJS)
- tree.abstractor().m_cachedCall = adoptPtr(new CachedCall(exec, jsCast<JSFunction*>(compareFunction), 2));
+ unsigned usedVectorLength = relevantLength<indexingType>();
+ unsigned nodeCount = usedVectorLength;
- if (!tree.abstractor().m_nodes.begin()) {
- throwOutOfMemoryError(exec);
- return;
- }
+ if (!nodeCount)
+ return;
- // FIXME: If the compare function modifies the array, the vector, map, etc. could be modified
- // right out from under us while we're building the tree here.
+ AVLTree<AVLTreeAbstractorForArrayCompare, 44> tree; // Depth 44 is enough for 2^31 items
+ tree.abstractor().m_exec = exec;
+ tree.abstractor().m_compareFunction = compareFunction;
+ tree.abstractor().m_compareCallType = callType;
+ tree.abstractor().m_compareCallData = &callData;
+ tree.abstractor().m_nodes.grow(nodeCount);
- unsigned numDefined = 0;
- unsigned numUndefined = 0;
+ if (callType == CallTypeJS)
+ tree.abstractor().m_cachedCall = adoptPtr(new CachedCall(exec, jsCast<JSFunction*>(compareFunction), 2));
- // Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree.
- for (; numDefined < usedVectorLength; ++numDefined) {
- JSValue v = storage->m_vector[numDefined].get();
- if (!v || v.isUndefined())
- break;
- tree.abstractor().m_nodes[numDefined].value = v;
- tree.insert(numDefined);
- }
- for (unsigned i = numDefined; i < usedVectorLength; ++i) {
- JSValue v = storage->m_vector[i].get();
- if (v) {
- if (v.isUndefined())
- ++numUndefined;
- else {
- tree.abstractor().m_nodes[numDefined].value = v;
- tree.insert(numDefined);
- ++numDefined;
- }
- }
- }
-
- unsigned newUsedVectorLength = numDefined + numUndefined;
+ if (!tree.abstractor().m_nodes.begin()) {
+ throwOutOfMemoryError(exec);
+ return;
+ }
- if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
- newUsedVectorLength += map->size();
- if (newUsedVectorLength > storage->vectorLength()) {
- // Check that it is possible to allocate an array large enough to hold all the entries.
- if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(exec->globalData(), newUsedVectorLength)) {
- throwOutOfMemoryError(exec);
- return;
- }
- storage = m_butterfly->arrayStorage();
- }
-
- SparseArrayValueMap::const_iterator end = map->end();
- for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) {
- tree.abstractor().m_nodes[numDefined].value = it->second.getNonSparseMode();
+ // FIXME: If the compare function modifies the array, the vector, map, etc. could be modified
+ // right out from under us while we're building the tree here.
+
+ unsigned numDefined = 0;
+ unsigned numUndefined = 0;
+
+ // Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree.
+ for (; numDefined < usedVectorLength; ++numDefined) {
+ if (numDefined > m_butterfly->vectorLength())
+ break;
+ JSValue v = indexingData<indexingType>()[numDefined].get();
+ if (!v || v.isUndefined())
+ break;
+ tree.abstractor().m_nodes[numDefined].value = v;
+ tree.insert(numDefined);
+ }
+ for (unsigned i = numDefined; i < usedVectorLength; ++i) {
+ if (i > m_butterfly->vectorLength())
+ break;
+ JSValue v = indexingData<indexingType>()[i].get();
+ if (v) {
+ if (v.isUndefined())
+ ++numUndefined;
+ else {
+ tree.abstractor().m_nodes[numDefined].value = v;
tree.insert(numDefined);
++numDefined;
}
-
- deallocateSparseIndexMap();
}
+ }
- ASSERT(tree.abstractor().m_nodes.size() >= numDefined);
-
- // FIXME: If the compare function changed the length of the array, the following might be
- // modifying the vector incorrectly.
+ unsigned newUsedVectorLength = numDefined + numUndefined;
- // Copy the values back into m_storage.
- AVLTree<AVLTreeAbstractorForArrayCompare, 44>::Iterator iter;
- iter.start_iter_least(tree);
- JSGlobalData& globalData = exec->globalData();
- for (unsigned i = 0; i < numDefined; ++i) {
- storage->m_vector[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value);
- ++iter;
- }
+ // The array size may have changed. Figure out the new bounds.
+ unsigned newestUsedVectorLength = relevantLength<indexingType>();
- // Put undefined values back in.
- for (unsigned i = numDefined; i < newUsedVectorLength; ++i)
- storage->m_vector[i].setUndefined();
+ unsigned elementsToExtractThreshold = min(min(newestUsedVectorLength, numDefined), static_cast<unsigned>(tree.abstractor().m_nodes.size()));
+ unsigned undefinedElementsThreshold = min(newestUsedVectorLength, newUsedVectorLength);
+ unsigned clearElementsThreshold = min(newestUsedVectorLength, usedVectorLength);
- // Ensure that unused values in the vector are zeroed out.
- for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i)
- storage->m_vector[i].clear();
-
- storage->m_numValuesInVector = newUsedVectorLength;
+ // Copy the values back into m_storage.
+ AVLTree<AVLTreeAbstractorForArrayCompare, 44>::Iterator iter;
+ iter.start_iter_least(tree);
+ JSGlobalData& globalData = exec->globalData();
+ for (unsigned i = 0; i < elementsToExtractThreshold; ++i) {
+ indexingData<indexingType>()[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value);
+ ++iter;
+ }
+ // Put undefined values back in.
+ for (unsigned i = elementsToExtractThreshold; i < undefinedElementsThreshold; ++i)
+ indexingData<indexingType>()[i].setUndefined();
+
+ // Ensure that unused values in the vector are zeroed out.
+ for (unsigned i = undefinedElementsThreshold; i < clearElementsThreshold; ++i)
+ indexingData<indexingType>()[i].clear();
+
+ if (hasArrayStorage(indexingType))
+ arrayStorage()->m_numValuesInVector = newUsedVectorLength;
+}
+
+void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
+{
+ ASSERT(!inSparseIndexingMode());
+
+ switch (structure()->indexingType()) {
+ case ArrayClass:
+ return;
+ case ArrayWithContiguous:
+ sortVector<ArrayWithContiguous>(exec, compareFunction, callType, callData);
+ return;
+
+ case ArrayWithArrayStorage:
+ sortVector<ArrayWithArrayStorage>(exec, compareFunction, callType, callData);
return;
- }
default:
ASSERT_NOT_REACHED();
@@ -905,129 +1165,127 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType,
void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
{
+ unsigned i = 0;
+ unsigned vectorEnd;
+ WriteBarrier<Unknown>* vector;
+
switch (structure()->indexingType()) {
case ArrayClass:
return;
+
+ case ArrayWithContiguous: {
+ vectorEnd = m_butterfly->publicLength();
+ vector = m_butterfly->contiguous();
+ break;
+ }
case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = m_butterfly->arrayStorage();
- WriteBarrier<Unknown>* vector = storage->m_vector;
- unsigned vectorEnd = min(storage->length(), storage->vectorLength());
- unsigned i = 0;
- for (; i < vectorEnd; ++i) {
- WriteBarrier<Unknown>& v = vector[i];
- if (!v)
- break;
- args.append(v.get());
- }
-
- for (; i < storage->length(); ++i)
- args.append(get(exec, i));
- return;
+ vector = storage->m_vector;
+ vectorEnd = min(storage->length(), storage->vectorLength());
+ break;
}
default:
- ASSERT_NOT_REACHED();
+ CRASH();
+ vector = 0;
+ vectorEnd = 0;
+ break;
}
+
+ for (; i < vectorEnd; ++i) {
+ WriteBarrier<Unknown>& v = vector[i];
+ if (!v)
+ break;
+ args.append(v.get());
+ }
+
+ for (; i < length(); ++i)
+ args.append(get(exec, i));
}
void JSArray::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t length)
{
+ unsigned i = 0;
+ WriteBarrier<Unknown>* vector;
+ unsigned vectorEnd;
+
ASSERT(length == this->length());
switch (structure()->indexingType()) {
case ArrayClass:
return;
+ case ArrayWithContiguous: {
+ vector = m_butterfly->contiguous();
+ vectorEnd = m_butterfly->publicLength();
+ break;
+ }
+
case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = m_butterfly->arrayStorage();
- unsigned i = 0;
- WriteBarrier<Unknown>* vector = storage->m_vector;
- unsigned vectorEnd = min(length, storage->vectorLength());
- for (; i < vectorEnd; ++i) {
- WriteBarrier<Unknown>& v = vector[i];
- if (!v)
- break;
- callFrame->setArgument(i, v.get());
- }
-
- for (; i < length; ++i)
- callFrame->setArgument(i, get(exec, i));
- return;
+ vector = storage->m_vector;
+ vectorEnd = min(length, storage->vectorLength());
+ break;
}
default:
- ASSERT_NOT_REACHED();
+ CRASH();
+ vector = 0;
+ vectorEnd = 0;
+ break;
+ }
+
+ for (; i < vectorEnd; ++i) {
+ WriteBarrier<Unknown>& v = vector[i];
+ if (!v)
+ break;
+ callFrame->setArgument(i, v.get());
}
+
+ for (; i < length; ++i)
+ callFrame->setArgument(i, get(exec, i));
}
-unsigned JSArray::compactForSorting(JSGlobalData& globalData)
+template<IndexingType indexingType>
+void JSArray::compactForSorting(unsigned& numDefined, unsigned& newRelevantLength)
{
ASSERT(!inSparseIndexingMode());
+ ASSERT(indexingType == structure()->indexingType());
- switch (structure()->indexingType()) {
- case ArrayClass:
- return 0;
-
- case ArrayWithArrayStorage: {
- ArrayStorage* storage = m_butterfly->arrayStorage();
-
- unsigned usedVectorLength = min(storage->length(), storage->vectorLength());
-
- unsigned numDefined = 0;
- unsigned numUndefined = 0;
-
- for (; numDefined < usedVectorLength; ++numDefined) {
- JSValue v = storage->m_vector[numDefined].get();
- if (!v || v.isUndefined())
- break;
- }
+ unsigned myRelevantLength = relevantLength<indexingType>();
+
+ numDefined = 0;
+ unsigned numUndefined = 0;
- for (unsigned i = numDefined; i < usedVectorLength; ++i) {
- JSValue v = storage->m_vector[i].get();
- if (v) {
- if (v.isUndefined())
- ++numUndefined;
- else
- storage->m_vector[numDefined++].setWithoutWriteBarrier(v);
- }
- }
+ for (; numDefined < myRelevantLength; ++numDefined) {
+ JSValue v = indexingData<indexingType>()[numDefined].get();
+ if (!v || v.isUndefined())
+ break;
+ }
- unsigned newUsedVectorLength = numDefined + numUndefined;
-
- if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
- newUsedVectorLength += map->size();
- if (newUsedVectorLength > storage->vectorLength()) {
- // Check that it is possible to allocate an array large enough to hold all the entries - if not,
- // exception is thrown by caller.
- if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(globalData, newUsedVectorLength))
- return 0;
-
- storage = m_butterfly->arrayStorage();
- }
-
- SparseArrayValueMap::const_iterator end = map->end();
- for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it)
- storage->m_vector[numDefined++].setWithoutWriteBarrier(it->second.getNonSparseMode());
-
- deallocateSparseIndexMap();
+ for (unsigned i = numDefined; i < myRelevantLength; ++i) {
+ JSValue v = indexingData<indexingType>()[i].get();
+ if (v) {
+ if (v.isUndefined())
+ ++numUndefined;
+ else
+ indexingData<indexingType>()[numDefined++].setWithoutWriteBarrier(v);
}
-
- for (unsigned i = numDefined; i < newUsedVectorLength; ++i)
- storage->m_vector[i].setUndefined();
- for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i)
- storage->m_vector[i].clear();
-
- storage->m_numValuesInVector = newUsedVectorLength;
-
- return numDefined;
}
- default:
- ASSERT_NOT_REACHED();
- return 0;
- }
-}
+ newRelevantLength = numDefined + numUndefined;
+
+ if (hasArrayStorage(indexingType))
+ ASSERT(!arrayStorage()->m_sparseMap);
+
+ for (unsigned i = numDefined; i < newRelevantLength; ++i)
+ indexingData<indexingType>()[i].setUndefined();
+ for (unsigned i = newRelevantLength; i < myRelevantLength; ++i)
+ indexingData<indexingType>()[i].clear();
+ if (hasArrayStorage(indexingType))
+ arrayStorage()->m_numValuesInVector = newRelevantLength;
+}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSArray.h b/Source/JavaScriptCore/runtime/JSArray.h
index 6e539c9db..d4622aacc 100644
--- a/Source/JavaScriptCore/runtime/JSArray.h
+++ b/Source/JavaScriptCore/runtime/JSArray.h
@@ -71,8 +71,60 @@ namespace JSC {
void push(ExecState*, JSValue);
JSValue pop(ExecState*);
- bool shiftCount(ExecState*, unsigned count);
- bool unshiftCount(ExecState*, unsigned count);
+ enum ShiftCountMode {
+ // This form of shift hints that we're doing queueing. With this assumption in hand,
+ // we convert to ArrayStorage, which has queue optimizations.
+ ShiftCountForShift,
+
+ // This form of shift hints that we're just doing care and feeding on an array that
+ // is probably typically used for ordinary accesses. With this assumption in hand,
+ // we try to preserve whatever indexing type it has already.
+ ShiftCountForSplice
+ };
+
+ bool shiftCountForShift(ExecState* exec, unsigned startIndex, unsigned count)
+ {
+ return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData()));
+ }
+ bool shiftCountForSplice(ExecState* exec, unsigned startIndex, unsigned count)
+ {
+ return shiftCountWithAnyIndexingType(exec, startIndex, count);
+ }
+ template<ShiftCountMode shiftCountMode>
+ bool shiftCount(ExecState* exec, unsigned startIndex, unsigned count)
+ {
+ switch (shiftCountMode) {
+ case ShiftCountForShift:
+ return shiftCountForShift(exec, startIndex, count);
+ case ShiftCountForSplice:
+ return shiftCountForSplice(exec, startIndex, count);
+ default:
+ CRASH();
+ return false;
+ }
+ }
+
+ bool unshiftCountForShift(ExecState* exec, unsigned startIndex, unsigned count)
+ {
+ return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData()));
+ }
+ bool unshiftCountForSplice(ExecState* exec, unsigned startIndex, unsigned count)
+ {
+ return unshiftCountWithAnyIndexingType(exec, startIndex, count);
+ }
+ template<ShiftCountMode shiftCountMode>
+ bool unshiftCount(ExecState* exec, unsigned startIndex, unsigned count)
+ {
+ switch (shiftCountMode) {
+ case ShiftCountForShift:
+ return unshiftCountForShift(exec, startIndex, count);
+ case ShiftCountForSplice:
+ return unshiftCountForSplice(exec, startIndex, count);
+ default:
+ CRASH();
+ return false;
+ }
+ }
void fillArgList(ExecState*, MarkedArgumentBuffer&);
void copyToArguments(ExecState*, CallFrame*, uint32_t length);
@@ -94,18 +146,44 @@ namespace JSC {
{
ArrayStorage* storage = arrayStorageOrNull();
if (!storage)
- return false;
+ return true;
SparseArrayValueMap* map = storage->m_sparseMap.get();
return !map || !map->lengthIsReadOnly();
}
+
+ bool shiftCountWithAnyIndexingType(ExecState*, unsigned startIndex, unsigned count);
+ bool shiftCountWithArrayStorage(unsigned startIndex, unsigned count, ArrayStorage*);
- void setLengthWritable(ExecState*, bool writable);
+ bool unshiftCountWithAnyIndexingType(ExecState*, unsigned startIndex, unsigned count);
+ bool unshiftCountWithArrayStorage(ExecState*, unsigned startIndex, unsigned count, ArrayStorage*);
+ bool unshiftCountSlowCase(JSGlobalData&, bool, unsigned);
+
+ template<IndexingType indexingType>
+ void sortNumericVector(ExecState*, JSValue compareFunction, CallType, const CallData&);
+
+ template<IndexingType indexingType>
+ void sortCompactedVector(ExecState*, WriteBarrier<Unknown>* begin, unsigned relevantLength);
+
+ template<IndexingType indexingType>
+ void sortVector(ExecState*, JSValue compareFunction, CallType, const CallData&);
- bool unshiftCountSlowCase(JSGlobalData&, unsigned count);
+ bool setLengthWithArrayStorage(ExecState*, unsigned newLength, bool throwException, ArrayStorage*);
+ void setLengthWritable(ExecState*, bool writable);
- unsigned compactForSorting(JSGlobalData&);
+ template<IndexingType indexingType>
+ void compactForSorting(unsigned& numDefined, unsigned& newRelevantLength);
};
+ inline Butterfly* createContiguousArrayButterfly(JSGlobalData& globalData, unsigned length)
+ {
+ IndexingHeader header;
+ header.setVectorLength(std::max(length, BASE_VECTOR_LEN));
+ header.setPublicLength(length);
+ Butterfly* result = Butterfly::create(
+ globalData, 0, 0, true, header, header.vectorLength() * sizeof(EncodedJSValue));
+ return result;
+ }
+
inline Butterfly* createArrayButterfly(JSGlobalData& globalData, unsigned initialLength)
{
Butterfly* butterfly = Butterfly::create(
@@ -121,7 +199,16 @@ namespace JSC {
inline JSArray* JSArray::create(JSGlobalData& globalData, Structure* structure, unsigned initialLength)
{
- Butterfly* butterfly = createArrayButterfly(globalData, initialLength);
+ Butterfly* butterfly;
+ if (LIKELY(structure->indexingType() == ArrayWithContiguous)) {
+ butterfly = createContiguousArrayButterfly(globalData, initialLength);
+ ASSERT(initialLength < MIN_SPARSE_ARRAY_INDEX);
+ } else {
+ ASSERT(
+ structure->indexingType() == ArrayWithSlowPutArrayStorage
+ || (initialLength && structure->indexingType() == ArrayWithArrayStorage));
+ butterfly = createArrayButterfly(globalData, initialLength);
+ }
JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure, butterfly);
array->finishCreation(globalData);
return array;
@@ -133,15 +220,26 @@ namespace JSC {
if (vectorLength > MAX_STORAGE_VECTOR_LENGTH)
return 0;
- void* temp;
- if (!globalData.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, ArrayStorage::sizeFor(vectorLength)), &temp))
- return 0;
- Butterfly* butterfly = Butterfly::fromBase(temp, 0, 0);
- *butterfly->indexingHeader() = indexingHeaderForArray(initialLength, vectorLength);
- ArrayStorage* storage = butterfly->arrayStorage();
- storage->m_indexBias = 0;
- storage->m_sparseMap.clear();
- storage->m_numValuesInVector = initialLength;
+ Butterfly* butterfly;
+ if (LIKELY(structure->indexingType() == ArrayWithContiguous)) {
+
+ void* temp;
+ if (!globalData.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, vectorLength * sizeof(EncodedJSValue)), &temp))
+ return 0;
+ butterfly = Butterfly::fromBase(temp, 0, 0);
+ butterfly->setVectorLength(vectorLength);
+ butterfly->setPublicLength(initialLength);
+ } else {
+ void* temp;
+ if (!globalData.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, ArrayStorage::sizeFor(vectorLength)), &temp))
+ return 0;
+ butterfly = Butterfly::fromBase(temp, 0, 0);
+ *butterfly->indexingHeader() = indexingHeaderForArray(initialLength, vectorLength);
+ ArrayStorage* storage = butterfly->arrayStorage();
+ storage->m_indexBias = 0;
+ storage->m_sparseMap.clear();
+ storage->m_numValuesInVector = initialLength;
+ }
JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure, butterfly);
array->finishCreation(globalData);
diff --git a/Source/JavaScriptCore/runtime/JSBoundFunction.cpp b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp
index 3815c144e..d8f611477 100644
--- a/Source/JavaScriptCore/runtime/JSBoundFunction.cpp
+++ b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp
@@ -31,7 +31,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(JSBoundFunction);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSBoundFunction);
const ClassInfo JSBoundFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSBoundFunction) };
diff --git a/Source/JavaScriptCore/runtime/JSCell.cpp b/Source/JavaScriptCore/runtime/JSCell.cpp
index 739247fb2..f6f4d716d 100644
--- a/Source/JavaScriptCore/runtime/JSCell.cpp
+++ b/Source/JavaScriptCore/runtime/JSCell.cpp
@@ -38,6 +38,10 @@ void JSCell::destroy(JSCell* cell)
cell->JSCell::~JSCell();
}
+void JSCell::copyBackingStore(JSCell*, CopyVisitor&)
+{
+}
+
bool JSCell::getString(ExecState* exec, String& stringValue) const
{
if (!isString())
diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h
index cf6f4ec45..a39af1283 100644
--- a/Source/JavaScriptCore/runtime/JSCell.h
+++ b/Source/JavaScriptCore/runtime/JSCell.h
@@ -31,12 +31,15 @@
#include "JSValueInlineMethods.h"
#include "SlotVisitor.h"
#include "SlotVisitorInlineMethods.h"
+#include "TypedArrayDescriptor.h"
#include "WriteBarrier.h"
#include <wtf/Noncopyable.h>
#include <wtf/TypeTraits.h>
namespace JSC {
+ class CopyVisitor;
+ class JSDestructibleObject;
class JSGlobalObject;
class LLIntOffsetsExtractor;
class PropertyDescriptor;
@@ -48,19 +51,6 @@ namespace JSC {
IncludeDontEnumProperties
};
- enum TypedArrayType {
- TypedArrayNone,
- TypedArrayInt8,
- TypedArrayInt16,
- TypedArrayInt32,
- TypedArrayUint8,
- TypedArrayUint8Clamped,
- TypedArrayUint16,
- TypedArrayUint32,
- TypedArrayFloat32,
- TypedArrayFloat64
- };
-
class JSCell {
friend class JSValue;
friend class MarkedBlock;
@@ -70,6 +60,9 @@ namespace JSC {
public:
static const unsigned StructureFlags = 0;
+ static const bool needsDestruction = false;
+ static const bool hasImmortalStructure = false;
+
enum CreatingEarlyCellTag { CreatingEarlyCell };
JSCell(CreatingEarlyCellTag);
@@ -108,6 +101,7 @@ namespace JSC {
JS_EXPORT_PRIVATE JSObject* toObject(ExecState*, JSGlobalObject*) const;
static void visitChildren(JSCell*, SlotVisitor&);
+ JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&);
// Object operations, with the toObject operation included.
const ClassInfo* classInfo() const;
@@ -309,46 +303,29 @@ namespace JSC {
return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject);
}
- template<class T>
- struct NeedsDestructor {
- static const bool value = !WTF::HasTrivialDestructor<T>::value;
- };
-
template<typename T>
- void* allocateCell(Heap& heap)
+ void* allocateCell(Heap& heap, size_t size)
{
+ ASSERT(size >= sizeof(T));
#if ENABLE(GC_VALIDATION)
ASSERT(!heap.globalData()->isInitializingObject());
heap.globalData()->setInitializingObjectClass(&T::s_info);
#endif
JSCell* result = 0;
- if (NeedsDestructor<T>::value)
- result = static_cast<JSCell*>(heap.allocateWithDestructor(sizeof(T)));
- else {
- ASSERT(T::s_info.methodTable.destroy == JSCell::destroy);
- result = static_cast<JSCell*>(heap.allocateWithoutDestructor(sizeof(T)));
- }
+ if (T::needsDestruction && T::hasImmortalStructure)
+ result = static_cast<JSCell*>(heap.allocateWithImmortalStructureDestructor(size));
+ else if (T::needsDestruction && !T::hasImmortalStructure)
+ result = static_cast<JSCell*>(heap.allocateWithNormalDestructor(size));
+ else
+ result = static_cast<JSCell*>(heap.allocateWithoutDestructor(size));
result->clearStructure();
return result;
}
template<typename T>
- void* allocateCell(Heap& heap, size_t size)
+ void* allocateCell(Heap& heap)
{
- ASSERT(size >= sizeof(T));
-#if ENABLE(GC_VALIDATION)
- ASSERT(!heap.globalData()->isInitializingObject());
- heap.globalData()->setInitializingObjectClass(&T::s_info);
-#endif
- JSCell* result = 0;
- if (NeedsDestructor<T>::value)
- result = static_cast<JSCell*>(heap.allocateWithDestructor(size));
- else {
- ASSERT(T::s_info.methodTable.destroy == JSCell::destroy);
- result = static_cast<JSCell*>(heap.allocateWithoutDestructor(size));
- }
- result->clearStructure();
- return result;
+ return allocateCell<T>(heap, sizeof(T));
}
inline bool isZapped(const JSCell* cell)
@@ -362,7 +339,7 @@ namespace JSC {
ASSERT(!from || from->JSCell::inherits(&WTF::RemovePointer<To>::Type::s_info));
return static_cast<To>(from);
}
-
+
template<typename To>
inline To jsCast(JSValue from)
{
diff --git a/Source/JavaScriptCore/runtime/JSDestructibleObject.h b/Source/JavaScriptCore/runtime/JSDestructibleObject.h
new file mode 100644
index 000000000..b8479be62
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSDestructibleObject.h
@@ -0,0 +1,43 @@
+#ifndef JSDestructibleObject_h
+#define JSDestructibleObject_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+struct ClassInfo;
+
+class JSDestructibleObject : public JSNonFinalObject {
+public:
+ typedef JSNonFinalObject Base;
+
+ static const bool needsDestruction = true;
+
+ const ClassInfo* classInfo() const { return m_classInfo; }
+
+protected:
+ JSDestructibleObject(JSGlobalData& globalData, Structure* structure, Butterfly* butterfly = 0)
+ : JSNonFinalObject(globalData, structure, butterfly)
+ , m_classInfo(structure->classInfo())
+ {
+ ASSERT(m_classInfo);
+ }
+
+private:
+ const ClassInfo* m_classInfo;
+};
+
+inline const ClassInfo* JSCell::classInfo() const
+{
+ if (MarkedBlock::blockFor(this)->destructorType() == MarkedBlock::Normal)
+ return static_cast<const JSDestructibleObject*>(this)->classInfo();
+#if ENABLE(GC_VALIDATION)
+ return m_structure.unvalidatedGet()->classInfo();
+#else
+ return m_structure->classInfo();
+#endif
+}
+
+} // namespace JSC
+
+#endif
diff --git a/Source/JavaScriptCore/runtime/JSFunction.cpp b/Source/JavaScriptCore/runtime/JSFunction.cpp
index 4afe63216..891a23930 100644
--- a/Source/JavaScriptCore/runtime/JSFunction.cpp
+++ b/Source/JavaScriptCore/runtime/JSFunction.cpp
@@ -48,7 +48,6 @@ EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState* exec)
return throwVMError(exec, createNotAConstructorError(exec, exec->callee()));
}
-ASSERT_CLASS_FITS_IN_CELL(JSFunction);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSFunction);
const ClassInfo JSFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFunction) };
diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/Source/JavaScriptCore/runtime/JSGlobalData.cpp
index e30a7913d..bc3d00067 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalData.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalData.cpp
@@ -231,7 +231,9 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread
interpreter->initialize(this->canUseJIT());
+#if ENABLE(JIT)
initializeHostCallReturnValue(); // This is needed to convince the linker not to drop host call return support.
+#endif
heap.notifyIsSafeToCollect();
diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.h b/Source/JavaScriptCore/runtime/JSGlobalData.h
index 603f9f82a..6cc0aad8d 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalData.h
+++ b/Source/JavaScriptCore/runtime/JSGlobalData.h
@@ -44,6 +44,7 @@
#include "Strong.h"
#include "Terminator.h"
#include "TimeoutChecker.h"
+#include "TypedArrayDescriptor.h"
#include "WeakRandom.h"
#include <wtf/BumpPointerAllocator.h>
#include <wtf/Forward.h>
@@ -108,24 +109,6 @@ namespace JSC {
ThreadStackTypeSmall
};
- struct TypedArrayDescriptor {
- TypedArrayDescriptor()
- : m_classInfo(0)
- , m_storageOffset(0)
- , m_lengthOffset(0)
- {
- }
- TypedArrayDescriptor(const ClassInfo* classInfo, size_t storageOffset, size_t lengthOffset)
- : m_classInfo(classInfo)
- , m_storageOffset(storageOffset)
- , m_lengthOffset(lengthOffset)
- {
- }
- const ClassInfo* m_classInfo;
- size_t m_storageOffset;
- size_t m_lengthOffset;
- };
-
#if ENABLE(DFG_JIT)
class ConservativeRoots;
@@ -429,6 +412,35 @@ namespace JSC {
registerTypedArrayFunction(float32, Float32);
registerTypedArrayFunction(float64, Float64);
#undef registerTypedArrayFunction
+
+ const TypedArrayDescriptor* typedArrayDescriptor(TypedArrayType type) const
+ {
+ switch (type) {
+ case TypedArrayNone:
+ return 0;
+ case TypedArrayInt8:
+ return &int8ArrayDescriptor();
+ case TypedArrayInt16:
+ return &int16ArrayDescriptor();
+ case TypedArrayInt32:
+ return &int32ArrayDescriptor();
+ case TypedArrayUint8:
+ return &uint8ArrayDescriptor();
+ case TypedArrayUint8Clamped:
+ return &uint8ClampedArrayDescriptor();
+ case TypedArrayUint16:
+ return &uint16ArrayDescriptor();
+ case TypedArrayUint32:
+ return &uint32ArrayDescriptor();
+ case TypedArrayFloat32:
+ return &float32ArrayDescriptor();
+ case TypedArrayFloat64:
+ return &float64ArrayDescriptor();
+ default:
+ CRASH();
+ return 0;
+ }
+ }
JSLock& apiLock() { return m_apiLock; }
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
index b0a0e8122..9eb266135 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
@@ -100,8 +100,6 @@ const GlobalObjectMethodTable JSGlobalObject::s_globalObjectMethodTable = { &all
@end
*/
-ASSERT_CLASS_FITS_IN_CELL(JSGlobalObject);
-
// Default number of ticks before a timeout check should be done.
static const int initialTickCountThreshold = 255;
@@ -228,10 +226,11 @@ void JSGlobalObject::reset(JSValue prototype)
m_callbackFunctionStructure.set(exec->globalData(), this, JSCallbackFunction::createStructure(exec->globalData(), this, m_functionPrototype.get()));
m_argumentsStructure.set(exec->globalData(), this, Arguments::createStructure(exec->globalData(), this, m_objectPrototype.get()));
m_callbackConstructorStructure.set(exec->globalData(), this, JSCallbackConstructor::createStructure(exec->globalData(), this, m_objectPrototype.get()));
- m_callbackObjectStructure.set(exec->globalData(), this, JSCallbackObject<JSNonFinalObject>::createStructure(exec->globalData(), this, m_objectPrototype.get()));
+ m_callbackObjectStructure.set(exec->globalData(), this, JSCallbackObject<JSDestructibleObject>::createStructure(exec->globalData(), this, m_objectPrototype.get()));
m_arrayPrototype.set(exec->globalData(), this, ArrayPrototype::create(exec, this, ArrayPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get())));
- m_arrayStructure.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithArrayStorage));
+ m_arrayStructure.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithContiguous));
+ m_arrayStructureWithArrayStorage.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithArrayStorage));
m_arrayStructureForSlowPut.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithSlowPutArrayStorage));
m_regExpMatchesArrayStructure.set(exec->globalData(), this, RegExpMatchesArray::createStructure(exec->globalData(), this, m_arrayPrototype.get()));
@@ -318,6 +317,9 @@ void JSGlobalObject::reset(JSValue prototype)
GlobalPropertyInfo(Identifier(exec, "undefined"), jsUndefined(), DontEnum | DontDelete | ReadOnly)
};
addStaticGlobals(staticGlobals, WTF_ARRAY_LENGTH(staticGlobals));
+
+ m_specialPointers[Special::CallFunction] = m_callFunction.get();
+ m_specialPointers[Special::ApplyFunction] = m_applyFunction.get();
if (m_experimentsEnabled) {
NamePrototype* privateNamePrototype = NamePrototype::create(exec, NamePrototype::createStructure(exec->globalData(), this, m_objectPrototype.get()));
@@ -354,7 +356,8 @@ ObjectsWithBrokenIndexingFinder::ObjectsWithBrokenIndexingFinder(
inline bool hasBrokenIndexing(JSObject* object)
{
// This will change if we have more indexing types.
- return !!(object->structure()->indexingType() & HasArrayStorage);
+ IndexingType type = object->structure()->indexingType();
+ return hasContiguous(type) || hasFastArrayStorage(type);
}
void ObjectsWithBrokenIndexingFinder::operator()(JSCell* cell)
@@ -407,6 +410,7 @@ void JSGlobalObject::haveABadTime(JSGlobalData& globalData)
// Make sure that all JSArray allocations that load the appropriate structure from
// this object now load a structure that uses SlowPut.
m_arrayStructure.set(globalData, this, m_arrayStructureForSlowPut.get());
+ m_arrayStructureWithArrayStorage.set(globalData, this, m_arrayStructureForSlowPut.get());
// Make sure that all objects that have indexed storage switch to the slow kind of
// indexed storage.
@@ -482,6 +486,7 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
visitor.append(&thisObject->m_nameScopeStructure);
visitor.append(&thisObject->m_argumentsStructure);
visitor.append(&thisObject->m_arrayStructure);
+ visitor.append(&thisObject->m_arrayStructureWithArrayStorage);
visitor.append(&thisObject->m_arrayStructureForSlowPut);
visitor.append(&thisObject->m_booleanObjectStructure);
visitor.append(&thisObject->m_callbackConstructorStructure);
@@ -502,9 +507,14 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
visitor.append(&thisObject->m_internalFunctionStructure);
}
+JSObject* JSGlobalObject::toThisObject(JSCell* cell, ExecState*)
+{
+ return jsCast<JSGlobalObject*>(cell)->globalThis();
+}
+
ExecState* JSGlobalObject::globalExec()
{
- return CallFrame::create(m_globalCallFrame + RegisterFile::CallFrameHeaderSize);
+ return CallFrame::create(m_globalCallFrame + JSStack::CallFrameHeaderSize);
}
void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count)
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h
index ad56783cc..2994aa64b 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.h
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h
@@ -24,10 +24,10 @@
#include "JSArray.h"
#include "JSGlobalData.h"
-#include "JSGlobalThis.h"
#include "JSSegmentedVariableObject.h"
#include "JSWeakObjectMapRefInternal.h"
#include "NumberPrototype.h"
+#include "SpecialPointer.h"
#include "StringPrototype.h"
#include "StructureChain.h"
#include "Watchpoint.h"
@@ -46,12 +46,12 @@ namespace JSC {
class FunctionPrototype;
class GetterSetter;
class GlobalCodeBlock;
+ class JSStack;
class LLIntOffsetsExtractor;
class NativeErrorConstructor;
class ProgramCodeBlock;
class RegExpConstructor;
class RegExpPrototype;
- class RegisterFile;
struct ActivationStackNode;
struct HashTable;
@@ -77,7 +77,6 @@ namespace JSC {
class JSGlobalObject : public JSSegmentedVariableObject {
private:
- typedef JSSegmentedVariableObject Base;
typedef HashSet<RefPtr<OpaqueJSWeakObjectMap> > WeakMapSet;
struct JSGlobalObjectRareData {
@@ -92,7 +91,7 @@ namespace JSC {
protected:
- Register m_globalCallFrame[RegisterFile::CallFrameHeaderSize];
+ Register m_globalCallFrame[JSStack::CallFrameHeaderSize];
WriteBarrier<JSObject> m_globalThis;
WriteBarrier<JSObject> m_methodCallDummy;
@@ -127,6 +126,7 @@ namespace JSC {
WriteBarrier<Structure> m_nameScopeStructure;
WriteBarrier<Structure> m_argumentsStructure;
WriteBarrier<Structure> m_arrayStructure; // This gets set to m_arrayStructureForSlowPut as soon as we decide to have a bad time.
+ WriteBarrier<Structure> m_arrayStructureWithArrayStorage; // This gets set to m_arrayStructureForSlowPut as soon as we decide to have a bad time.
WriteBarrier<Structure> m_arrayStructureForSlowPut;
WriteBarrier<Structure> m_booleanObjectStructure;
WriteBarrier<Structure> m_callbackConstructorStructure;
@@ -146,6 +146,8 @@ namespace JSC {
WriteBarrier<Structure> m_regExpStructure;
WriteBarrier<Structure> m_stringObjectStructure;
WriteBarrier<Structure> m_internalFunctionStructure;
+
+ void* m_specialPointers[Special::TableSize]; // Special pointers used by the LLInt and JIT.
Debugger* m_debugger;
@@ -168,14 +170,16 @@ namespace JSC {
if (m_rareData)
return;
m_rareData = adoptPtr(new JSGlobalObjectRareData);
- Heap::heap(this)->addFinalizer(this, clearRareData);
}
public:
+ typedef JSSegmentedVariableObject Base;
+
static JSGlobalObject* create(JSGlobalData& globalData, Structure* structure)
{
JSGlobalObject* globalObject = new (NotNull, allocateCell<JSGlobalObject>(globalData.heap)) JSGlobalObject(globalData, structure);
globalObject->finishCreation(globalData);
+ globalData.heap.addFinalizer(globalObject, destroy);
return globalObject;
}
@@ -192,7 +196,7 @@ namespace JSC {
init(this);
}
- void finishCreation(JSGlobalData& globalData, JSGlobalThis* thisValue)
+ void finishCreation(JSGlobalData& globalData, JSObject* thisValue)
{
Base::finishCreation(globalData);
structure()->setGlobalObject(globalData, this);
@@ -203,6 +207,8 @@ namespace JSC {
public:
JS_EXPORT_PRIVATE ~JSGlobalObject();
JS_EXPORT_PRIVATE static void destroy(JSCell*);
+ // We don't need a destructor because we use a finalizer instead.
+ static const bool needsDestruction = false;
JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
@@ -262,7 +268,9 @@ namespace JSC {
Structure* nameScopeStructure() const { return m_nameScopeStructure.get(); }
Structure* argumentsStructure() const { return m_argumentsStructure.get(); }
Structure* arrayStructure() const { return m_arrayStructure.get(); }
+ Structure* arrayStructureWithArrayStorage() const { return m_arrayStructureWithArrayStorage.get(); }
void* addressOfArrayStructure() { return &m_arrayStructure; }
+ void* addressOfArrayStructureWithArrayStorage() { return &m_arrayStructureWithArrayStorage; }
Structure* booleanObjectStructure() const { return m_booleanObjectStructure.get(); }
Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); }
Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); }
@@ -282,6 +290,12 @@ namespace JSC {
Structure* regExpStructure() const { return m_regExpStructure.get(); }
Structure* stringObjectStructure() const { return m_stringObjectStructure.get(); }
+ void* actualPointerFor(Special::Pointer pointer)
+ {
+ ASSERT(pointer < Special::TableSize);
+ return m_specialPointers[pointer];
+ }
+
WatchpointSet* masqueradesAsUndefinedWatchpoint() { return m_masqueradesAsUndefinedWatchpoint.get(); }
WatchpointSet* havingABadTimeWatchpoint() { return m_havingABadTimeWatchpoint.get(); }
@@ -366,13 +380,16 @@ namespace JSC {
};
JS_EXPORT_PRIVATE void addStaticGlobals(GlobalPropertyInfo*, int count);
+ JS_EXPORT_PRIVATE static JSC::JSObject* toThisObject(JSC::JSCell*, JSC::ExecState*);
+
+ JS_EXPORT_PRIVATE void setGlobalThis(JSGlobalData&, JSObject* globalThis);
+
private:
friend class LLIntOffsetsExtractor;
// FIXME: Fold reset into init.
JS_EXPORT_PRIVATE void init(JSObject* thisValue);
void reset(JSValue prototype);
- void setGlobalThis(JSGlobalData&, JSObject* globalThis);
void createThrowTypeError(ExecState*);
@@ -465,7 +482,7 @@ namespace JSC {
inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject, unsigned initialLength = 0)
{
- return JSArray::create(exec->globalData(), globalObject->arrayStructure(), initialLength);
+ return JSArray::create(exec->globalData(), initialLength >= MIN_SPARSE_ARRAY_INDEX ? globalObject->arrayStructureWithArrayStorage() : globalObject->arrayStructure(), initialLength);
}
inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength = 0)
diff --git a/Source/JavaScriptCore/runtime/JSGlobalThis.cpp b/Source/JavaScriptCore/runtime/JSGlobalThis.cpp
deleted file mode 100644
index a3f2e7785..000000000
--- a/Source/JavaScriptCore/runtime/JSGlobalThis.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2011 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. AND ITS CONTRIBUTORS ``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 ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "JSGlobalThis.h"
-
-#include "JSGlobalObject.h"
-
-namespace JSC {
-
-ASSERT_CLASS_FITS_IN_CELL(JSGlobalThis);
-ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSGlobalThis);
-
-const ClassInfo JSGlobalThis::s_info = { "JSGlobalThis", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSGlobalThis) };
-
-void JSGlobalThis::visitChildren(JSCell* cell, SlotVisitor& visitor)
-{
- JSGlobalThis* thisObject = jsCast<JSGlobalThis*>(cell);
- ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
-
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
-
- Base::visitChildren(thisObject, visitor);
- visitor.append(&thisObject->m_unwrappedObject);
-}
-
-void JSGlobalThis::setUnwrappedObject(JSGlobalData& globalData, JSGlobalObject* globalObject)
-{
- ASSERT_ARG(globalObject, globalObject);
- m_unwrappedObject.set(globalData, this, globalObject);
- setPrototype(globalData, globalObject->prototype());
- resetInheritorID(globalData);
-}
-
-} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSGlobalThis.h b/Source/JavaScriptCore/runtime/JSGlobalThis.h
deleted file mode 100644
index 0ca99414a..000000000
--- a/Source/JavaScriptCore/runtime/JSGlobalThis.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2011 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 JSGlobalThis_h
-#define JSGlobalThis_h
-
-#include "JSObject.h"
-
-namespace JSC {
-
-class JSGlobalThis : public JSNonFinalObject {
-public:
- typedef JSNonFinalObject Base;
-
- static JSGlobalThis* create(JSGlobalData& globalData, Structure* structure)
- {
- JSGlobalThis* globalThis = new (NotNull, allocateCell<JSGlobalThis>(globalData.heap)) JSGlobalThis(globalData, structure);
- globalThis->finishCreation(globalData);
- return globalThis;
- }
-
- static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
- {
- return Structure::create(globalData, 0, prototype, TypeInfo(GlobalThisType, StructureFlags), &s_info);
- }
-
- static JS_EXPORTDATA const JSC::ClassInfo s_info;
-
- JSGlobalObject* unwrappedObject() const { return m_unwrappedObject.get(); }
-
-protected:
- JSGlobalThis(JSGlobalData& globalData, Structure* structure)
- : JSNonFinalObject(globalData, structure)
- {
- }
-
- void finishCreation(JSGlobalData& globalData)
- {
- Base::finishCreation(globalData);
- }
-
- static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags;
-
- JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
-
- JS_EXPORT_PRIVATE void setUnwrappedObject(JSGlobalData&, JSGlobalObject*);
-
-private:
- WriteBarrier<JSGlobalObject> m_unwrappedObject;
-};
-
-} // namespace JSC
-
-#endif // JSGlobalThis_h
diff --git a/Source/JavaScriptCore/runtime/JSLock.cpp b/Source/JavaScriptCore/runtime/JSLock.cpp
index 9f02b69b8..85dbdfedb 100644
--- a/Source/JavaScriptCore/runtime/JSLock.cpp
+++ b/Source/JavaScriptCore/runtime/JSLock.cpp
@@ -140,13 +140,13 @@ bool JSLock::currentThreadIsHoldingLock()
// context if the thread leaves JSC by making a call out to an external
// function through a callback.
//
-// All threads using the context share the same JS stack (the RegisterFile).
-// Whenever a thread calls into JSC it starts using the RegisterFile from the
+// All threads using the context share the same JS stack (the JSStack).
+// Whenever a thread calls into JSC it starts using the JSStack from the
// previous 'high water mark' - the maximum point the stack has ever grown to
-// (returned by RegisterFile::end()). So if a first thread calls out to a
+// (returned by JSStack::end()). So if a first thread calls out to a
// callback, and a second thread enters JSC, then also exits by calling out
// to a callback, we can be left with stackframes from both threads in the
-// RegisterFile. As such, a problem may occur should the first thread's
+// JSStack. As such, a problem may occur should the first thread's
// callback complete first, and attempt to return to JSC. Were we to allow
// this to happen, and were its stack to grow further, then it may potentially
// write over the second thread's call frames.
diff --git a/Source/JavaScriptCore/runtime/JSNameScope.cpp b/Source/JavaScriptCore/runtime/JSNameScope.cpp
index 5dc665c44..335631fd0 100644
--- a/Source/JavaScriptCore/runtime/JSNameScope.cpp
+++ b/Source/JavaScriptCore/runtime/JSNameScope.cpp
@@ -30,8 +30,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(JSNameScope);
-
const ClassInfo JSNameScope::s_info = { "NameScope", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSNameScope) };
void JSNameScope::visitChildren(JSCell* cell, SlotVisitor& visitor)
diff --git a/Source/JavaScriptCore/runtime/JSNotAnObject.cpp b/Source/JavaScriptCore/runtime/JSNotAnObject.cpp
index f75fa1f96..53592ba2b 100644
--- a/Source/JavaScriptCore/runtime/JSNotAnObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSNotAnObject.cpp
@@ -34,7 +34,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(JSNotAnObject);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSNotAnObject);
const ClassInfo JSNotAnObject::s_info = { "Object", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSNotAnObject) };
diff --git a/Source/JavaScriptCore/runtime/JSONObject.cpp b/Source/JavaScriptCore/runtime/JSONObject.cpp
index fe894afba..fd939934e 100644
--- a/Source/JavaScriptCore/runtime/JSONObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSONObject.cpp
@@ -41,7 +41,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(JSONObject);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSONObject);
static EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState*);
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp
index bf38f6876..6a3fb84e4 100644
--- a/Source/JavaScriptCore/runtime/JSObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSObject.cpp
@@ -26,13 +26,14 @@
#include "ButterflyInlineMethods.h"
#include "CopiedSpaceInlineMethods.h"
+#include "CopyVisitor.h"
+#include "CopyVisitorInlineMethods.h"
#include "DatePrototype.h"
#include "ErrorConstructor.h"
#include "GetterSetter.h"
#include "IndexingHeaderInlineMethods.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
-#include "JSGlobalThis.h"
#include "Lookup.h"
#include "NativeErrorConstructor.h"
#include "Nodes.h"
@@ -63,10 +64,6 @@ JSCell* getCallableObjectSlow(JSCell* cell)
return 0;
}
-ASSERT_CLASS_FITS_IN_CELL(JSObject);
-ASSERT_CLASS_FITS_IN_CELL(JSNonFinalObject);
-ASSERT_CLASS_FITS_IN_CELL(JSFinalObject);
-
ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSObject);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSFinalObject);
@@ -95,7 +92,7 @@ static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* class
}
}
-ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* butterfly, size_t storageSize)
+ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butterfly, size_t storageSize)
{
ASSERT(butterfly);
@@ -112,61 +109,93 @@ ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* but
preCapacity = 0;
indexingPayloadSizeInBytes = 0;
}
- size_t capacityInBytes = Butterfly::totalSize(
- preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
- if (visitor.checkIfShouldCopyAndPinOtherwise(
- butterfly->base(preCapacity, propertyCapacity), capacityInBytes)) {
+ size_t capacityInBytes = Butterfly::totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
+ if (visitor.checkIfShouldCopy(butterfly->base(preCapacity, propertyCapacity), capacityInBytes)) {
Butterfly* newButterfly = Butterfly::createUninitializedDuringCollection(visitor, preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
- // Mark and copy the properties.
+ // Copy the properties.
PropertyStorage currentTarget = newButterfly->propertyStorage();
PropertyStorage currentSource = butterfly->propertyStorage();
- for (size_t count = storageSize; count--;) {
- JSValue value = (--currentSource)->get();
- ASSERT(value);
- visitor.appendUnbarrieredValue(&value);
- (--currentTarget)->setWithoutWriteBarrier(value);
- }
+ for (size_t count = storageSize; count--;)
+ (--currentTarget)->setWithoutWriteBarrier((--currentSource)->get());
if (UNLIKELY(hasIndexingHeader)) {
*newButterfly->indexingHeader() = *butterfly->indexingHeader();
- // Mark and copy the array if appropriate.
+ // Copy the array if appropriate.
+
+ WriteBarrier<Unknown>* currentTarget;
+ WriteBarrier<Unknown>* currentSource;
+ size_t count;
+
switch (structure->indexingType()) {
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ currentTarget = newButterfly->contiguous();
+ currentSource = butterfly->contiguous();
+ ASSERT(newButterfly->publicLength() <= newButterfly->vectorLength());
+ count = newButterfly->vectorLength();
+ break;
+ }
+
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;
- for (size_t count = newButterfly->arrayStorage()->vectorLength(); count--;) {
- JSValue value = (currentSource++)->get();
- if (value)
- visitor.appendUnbarrieredValue(&value);
- (currentTarget++)->setWithoutWriteBarrier(value);
- }
- if (newButterfly->arrayStorage()->m_sparseMap)
- visitor.append(&newButterfly->arrayStorage()->m_sparseMap);
+ currentTarget = newButterfly->arrayStorage()->m_vector;
+ currentSource = butterfly->arrayStorage()->m_vector;
+ count = newButterfly->arrayStorage()->vectorLength();
break;
}
default:
+ CRASH();
+ currentTarget = 0;
+ currentSource = 0;
+ count = 0;
break;
}
+
+ while (count--)
+ (currentTarget++)->setWithoutWriteBarrier((currentSource++)->get());
}
m_butterfly = newButterfly;
+ visitor.didCopy(butterfly->base(preCapacity, propertyCapacity), capacityInBytes);
+ }
+}
+
+ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* butterfly, size_t storageSize)
+{
+ ASSERT(butterfly);
+
+ Structure* structure = this->structure();
+
+ size_t propertyCapacity = structure->outOfLineCapacity();
+ size_t preCapacity;
+ size_t indexingPayloadSizeInBytes;
+ bool hasIndexingHeader = JSC::hasIndexingHeader(structure->indexingType());
+ if (UNLIKELY(hasIndexingHeader)) {
+ preCapacity = butterfly->indexingHeader()->preCapacity(structure);
+ indexingPayloadSizeInBytes = butterfly->indexingHeader()->indexingPayloadSizeInBytes(structure);
} else {
- // Mark the properties.
- visitor.appendValues(butterfly->propertyStorage() - storageSize, storageSize);
-
- // Mark the array if appropriate.
- switch (structure->indexingType()) {
- 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);
- break;
- default:
- break;
- }
+ preCapacity = 0;
+ indexingPayloadSizeInBytes = 0;
+ }
+ size_t capacityInBytes = Butterfly::totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
+
+ // Mark the properties.
+ visitor.appendValues(butterfly->propertyStorage() - storageSize, storageSize);
+ visitor.copyLater(butterfly->base(preCapacity, propertyCapacity), capacityInBytes);
+
+ // Mark the array if appropriate.
+ switch (structure->indexingType()) {
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ visitor.appendValues(butterfly->contiguous(), butterfly->publicLength());
+ break;
+ 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);
+ break;
+ default:
+ break;
}
}
@@ -183,13 +212,23 @@ void JSObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
Butterfly* butterfly = thisObject->butterfly();
if (butterfly)
- thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSizeForKnownNonFinalObject());
+ thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
#if !ASSERT_DISABLED
visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
#endif
}
+void JSObject::copyBackingStore(JSCell* cell, CopyVisitor& visitor)
+{
+ JSObject* thisObject = jsCast<JSObject*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+
+ Butterfly* butterfly = thisObject->butterfly();
+ if (butterfly)
+ thisObject->copyButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
+}
+
void JSFinalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
JSFinalObject* thisObject = jsCast<JSFinalObject*>(cell);
@@ -203,9 +242,9 @@ void JSFinalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
Butterfly* butterfly = thisObject->butterfly();
if (butterfly)
- thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSizeForKnownFinalObject());
+ thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
- size_t storageSize = thisObject->structure()->inlineSizeForKnownFinalObject();
+ size_t storageSize = thisObject->structure()->inlineSize();
visitor.appendValues(thisObject->inlineStorage(), storageSize);
#if !ASSERT_DISABLED
@@ -235,6 +274,20 @@ bool JSObject::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned
case ALL_BLANK_INDEXING_TYPES:
break;
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ Butterfly* butterfly = thisObject->m_butterfly;
+ if (i >= butterfly->vectorLength())
+ return false;
+
+ JSValue value = butterfly->contiguous()[i].get();
+ if (value) {
+ slot.setValue(value);
+ return true;
+ }
+
+ return false;
+ }
+
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
if (i >= storage->length())
@@ -249,7 +302,7 @@ bool JSObject::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned
} else if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
SparseArrayValueMap::iterator it = map->find(i);
if (it != map->notFound()) {
- it->second.get(slot);
+ it->value.get(slot);
return true;
}
}
@@ -352,6 +405,16 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName,
case ALL_BLANK_INDEXING_TYPES:
break;
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ Butterfly* butterfly = thisObject->m_butterfly;
+ if (propertyName >= butterfly->vectorLength())
+ break;
+ butterfly->contiguous()[propertyName].set(exec->globalData(), thisObject, value);
+ if (propertyName >= butterfly->publicLength())
+ butterfly->setPublicLength(propertyName + 1);
+ return;
+ }
+
case NonArrayWithArrayStorage:
case ArrayWithArrayStorage: {
ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
@@ -426,7 +489,7 @@ ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists
// This will always be a new entry in the map, so no need to check we can write,
// and attributes are default so no need to set them.
if (value)
- map->add(this, i).iterator->second.set(globalData, this, value);
+ map->add(this, i).iterator->value.set(globalData, this, value);
}
Butterfly* newButterfly = storage->butterfly()->resizeArray(globalData, structure(), 0, ArrayStorage::sizeFor(0));
@@ -444,6 +507,11 @@ ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists
void JSObject::enterDictionaryIndexingMode(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ // NOTE: this is horribly inefficient, as it will perform two conversions. We could optimize
+ // this case if we ever cared.
+ enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertContiguousToArrayStorage(globalData));
+ break;
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage());
break;
@@ -466,6 +534,24 @@ void JSObject::notifyPresenceOfIndexedAccessors(JSGlobalData& globalData)
globalObject()->haveABadTime(globalData);
}
+WriteBarrier<Unknown>* JSObject::createInitialContiguous(JSGlobalData& globalData, unsigned length)
+{
+ ASSERT(length < MAX_ARRAY_INDEX);
+ IndexingType oldType = structure()->indexingType();
+ ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
+ ASSERT(!structure()->needsSlowPutIndexing());
+ ASSERT(!indexingShouldBeSparse());
+ unsigned vectorLength = std::max(length, BASE_VECTOR_LEN);
+ Butterfly* newButterfly = m_butterfly->growArrayRight(
+ globalData, structure(), structure()->outOfLineCapacity(), false, 0,
+ sizeof(EncodedJSValue) * vectorLength);
+ newButterfly->setPublicLength(length);
+ newButterfly->setVectorLength(vectorLength);
+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous);
+ setButterfly(globalData, newButterfly, newStructure);
+ return newButterfly->contiguous();
+}
+
ArrayStorage* JSObject::createArrayStorage(JSGlobalData& globalData, unsigned length, unsigned vectorLength)
{
IndexingType oldType = structure()->indexingType();
@@ -481,7 +567,7 @@ ArrayStorage* JSObject::createArrayStorage(JSGlobalData& globalData, unsigned le
result->m_sparseMap.clear();
result->m_numValuesInVector = 0;
result->m_indexBias = 0;
- Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), structure()->suggestedIndexingTransition());
+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), structure()->suggestedArrayStorageTransition());
setButterfly(globalData, newButterfly, newStructure);
return result;
}
@@ -491,9 +577,107 @@ ArrayStorage* JSObject::createInitialArrayStorage(JSGlobalData& globalData)
return createArrayStorage(globalData, 0, BASE_VECTOR_LEN);
}
+ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength)
+{
+ ASSERT(hasContiguous(structure()->indexingType()));
+
+ unsigned publicLength = m_butterfly->publicLength();
+ unsigned propertyCapacity = structure()->outOfLineCapacity();
+ unsigned propertySize = structure()->outOfLineSize();
+
+ Butterfly* newButterfly = Butterfly::createUninitialized(
+ globalData, 0, propertyCapacity, true, ArrayStorage::sizeFor(neededLength));
+
+ memcpy(
+ newButterfly->propertyStorage() - propertySize,
+ m_butterfly->propertyStorage() - propertySize,
+ propertySize * sizeof(EncodedJSValue));
+
+ ArrayStorage* newStorage = newButterfly->arrayStorage();
+ newStorage->setVectorLength(neededLength);
+ newStorage->setLength(publicLength);
+ newStorage->m_sparseMap.clear();
+ newStorage->m_indexBias = 0;
+ newStorage->m_numValuesInVector = 0;
+ for (unsigned i = publicLength; i--;) {
+ JSValue v = m_butterfly->contiguous()[i].get();
+ if (!v)
+ continue;
+ newStorage->m_vector[i].setWithoutWriteBarrier(v);
+ newStorage->m_numValuesInVector++;
+ }
+
+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition);
+ setButterfly(globalData, newButterfly, newStructure);
+ return newStorage;
+}
+
+ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition)
+{
+ return convertContiguousToArrayStorage(globalData, transition, m_butterfly->vectorLength());
+}
+
+ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData)
+{
+ return convertContiguousToArrayStorage(globalData, structure()->suggestedArrayStorageTransition());
+}
+
+WriteBarrier<Unknown>* JSObject::ensureContiguousSlow(JSGlobalData& globalData)
+{
+ switch (structure()->indexingType()) {
+ case ALL_BLANK_INDEXING_TYPES:
+ if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
+ return 0;
+ return createInitialContiguous(globalData, 0);
+
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+}
+
+ArrayStorage* JSObject::ensureArrayStorageSlow(JSGlobalData& globalData)
+{
+ switch (structure()->indexingType()) {
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ ASSERT(!indexingShouldBeSparse());
+ ASSERT(!structure()->needsSlowPutIndexing());
+ return convertContiguousToArrayStorage(globalData);
+
+ case ALL_BLANK_INDEXING_TYPES:
+ if (UNLIKELY(indexingShouldBeSparse()))
+ return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData);
+ return createInitialArrayStorage(globalData);
+
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+}
+
+Butterfly* JSObject::ensureIndexedStorageSlow(JSGlobalData& globalData)
+{
+ switch (structure()->indexingType()) {
+ case ALL_BLANK_INDEXING_TYPES:
+ if (UNLIKELY(structure()->needsSlowPutIndexing()))
+ return createInitialArrayStorage(globalData)->butterfly();
+ if (UNLIKELY(indexingShouldBeSparse()))
+ return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData)->butterfly();
+ return Butterfly::fromContiguous(createInitialContiguous(globalData, 0));
+
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+}
+
ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ // FIXME: This could be made way more efficient, if we cared.
+ return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertContiguousToArrayStorage(globalData));
+
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage());
@@ -513,6 +697,11 @@ ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(J
void JSObject::switchToSlowPutArrayStorage(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ convertContiguousToArrayStorage(globalData, AllocateSlowPutArrayStorage);
+ break;
+ }
+
case NonArrayWithArrayStorage:
case ArrayWithArrayStorage: {
Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), SwitchToSlowPutArrayStorage);
@@ -556,8 +745,7 @@ void JSObject::setPrototype(JSGlobalData& globalData, JSValue prototype)
if (shouldUseSlowPut(structure()->indexingType()))
return;
- newStructure = Structure::nonPropertyTransition(globalData, newStructure, SwitchToSlowPutArrayStorage);
- setStructure(globalData, newStructure);
+ switchToSlowPutArrayStorage(globalData);
}
bool JSObject::setPrototypeWithCycleCheck(JSGlobalData& globalData, JSValue prototype)
@@ -691,6 +879,14 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
case ALL_BLANK_INDEXING_TYPES:
return true;
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ Butterfly* butterfly = thisObject->m_butterfly;
+ if (i >= butterfly->vectorLength())
+ return true;
+ butterfly->contiguous()[i].clear();
+ return true;
+ }
+
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
@@ -703,7 +899,7 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
} else if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
SparseArrayValueMap::iterator it = map->find(i);
if (it != map->notFound()) {
- if (it->second.attributes & DontDelete)
+ if (it->value.attributes & DontDelete)
return false;
map->remove(it);
}
@@ -864,6 +1060,17 @@ void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNa
case ALL_BLANK_INDEXING_TYPES:
break;
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ Butterfly* butterfly = object->m_butterfly;
+ unsigned usedLength = butterfly->publicLength();
+ for (unsigned i = 0; i < usedLength; ++i) {
+ if (!butterfly->contiguous()[i])
+ continue;
+ propertyNames.add(Identifier::from(exec, i));
+ }
+ break;
+ }
+
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = object->m_butterfly->arrayStorage();
@@ -879,8 +1086,8 @@ void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNa
SparseArrayValueMap::const_iterator end = map->end();
for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) {
- if (mode == IncludeDontEnumProperties || !(it->second.attributes & DontEnum))
- keys.append(static_cast<unsigned>(it->first));
+ if (mode == IncludeDontEnumProperties || !(it->value.attributes & DontEnum))
+ keys.append(static_cast<unsigned>(it->key));
}
std::sort(keys.begin(), keys.end());
@@ -1089,9 +1296,6 @@ bool JSObject::defineOwnIndexedProperty(ExecState* exec, unsigned index, Propert
{
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
// FIXME: this will pessimistically assume that if attributes are missing then they'll default to false
@@ -1101,16 +1305,19 @@ bool JSObject::defineOwnIndexedProperty(ExecState* exec, unsigned index, Propert
ASSERT(!descriptor.isAccessorDescriptor());
return putDirectIndex(exec, index, descriptor.value(), 0, throwException ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
}
-
+
ensureArrayStorageExistsAndEnterDictionaryIndexingMode(exec->globalData());
}
+ if (descriptor.attributes() & (ReadOnly | Accessor))
+ notifyPresenceOfIndexedAccessors(exec->globalData());
+
SparseArrayValueMap* map = m_butterfly->arrayStorage()->m_sparseMap.get();
ASSERT(map);
// 1. Let current be the result of calling the [[GetOwnProperty]] internal method of O with property name P.
SparseArrayValueMap::AddResult result = map->add(this, index);
- SparseArrayEntry* entryInMap = &result.iterator->second;
+ SparseArrayEntry* entryInMap = &result.iterator->value;
// 2. Let extensible be the value of the [[Extensible]] internal property of O.
// 3. If current is undefined and extensible is false, then Reject.
@@ -1230,8 +1437,8 @@ bool JSObject::attemptToInterceptPutByIndexOnHoleForPrototype(ExecState* exec, J
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);
+ if (iter != storage->m_sparseMap->notFound() && (iter->value.attributes & (Accessor | ReadOnly))) {
+ iter->value.put(exec, thisValue, storage->m_sparseMap.get(), value, shouldThrow);
return true;
}
}
@@ -1253,6 +1460,35 @@ bool JSObject::attemptToInterceptPutByIndexOnHole(ExecState* exec, unsigned i, J
return asObject(prototypeValue)->attemptToInterceptPutByIndexOnHoleForPrototype(exec, this, i, value, shouldThrow);
}
+void JSObject::putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState* exec, unsigned i, JSValue value)
+{
+ ASSERT(hasContiguous(structure()->indexingType()));
+ ASSERT(!indexingShouldBeSparse());
+
+ // For us to get here, the index is either greater than the public length, or greater than
+ // or equal to the vector length.
+ ASSERT(i >= m_butterfly->vectorLength());
+
+ JSGlobalData& globalData = exec->globalData();
+
+ if (i >= MAX_ARRAY_INDEX - 1
+ || (i >= MIN_SPARSE_ARRAY_INDEX
+ && !isDenseEnoughForVector(i, countElementsInContiguous(m_butterfly)))) {
+ ASSERT(i <= MAX_ARRAY_INDEX);
+ convertContiguousToArrayStorage(globalData, AllocateArrayStorage);
+ SparseArrayValueMap* map = allocateSparseIndexMap(globalData);
+ map->putEntry(exec, this, i, value, false);
+ ASSERT(i >= arrayStorage()->length());
+ arrayStorage()->setLength(i + 1);
+ return;
+ }
+
+ ensureContiguousLength(globalData, i + 1);
+
+ ASSERT(i < m_butterfly->vectorLength());
+ m_butterfly->contiguous()[i].set(globalData, this, value);
+}
+
void JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, bool shouldThrow, ArrayStorage* storage)
{
JSGlobalData& globalData = exec->globalData();
@@ -1315,7 +1551,7 @@ void JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, uns
WriteBarrier<Unknown>* vector = storage->m_vector;
SparseArrayValueMap::const_iterator end = map->end();
for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it)
- vector[it->first].set(globalData, this, it->second.getNonSparseMode());
+ vector[it->key].set(globalData, this, it->value.getNonSparseMode());
deallocateSparseIndexMap();
// Store the new property into the vector.
@@ -1335,17 +1571,29 @@ void JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES: {
if (indexingShouldBeSparse()) {
- putByIndexBeyondVectorLengthWithArrayStorage(exec, i, value, shouldThrow, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData));
+ putByIndexBeyondVectorLengthWithArrayStorage(
+ exec, i, value, shouldThrow,
+ ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData));
+ break;
+ }
+ if (i >= MIN_SPARSE_ARRAY_INDEX) {
+ putByIndexBeyondVectorLengthWithArrayStorage(
+ exec, i, value, shouldThrow, createArrayStorage(globalData, 0, 0));
break;
}
- if (!isDenseEnoughForVector(i, 0) || i >= MAX_STORAGE_VECTOR_LENGTH) {
- putByIndexBeyondVectorLengthWithArrayStorage(exec, i, value, shouldThrow, createArrayStorage(globalData, 0, 0));
+ if (structure()->needsSlowPutIndexing()) {
+ ArrayStorage* storage = createArrayStorage(globalData, i + 1, getNewVectorLength(0, 0, i + 1));
+ storage->m_vector[i].set(globalData, this, value);
+ storage->m_numValuesInVector++;
break;
}
+
+ createInitialContiguous(globalData, i + 1)[i].set(globalData, this, value);
+ break;
+ }
- ArrayStorage* storage = createArrayStorage(globalData, i + 1, getNewVectorLength(0, 0, i + 1));
- storage->m_vector[i].set(globalData, this, value);
- storage->m_numValuesInVector = 1;
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, i, value);
break;
}
@@ -1371,8 +1619,10 @@ void JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue
bool JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, unsigned attributes, PutDirectIndexMode mode, ArrayStorage* storage)
{
JSGlobalData& globalData = exec->globalData();
-
+
// i should be a valid array index that is outside of the current vector.
+ ASSERT(hasArrayStorage(structure()->indexingType()));
+ ASSERT(arrayStorage() == storage);
ASSERT(i >= storage->vectorLength() || attributes);
ASSERT(i <= MAX_ARRAY_INDEX);
@@ -1431,7 +1681,7 @@ bool JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState* exec,
WriteBarrier<Unknown>* vector = storage->m_vector;
SparseArrayValueMap::const_iterator end = map->end();
for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it)
- vector[it->first].set(globalData, this, it->second.getNonSparseMode());
+ vector[it->key].set(globalData, this, it->value.getNonSparseMode());
deallocateSparseIndexMap();
// Store the new property into the vector.
@@ -1454,14 +1704,32 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV
switch (structure()->indexingType()) {
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)
- return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, createArrayStorage(globalData, 0, 0));
+ if (indexingShouldBeSparse() || attributes) {
+ return putDirectIndexBeyondVectorLengthWithArrayStorage(
+ exec, i, value, attributes, mode,
+ ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData));
+ }
+ if (i >= MIN_SPARSE_ARRAY_INDEX) {
+ return putDirectIndexBeyondVectorLengthWithArrayStorage(
+ exec, i, value, attributes, mode, createArrayStorage(globalData, 0, 0));
+ }
+ if (structure()->needsSlowPutIndexing()) {
+ ArrayStorage* storage = createArrayStorage(globalData, i + 1, getNewVectorLength(0, 0, i + 1));
+ storage->m_vector[i].set(globalData, this, value);
+ storage->m_numValuesInVector++;
+ return true;
+ }
- ArrayStorage* storage = createArrayStorage(globalData, i + 1, getNewVectorLength(0, 0, i + 1));
- storage->m_vector[i].set(globalData, this, value);
- storage->m_numValuesInVector = 1;
+ createInitialContiguous(globalData, i + 1)[i].set(globalData, this, value);
+ return true;
+ }
+
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ if (attributes & (ReadOnly | Accessor)) {
+ return putDirectIndexBeyondVectorLengthWithArrayStorage(
+ exec, i, value, attributes, mode, convertContiguousToArrayStorage(globalData));
+ }
+ putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, i, value);
return true;
}
@@ -1486,12 +1754,7 @@ ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned currentVectorLength
else if (!currentVectorLength)
increasedLength = std::max(desiredLength, lastArraySize);
else {
- // Mathematically equivalent to:
- // increasedLength = (newLength * 3 + 1) / 2;
- // or:
- // increasedLength = (unsigned)ceil(newLength * 1.5));
- // This form is not prone to internal overflow.
- increasedLength = desiredLength + (desiredLength >> 1) + (desiredLength & 1);
+ increasedLength = timesThreePlusOneDividedByTwo(desiredLength);
}
ASSERT(increasedLength >= desiredLength);
@@ -1511,9 +1774,10 @@ ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned desiredLength)
vectorLength = 0;
length = 0;
break;
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- vectorLength = m_butterfly->arrayStorage()->vectorLength();
- length = m_butterfly->arrayStorage()->length();
+ vectorLength = m_butterfly->vectorLength();
+ length = m_butterfly->publicLength();
break;
default:
CRASH();
@@ -1522,6 +1786,16 @@ ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned desiredLength)
return getNewVectorLength(vectorLength, length, desiredLength);
}
+unsigned JSObject::countElementsInContiguous(Butterfly* butterfly)
+{
+ unsigned numValues = 0;
+ for (unsigned i = butterfly->publicLength(); i--;) {
+ if (butterfly->contiguous()[i])
+ numValues++;
+ }
+ return numValues;
+}
+
bool JSObject::increaseVectorLength(JSGlobalData& globalData, unsigned newLength)
{
// This function leaves the array in an internally inconsistent state, because it does not move any values from sparse value map
@@ -1530,6 +1804,10 @@ bool JSObject::increaseVectorLength(JSGlobalData& globalData, unsigned newLength
return false;
ArrayStorage* storage = arrayStorage();
+
+ if (newLength >= MIN_SPARSE_ARRAY_INDEX
+ && !isDenseEnoughForVector(newLength, storage->m_numValuesInVector))
+ return false;
unsigned indexBias = storage->m_indexBias;
unsigned vectorLength = storage->vectorLength();
@@ -1561,6 +1839,22 @@ bool JSObject::increaseVectorLength(JSGlobalData& globalData, unsigned newLength
return true;
}
+void JSObject::ensureContiguousLengthSlow(JSGlobalData& globalData, unsigned length)
+{
+ ASSERT(length < MAX_ARRAY_INDEX);
+ ASSERT(hasContiguous(structure()->indexingType()));
+ ASSERT(length > m_butterfly->vectorLength());
+
+ unsigned newVectorLength = std::min(
+ length << 1,
+ MAX_STORAGE_VECTOR_LENGTH);
+ m_butterfly = m_butterfly->growArrayRight(
+ globalData, structure(), structure()->outOfLineCapacity(), true,
+ m_butterfly->vectorLength() * sizeof(EncodedJSValue),
+ newVectorLength * sizeof(EncodedJSValue));
+ m_butterfly->setVectorLength(newVectorLength);
+}
+
Butterfly* JSObject::growOutOfLineStorage(JSGlobalData& globalData, size_t oldSize, size_t newSize)
{
ASSERT(newSize > oldSize);
@@ -1589,6 +1883,17 @@ bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Prope
case ALL_BLANK_INDEXING_TYPES:
return false;
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ Butterfly* butterfly = object->m_butterfly;
+ if (i >= butterfly->vectorLength())
+ return false;
+ JSValue value = butterfly->contiguous()[i].get();
+ if (!value)
+ return false;
+ descriptor.setDescriptor(value, 0);
+ return true;
+ }
+
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = object->m_butterfly->arrayStorage();
if (i >= storage->length())
@@ -1604,7 +1909,7 @@ bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Prope
SparseArrayValueMap::iterator it = map->find(i);
if (it == map->notFound())
return false;
- it->second.get(descriptor);
+ it->value.get(descriptor);
return true;
}
return false;
diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h
index 4b9cff5ad..9204099cb 100644
--- a/Source/JavaScriptCore/runtime/JSObject.h
+++ b/Source/JavaScriptCore/runtime/JSObject.h
@@ -109,7 +109,13 @@ namespace JSC {
public:
typedef JSCell Base;
+ static size_t allocationSize(size_t inlineCapacity)
+ {
+ return sizeof(JSObject) + inlineCapacity * sizeof(WriteBarrierBase<Unknown>);
+ }
+
JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
+ JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&);
JS_EXPORT_PRIVATE static String className(const JSObject*);
@@ -148,8 +154,9 @@ namespace JSC {
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
return 0;
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return m_butterfly->arrayStorage()->length();
+ return m_butterfly->publicLength();
default:
ASSERT_NOT_REACHED();
return 0;
@@ -161,8 +168,9 @@ namespace JSC {
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
return 0;
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return m_butterfly->arrayStorage()->vectorLength();
+ return m_butterfly->vectorLength();
default:
ASSERT_NOT_REACHED();
return 0;
@@ -207,6 +215,8 @@ namespace JSC {
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
return false;
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ return i < m_butterfly->vectorLength() && m_butterfly->contiguous()[i];
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return i < m_butterfly->arrayStorage()->vectorLength() && m_butterfly->arrayStorage()->m_vector[i];
default:
@@ -218,6 +228,8 @@ namespace JSC {
JSValue getIndexQuickly(unsigned i)
{
switch (structure()->indexingType()) {
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ return m_butterfly->contiguous()[i].get();
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return m_butterfly->arrayStorage()->m_vector[i].get();
default:
@@ -231,12 +243,13 @@ namespace JSC {
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
break;
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ if (i < m_butterfly->publicLength())
+ return m_butterfly->contiguous()[i].get();
+ break;
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- if (i < m_butterfly->arrayStorage()->vectorLength()) {
- JSValue v = m_butterfly->arrayStorage()->m_vector[i].get();
- if (v)
- return v;
- }
+ if (i < m_butterfly->arrayStorage()->vectorLength())
+ return m_butterfly->arrayStorage()->m_vector[i].get();
break;
default:
ASSERT_NOT_REACHED();
@@ -267,9 +280,10 @@ namespace JSC {
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
return false;
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
case NonArrayWithArrayStorage:
case ArrayWithArrayStorage:
- return i < m_butterfly->arrayStorage()->vectorLength();
+ return i < m_butterfly->vectorLength();
case NonArrayWithSlowPutArrayStorage:
case ArrayWithSlowPutArrayStorage:
return i < m_butterfly->arrayStorage()->vectorLength()
@@ -285,8 +299,9 @@ namespace JSC {
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
return false;
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return i < m_butterfly->arrayStorage()->vectorLength();
+ return i < m_butterfly->vectorLength();
default:
ASSERT_NOT_REACHED();
return false;
@@ -296,15 +311,23 @@ namespace JSC {
void setIndexQuickly(JSGlobalData& globalData, unsigned i, JSValue v)
{
switch (structure()->indexingType()) {
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ ASSERT(i < m_butterfly->vectorLength());
+ m_butterfly->contiguous()[i].set(globalData, this, v);
+ if (i >= m_butterfly->publicLength())
+ m_butterfly->setPublicLength(i + 1);
+ break;
+ }
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
- WriteBarrier<Unknown>& x = m_butterfly->arrayStorage()->m_vector[i];
- if (!x) {
- ArrayStorage* storage = m_butterfly->arrayStorage();
+ ArrayStorage* storage = m_butterfly->arrayStorage();
+ WriteBarrier<Unknown>& x = storage->m_vector[i];
+ JSValue old = x.get();
+ x.set(globalData, this, v);
+ if (!old) {
++storage->m_numValuesInVector;
if (i >= storage->length())
storage->setLength(i + 1);
}
- x.set(globalData, this, v);
break;
}
default:
@@ -315,6 +338,12 @@ namespace JSC {
void initializeIndex(JSGlobalData& globalData, unsigned i, JSValue v)
{
switch (structure()->indexingType()) {
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ ASSERT(i < m_butterfly->publicLength());
+ ASSERT(i < m_butterfly->vectorLength());
+ m_butterfly->contiguous()[i].set(globalData, this, v);
+ break;
+ }
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = m_butterfly->arrayStorage();
ASSERT(i < storage->length());
@@ -327,10 +356,25 @@ namespace JSC {
}
}
+ bool hasSparseMap()
+ {
+ switch (structure()->indexingType()) {
+ case ALL_BLANK_INDEXING_TYPES:
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ return false;
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ return m_butterfly->arrayStorage()->m_sparseMap;
+ default:
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+ }
+
bool inSparseIndexingMode()
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
return false;
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return m_butterfly->arrayStorage()->inSparseMode();
@@ -448,10 +492,10 @@ namespace JSC {
{
PropertyOffset result;
size_t offsetInInlineStorage = location - inlineStorageUnsafe();
- if (offsetInInlineStorage < static_cast<size_t>(inlineStorageCapacity))
+ if (offsetInInlineStorage < static_cast<size_t>(firstOutOfLineOffset))
result = offsetInInlineStorage;
else
- result = outOfLineStorage() - location + (inlineStorageCapacity - 1);
+ result = outOfLineStorage() - location + (firstOutOfLineOffset - 1);
validateOffset(result, structure()->typeInfo().type());
return result;
}
@@ -481,7 +525,7 @@ namespace JSC {
bool isNameScopeObject() const;
bool isActivationObject() const;
bool isErrorInstance() const;
- bool isGlobalThis() const;
+ bool isProxy() const;
void seal(JSGlobalData&);
void freeze(JSGlobalData&);
@@ -528,23 +572,34 @@ namespace JSC {
// foo->attemptToInterceptPutByIndexOnHole(...);
bool attemptToInterceptPutByIndexOnHoleForPrototype(ExecState*, JSValue thisValue, unsigned propertyName, JSValue, bool shouldThrow);
+ // Returns 0 if contiguous storage cannot be created - either because
+ // indexing should be sparse or because we're having a bad time.
+ WriteBarrier<Unknown>* ensureContiguous(JSGlobalData& globalData)
+ {
+ if (LIKELY(hasContiguous(structure()->indexingType())))
+ return m_butterfly->contiguous();
+
+ return ensureContiguousSlow(globalData);
+ }
+
// Ensure that the object is in a mode where it has array storage. Use
// this if you're about to perform actions that would have required the
// object to be converted to have array storage, if it didn't have it
// already.
ArrayStorage* ensureArrayStorage(JSGlobalData& globalData)
{
- switch (structure()->indexingType()) {
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ if (LIKELY(hasArrayStorage(structure()->indexingType())))
return m_butterfly->arrayStorage();
-
- case ALL_BLANK_INDEXING_TYPES:
- return createInitialArrayStorage(globalData);
-
- default:
- ASSERT_NOT_REACHED();
- return 0;
- }
+
+ return ensureArrayStorageSlow(globalData);
+ }
+
+ Butterfly* ensureIndexedStorage(JSGlobalData& globalData)
+ {
+ if (LIKELY(hasIndexedProperties(structure()->indexingType())))
+ return m_butterfly;
+
+ return ensureIndexedStorageSlow(globalData);
}
static size_t offsetOfInlineStorage();
@@ -585,6 +640,7 @@ namespace JSC {
void resetInheritorID(JSGlobalData&);
void visitButterfly(SlotVisitor&, Butterfly*, size_t storageSize);
+ void copyButterfly(CopyVisitor&, Butterfly*, size_t storageSize);
// Call this if you know that the object is in a mode where it has array
// storage. This will assert otherwise.
@@ -609,11 +665,16 @@ namespace JSC {
ArrayStorage* createArrayStorage(JSGlobalData&, unsigned length, unsigned vectorLength);
ArrayStorage* createInitialArrayStorage(JSGlobalData&);
+ WriteBarrier<Unknown>* createInitialContiguous(JSGlobalData&, unsigned length);
+ ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength);
+ ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&, NonPropertyTransition);
+ ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&);
ArrayStorage* ensureArrayStorageExistsAndEnterDictionaryIndexingMode(JSGlobalData&);
bool defineOwnNonIndexProperty(ExecState*, PropertyName, PropertyDescriptor&, bool throwException);
+ void putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState*, unsigned propertyName, JSValue);
void putByIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, bool shouldThrow, ArrayStorage*);
bool increaseVectorLength(JSGlobalData&, unsigned newLength);
@@ -624,6 +685,56 @@ namespace JSC {
void notifyPresenceOfIndexedAccessors(JSGlobalData&);
bool attemptToInterceptPutByIndexOnHole(ExecState*, unsigned index, JSValue, bool shouldThrow);
+
+ // Call this if you want setIndexQuickly to succeed and you're sure that
+ // the array is contiguous.
+ void ensureContiguousLength(JSGlobalData& globalData, unsigned length)
+ {
+ ASSERT(length < MAX_ARRAY_INDEX);
+ ASSERT(hasContiguous(structure()->indexingType()));
+
+ if (m_butterfly->vectorLength() < length)
+ ensureContiguousLengthSlow(globalData, length);
+
+ if (m_butterfly->publicLength() < length)
+ m_butterfly->setPublicLength(length);
+ }
+
+ unsigned countElementsInContiguous(Butterfly*);
+
+ template<IndexingType indexingType>
+ WriteBarrier<Unknown>* indexingData()
+ {
+ switch (indexingType) {
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ return m_butterfly->contiguous();
+
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ return m_butterfly->arrayStorage()->m_vector;
+
+ default:
+ CRASH();
+ return 0;
+ }
+ }
+
+ template<IndexingType indexingType>
+ unsigned relevantLength()
+ {
+ switch (indexingType) {
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ return m_butterfly->publicLength();
+
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ return std::min(
+ m_butterfly->arrayStorage()->length(),
+ m_butterfly->arrayStorage()->vectorLength());
+
+ default:
+ CRASH();
+ return 0;
+ }
+ }
private:
friend class LLIntOffsetsExtractor;
@@ -658,6 +769,12 @@ namespace JSC {
JS_EXPORT_PRIVATE bool getOwnPropertySlotSlow(ExecState*, PropertyName, PropertySlot&);
+ void ensureContiguousLengthSlow(JSGlobalData&, unsigned length);
+
+ WriteBarrier<Unknown>* ensureContiguousSlow(JSGlobalData&);
+ ArrayStorage* ensureArrayStorageSlow(JSGlobalData&);
+ Butterfly* ensureIndexedStorageSlow(JSGlobalData&);
+
protected:
Butterfly* m_butterfly;
};
@@ -677,11 +794,6 @@ namespace JSC {
return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
}
- static bool hasInlineStorage()
- {
- return false;
- }
-
protected:
explicit JSNonFinalObject(JSGlobalData& globalData, Structure* structure, Butterfly* butterfly = 0)
: JSObject(globalData, structure, butterfly)
@@ -709,45 +821,43 @@ namespace JSC {
static JSFinalObject* create(ExecState*, Structure*);
static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
{
- return Structure::create(globalData, globalObject, prototype, TypeInfo(FinalObjectType, StructureFlags), &s_info);
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(FinalObjectType, StructureFlags), &s_info, NonArray, INLINE_STORAGE_CAPACITY);
}
JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
static JS_EXPORTDATA const ClassInfo s_info;
- static bool hasInlineStorage()
- {
- return true;
- }
protected:
void visitChildrenCommon(SlotVisitor&);
void finishCreation(JSGlobalData& globalData)
{
Base::finishCreation(globalData);
- ASSERT(!(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) % sizeof(double)));
- ASSERT(this->structure()->inlineCapacity() == static_cast<unsigned>(inlineStorageCapacity));
- ASSERT(this->structure()->totalStorageCapacity() == static_cast<unsigned>(inlineStorageCapacity));
+ ASSERT(structure()->totalStorageCapacity() == structure()->inlineCapacity());
ASSERT(classInfo());
}
private:
friend class LLIntOffsetsExtractor;
-
+
explicit JSFinalObject(JSGlobalData& globalData, Structure* structure)
: JSObject(globalData, structure)
{
}
static const unsigned StructureFlags = JSObject::StructureFlags;
-
- WriteBarrierBase<Unknown> m_inlineStorage[INLINE_STORAGE_CAPACITY];
};
inline JSFinalObject* JSFinalObject::create(ExecState* exec, Structure* structure)
{
- JSFinalObject* finalObject = new (NotNull, allocateCell<JSFinalObject>(*exec->heap())) JSFinalObject(exec->globalData(), structure);
+ JSFinalObject* finalObject = new (
+ NotNull,
+ allocateCell<JSFinalObject>(
+ *exec->heap(),
+ allocationSize(structure->inlineCapacity())
+ )
+ ) JSFinalObject(exec->globalData(), structure);
finalObject->finishCreation(exec->globalData());
return finalObject;
}
@@ -764,7 +874,7 @@ inline bool isJSFinalObject(JSValue value)
inline size_t JSObject::offsetOfInlineStorage()
{
- return OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage);
+ return sizeof(JSObject);
}
inline bool JSObject::isGlobalObject() const
@@ -792,9 +902,9 @@ inline bool JSObject::isErrorInstance() const
return structure()->typeInfo().type() == ErrorInstanceType;
}
-inline bool JSObject::isGlobalThis() const
+inline bool JSObject::isProxy() const
{
- return structure()->typeInfo().type() == GlobalThisType;
+ return structure()->typeInfo().type() == ProxyType;
}
inline void JSObject::setButterfly(JSGlobalData& globalData, Butterfly* butterfly, Structure* structure)
@@ -856,14 +966,14 @@ inline JSValue JSObject::prototype() const
return structure()->storedPrototype();
}
-inline bool JSCell::inherits(const ClassInfo* info) const
+inline const MethodTable* JSCell::methodTable() const
{
- return classInfo()->isSubClassOf(info);
+ return &classInfo()->methodTable;
}
-inline const MethodTable* JSCell::methodTable() const
+inline bool JSCell::inherits(const ClassInfo* info) const
{
- return &classInfo()->methodTable;
+ return classInfo()->isSubClassOf(info);
}
// this method is here to be after the inline declaration of JSCell::inherits
@@ -1257,6 +1367,8 @@ inline int offsetRelativeToBase(PropertyOffset offset)
return JSObject::offsetOfInlineStorage() + offsetInInlineStorage(offset) * sizeof(EncodedJSValue);
}
+COMPILE_ASSERT(!(sizeof(JSObject) % sizeof(WriteBarrierBase<Unknown>)), JSObject_inline_storage_has_correct_alignment);
+
} // namespace JSC
#endif // JSObject_h
diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
index 897ceff8c..225401fbd 100644
--- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
+++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
@@ -33,8 +33,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(JSPropertyNameIterator);
-
const ClassInfo JSPropertyNameIterator::s_info = { "JSPropertyNameIterator", 0, 0, 0, CREATE_METHOD_TABLE(JSPropertyNameIterator) };
inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlots)
diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h
index 057ffe293..e59a5c6a4 100644
--- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h
+++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h
@@ -48,6 +48,8 @@ namespace JSC {
static JSPropertyNameIterator* create(ExecState*, JSObject*);
+ static const bool needsDestruction = true;
+ static const bool hasImmortalStructure = true;
static void destroy(JSCell*);
static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
@@ -57,14 +59,6 @@ namespace JSC {
static void visitChildren(JSCell*, SlotVisitor&);
- bool getOffset(size_t i, PropertyOffset& offset)
- {
- if (i >= m_numCacheableSlots)
- return false;
- offset = i + m_offsetBase;
- return true;
- }
-
JSValue get(ExecState*, JSObject*, size_t i);
size_t size() { return m_jsStringsSize; }
@@ -88,7 +82,7 @@ namespace JSC {
PropertyNameArrayData::PropertyNameVector& propertyNameVector = propertyNameArrayData->propertyNameVector();
for (size_t i = 0; i < m_jsStringsSize; ++i)
m_jsStrings[i].set(exec->globalData(), this, jsOwnedString(exec, propertyNameVector[i].string()));
- m_offsetBase = object->structure()->firstValidOffset();
+ m_cachedStructureInlineCapacity = object->structure()->inlineCapacity();
}
private:
@@ -100,7 +94,7 @@ namespace JSC {
WriteBarrier<StructureChain> m_cachedPrototypeChain;
uint32_t m_numCacheableSlots;
uint32_t m_jsStringsSize;
- PropertyOffset m_offsetBase;
+ unsigned m_cachedStructureInlineCapacity;
OwnArrayPtr<WriteBarrier<Unknown> > m_jsStrings;
};
diff --git a/Source/JavaScriptCore/runtime/JSProxy.cpp b/Source/JavaScriptCore/runtime/JSProxy.cpp
new file mode 100644
index 000000000..7108dcfa0
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSProxy.cpp
@@ -0,0 +1,129 @@
+/*
+ * 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. AND ITS CONTRIBUTORS ``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 ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSProxy.h"
+
+#include "JSGlobalObject.h"
+
+namespace JSC {
+
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSProxy);
+
+const ClassInfo JSProxy::s_info = { "JSProxy", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSProxy) };
+
+void JSProxy::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSProxy* thisObject = jsCast<JSProxy*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+
+ Base::visitChildren(thisObject, visitor);
+ visitor.append(&thisObject->m_target);
+}
+
+void JSProxy::setTarget(JSGlobalData& globalData, JSGlobalObject* globalObject)
+{
+ ASSERT_ARG(globalObject, globalObject);
+ m_target.set(globalData, this, globalObject);
+ setPrototype(globalData, globalObject->prototype());
+ resetInheritorID(globalData);
+}
+
+String JSProxy::className(const JSObject* object)
+{
+ const JSProxy* thisObject = jsCast<const JSProxy*>(object);
+ return thisObject->target()->methodTable()->className(thisObject->target());
+}
+
+bool JSProxy::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+{
+ JSProxy* thisObject = jsCast<JSProxy*>(cell);
+ return thisObject->target()->methodTable()->getOwnPropertySlot(thisObject->target(), exec, propertyName, slot);
+}
+
+bool JSProxy::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, PropertySlot& slot)
+{
+ JSProxy* thisObject = jsCast<JSProxy*>(cell);
+ return thisObject->target()->methodTable()->getOwnPropertySlotByIndex(thisObject->target(), exec, propertyName, slot);
+}
+
+bool JSProxy::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
+{
+ JSProxy* thisObject = jsCast<JSProxy*>(object);
+ return thisObject->target()->methodTable()->getOwnPropertyDescriptor(thisObject->target(), exec, propertyName, descriptor);
+}
+
+void JSProxy::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
+{
+ JSProxy* thisObject = jsCast<JSProxy*>(cell);
+ thisObject->target()->methodTable()->put(thisObject->target(), exec, propertyName, value, slot);
+}
+
+void JSProxy::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
+{
+ JSProxy* thisObject = jsCast<JSProxy*>(cell);
+ thisObject->target()->methodTable()->putByIndex(thisObject->target(), exec, propertyName, value, shouldThrow);
+}
+
+void JSProxy::putDirectVirtual(JSObject* object, ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes)
+{
+ JSProxy* thisObject = jsCast<JSProxy*>(object);
+ thisObject->target()->putDirectVirtual(thisObject->target(), exec, propertyName, value, attributes);
+}
+
+bool JSProxy::defineOwnProperty(JSC::JSObject* object, JSC::ExecState* exec, JSC::PropertyName propertyName, JSC::PropertyDescriptor& descriptor, bool shouldThrow)
+{
+ JSProxy* thisObject = jsCast<JSProxy*>(object);
+ return thisObject->target()->methodTable()->defineOwnProperty(thisObject->target(), exec, propertyName, descriptor, shouldThrow);
+}
+
+bool JSProxy::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
+{
+ JSProxy* thisObject = jsCast<JSProxy*>(cell);
+ return thisObject->target()->methodTable()->deleteProperty(thisObject->target(), exec, propertyName);
+}
+
+bool JSProxy::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName)
+{
+ JSProxy* thisObject = jsCast<JSProxy*>(cell);
+ return thisObject->target()->methodTable()->deletePropertyByIndex(thisObject->target(), exec, propertyName);
+}
+
+void JSProxy::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ JSProxy* thisObject = jsCast<JSProxy*>(object);
+ thisObject->target()->methodTable()->getPropertyNames(thisObject->target(), exec, propertyNames, mode);
+}
+
+void JSProxy::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ JSProxy* thisObject = jsCast<JSProxy*>(object);
+ thisObject->target()->methodTable()->getOwnPropertyNames(thisObject->target(), exec, propertyNames, mode);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSProxy.h b/Source/JavaScriptCore/runtime/JSProxy.h
new file mode 100644
index 000000000..144085a79
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSProxy.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2011 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 JSProxy_h
+#define JSProxy_h
+
+#include "JSDestructibleObject.h"
+
+namespace JSC {
+
+class JSProxy : public JSDestructibleObject {
+public:
+ typedef JSDestructibleObject Base;
+
+ static JSProxy* create(JSGlobalData& globalData, Structure* structure, JSObject* target)
+ {
+ JSProxy* proxy = new (NotNull, allocateCell<JSProxy>(globalData.heap)) JSProxy(globalData, structure);
+ proxy->finishCreation(globalData, target);
+ return proxy;
+ }
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ProxyType, StructureFlags), &s_info);
+ }
+
+ static JS_EXPORTDATA const ClassInfo s_info;
+
+ JSObject* target() const { return m_target.get(); }
+
+protected:
+ JSProxy(JSGlobalData& globalData, Structure* structure)
+ : JSDestructibleObject(globalData, structure)
+ {
+ }
+
+ void finishCreation(JSGlobalData& globalData)
+ {
+ Base::finishCreation(globalData);
+ }
+
+ void finishCreation(JSGlobalData& globalData, JSObject* target)
+ {
+ Base::finishCreation(globalData);
+ m_target.set(globalData, this, target);
+ }
+
+ static const unsigned StructureFlags = OverridesVisitChildren | OverridesGetOwnPropertySlot | OverridesGetPropertyNames | Base::StructureFlags;
+
+ JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
+
+ JS_EXPORT_PRIVATE void setTarget(JSGlobalData&, JSGlobalObject*);
+
+ JS_EXPORT_PRIVATE static String className(const JSObject*);
+ JS_EXPORT_PRIVATE static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
+ JS_EXPORT_PRIVATE static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned, PropertySlot&);
+ JS_EXPORT_PRIVATE static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
+ JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
+ JS_EXPORT_PRIVATE static void putByIndex(JSCell*, ExecState*, unsigned, JSValue, bool shouldThrow);
+ JS_EXPORT_PRIVATE static void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes);
+ JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName);
+ JS_EXPORT_PRIVATE static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned);
+ JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow);
+
+private:
+ WriteBarrier<JSObject> m_target;
+};
+
+} // namespace JSC
+
+#endif // JSProxy_h
diff --git a/Source/JavaScriptCore/runtime/JSScope.cpp b/Source/JavaScriptCore/runtime/JSScope.cpp
index b22211970..8fd49b861 100644
--- a/Source/JavaScriptCore/runtime/JSScope.cpp
+++ b/Source/JavaScriptCore/runtime/JSScope.cpp
@@ -33,7 +33,7 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(JSScope);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSScope);
void JSScope::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
diff --git a/Source/JavaScriptCore/runtime/JSString.h b/Source/JavaScriptCore/runtime/JSString.h
index 1500636f2..245c48a51 100644
--- a/Source/JavaScriptCore/runtime/JSString.h
+++ b/Source/JavaScriptCore/runtime/JSString.h
@@ -71,6 +71,8 @@ namespace JSC {
typedef JSCell Base;
+ static const bool needsDestruction = true;
+ static const bool hasImmortalStructure = true;
static void destroy(JSCell*);
private:
diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp b/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp
index 765e1d3d4..7dcde4700 100644
--- a/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp
@@ -61,8 +61,8 @@ void JSSymbolTableObject::getOwnNonIndexPropertyNames(JSObject* object, ExecStat
JSSymbolTableObject* thisObject = jsCast<JSSymbolTableObject*>(object);
SymbolTable::const_iterator end = thisObject->symbolTable()->end();
for (SymbolTable::const_iterator it = thisObject->symbolTable()->begin(); it != end; ++it) {
- if (!(it->second.getAttributes() & DontEnum) || (mode == IncludeDontEnumProperties))
- propertyNames.add(Identifier(exec, it->first.get()));
+ if (!(it->value.getAttributes() & DontEnum) || (mode == IncludeDontEnumProperties))
+ propertyNames.add(Identifier(exec, it->key.get()));
}
JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode);
diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.h b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h
index b4d313c19..913679f80 100644
--- a/Source/JavaScriptCore/runtime/JSSymbolTableObject.h
+++ b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h
@@ -76,7 +76,7 @@ inline bool symbolTableGet(
SymbolTable::iterator iter = symbolTable.find(propertyName.publicName());
if (iter == symbolTable.end())
return false;
- SymbolTableEntry::Fast entry = iter->second;
+ SymbolTableEntry::Fast entry = iter->value;
ASSERT(!entry.isNull());
slot.setValue(object->registerAt(entry.getIndex()).get());
return true;
@@ -90,7 +90,7 @@ inline bool symbolTableGet(
SymbolTable::iterator iter = symbolTable.find(propertyName.publicName());
if (iter == symbolTable.end())
return false;
- SymbolTableEntry::Fast entry = iter->second;
+ SymbolTableEntry::Fast entry = iter->value;
ASSERT(!entry.isNull());
descriptor.setDescriptor(
object->registerAt(entry.getIndex()).get(), entry.getAttributes() | DontDelete);
@@ -106,7 +106,7 @@ inline bool symbolTableGet(
SymbolTable::iterator iter = symbolTable.find(propertyName.publicName());
if (iter == symbolTable.end())
return false;
- SymbolTableEntry::Fast entry = iter->second;
+ SymbolTableEntry::Fast entry = iter->value;
ASSERT(!entry.isNull());
slot.setValue(object->registerAt(entry.getIndex()).get());
slotIsWriteable = !entry.isReadOnly();
@@ -126,7 +126,7 @@ inline bool symbolTablePut(
if (iter == symbolTable.end())
return false;
bool wasFat;
- SymbolTableEntry::Fast fastEntry = iter->second.getFast(wasFat);
+ SymbolTableEntry::Fast fastEntry = iter->value.getFast(wasFat);
ASSERT(!fastEntry.isNull());
if (fastEntry.isReadOnly()) {
if (shouldThrow)
@@ -134,7 +134,7 @@ inline bool symbolTablePut(
return true;
}
if (UNLIKELY(wasFat))
- iter->second.notifyWrite();
+ iter->value.notifyWrite();
object->registerAt(fastEntry.getIndex()).set(globalData, object, value);
return true;
}
@@ -149,7 +149,7 @@ inline bool symbolTablePutWithAttributes(
SymbolTable::iterator iter = object->symbolTable()->find(propertyName.publicName());
if (iter == object->symbolTable()->end())
return false;
- SymbolTableEntry& entry = iter->second;
+ SymbolTableEntry& entry = iter->value;
ASSERT(!entry.isNull());
entry.notifyWrite();
entry.setAttributes(attributes);
diff --git a/Source/JavaScriptCore/runtime/JSType.h b/Source/JavaScriptCore/runtime/JSType.h
index b8ab330f5..03f4a7790 100644
--- a/Source/JavaScriptCore/runtime/JSType.h
+++ b/Source/JavaScriptCore/runtime/JSType.h
@@ -48,7 +48,7 @@ enum JSType {
NameInstanceType,
NumberObjectType,
ErrorInstanceType,
- GlobalThisType,
+ ProxyType,
WithScopeType,
NameScopeObjectType,
diff --git a/Source/JavaScriptCore/runtime/JSValue.cpp b/Source/JavaScriptCore/runtime/JSValue.cpp
index ac00fad3d..651e50cec 100644
--- a/Source/JavaScriptCore/runtime/JSValue.cpp
+++ b/Source/JavaScriptCore/runtime/JSValue.cpp
@@ -195,7 +195,7 @@ void JSValue::putToPrimitiveByIndex(ExecState* exec, unsigned propertyName, JSVa
char* JSValue::description() const
{
- static const size_t size = 128;
+ static const size_t size = 256;
static char description[size];
if (!*this)
@@ -213,9 +213,12 @@ char* JSValue::description() const
u.asDouble = asDouble();
snprintf(description, size, "Double: %08x:%08x, %lf", u.asTwoInt32s[1], u.asTwoInt32s[0], asDouble());
#endif
- } else if (isCell())
- snprintf(description, size, "Cell: %p", asCell());
- else if (isTrue())
+ } else if (isCell()) {
+ snprintf(
+ description, size, "Cell: %p (%p: %s, %s)",
+ asCell(), asCell()->structure(), asCell()->structure()->classInfo()->className,
+ indexingTypeToString(asCell()->structure()->indexingTypeIncludingHistory()));
+ } else if (isTrue())
snprintf(description, size, "True");
else if (isFalse())
snprintf(description, size, "False");
diff --git a/Source/JavaScriptCore/runtime/JSVariableObject.h b/Source/JavaScriptCore/runtime/JSVariableObject.h
index 55952820e..25961dc09 100644
--- a/Source/JavaScriptCore/runtime/JSVariableObject.h
+++ b/Source/JavaScriptCore/runtime/JSVariableObject.h
@@ -68,7 +68,7 @@ namespace JSC {
{
}
- WriteBarrierBase<Unknown>* m_registers; // "r" in the register file.
+ WriteBarrierBase<Unknown>* m_registers; // "r" in the stack.
};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSWithScope.cpp b/Source/JavaScriptCore/runtime/JSWithScope.cpp
index 0c4b6e2cc..7d74e63c3 100644
--- a/Source/JavaScriptCore/runtime/JSWithScope.cpp
+++ b/Source/JavaScriptCore/runtime/JSWithScope.cpp
@@ -28,8 +28,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(JSWithScope);
-
const ClassInfo JSWithScope::s_info = { "WithScope", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSWithScope) };
void JSWithScope::visitChildren(JSCell* cell, SlotVisitor& visitor)
diff --git a/Source/JavaScriptCore/runtime/JSWrapperObject.cpp b/Source/JavaScriptCore/runtime/JSWrapperObject.cpp
index 4a46c2c69..ff80c1e20 100644
--- a/Source/JavaScriptCore/runtime/JSWrapperObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSWrapperObject.cpp
@@ -24,7 +24,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(JSWrapperObject);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSWrapperObject);
void JSWrapperObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
diff --git a/Source/JavaScriptCore/runtime/JSWrapperObject.h b/Source/JavaScriptCore/runtime/JSWrapperObject.h
index 65b4bdb7f..72bc1874c 100644
--- a/Source/JavaScriptCore/runtime/JSWrapperObject.h
+++ b/Source/JavaScriptCore/runtime/JSWrapperObject.h
@@ -22,15 +22,15 @@
#ifndef JSWrapperObject_h
#define JSWrapperObject_h
-#include "JSObject.h"
+#include "JSDestructibleObject.h"
namespace JSC {
// This class is used as a base for classes such as String,
// Number, Boolean and Date which are wrappers for primitive types.
- class JSWrapperObject : public JSNonFinalObject {
+ class JSWrapperObject : public JSDestructibleObject {
public:
- typedef JSNonFinalObject Base;
+ typedef JSDestructibleObject Base;
JSValue internalValue() const;
void setInternalValue(JSGlobalData&, JSValue);
@@ -42,7 +42,7 @@ namespace JSC {
protected:
explicit JSWrapperObject(JSGlobalData&, Structure*);
- static const unsigned StructureFlags = OverridesVisitChildren | JSNonFinalObject::StructureFlags;
+ static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags;
static void visitChildren(JSCell*, SlotVisitor&);
@@ -51,7 +51,7 @@ namespace JSC {
};
inline JSWrapperObject::JSWrapperObject(JSGlobalData& globalData, Structure* structure)
- : JSNonFinalObject(globalData, structure)
+ : JSDestructibleObject(globalData, structure)
{
}
diff --git a/Source/JavaScriptCore/runtime/MathObject.cpp b/Source/JavaScriptCore/runtime/MathObject.cpp
index 2a550a38b..2f4df375a 100644
--- a/Source/JavaScriptCore/runtime/MathObject.cpp
+++ b/Source/JavaScriptCore/runtime/MathObject.cpp
@@ -32,7 +32,7 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(MathObject);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(MathObject);
static EncodedJSValue JSC_HOST_CALL mathProtoFuncAbs(ExecState*);
static EncodedJSValue JSC_HOST_CALL mathProtoFuncACos(ExecState*);
@@ -59,9 +59,7 @@ static EncodedJSValue JSC_HOST_CALL mathProtoFuncTan(ExecState*);
namespace JSC {
-ASSERT_HAS_TRIVIAL_DESTRUCTOR(MathObject);
-
-const ClassInfo MathObject::s_info = { "Math", &JSNonFinalObject::s_info, 0, ExecState::mathTable, CREATE_METHOD_TABLE(MathObject) };
+const ClassInfo MathObject::s_info = { "Math", &Base::s_info, 0, ExecState::mathTable, CREATE_METHOD_TABLE(MathObject) };
/* Source for MathObject.lut.h
@begin mathTable
diff --git a/Source/JavaScriptCore/runtime/MemoryStatistics.cpp b/Source/JavaScriptCore/runtime/MemoryStatistics.cpp
index b35e9fbda..0f8efc604 100644
--- a/Source/JavaScriptCore/runtime/MemoryStatistics.cpp
+++ b/Source/JavaScriptCore/runtime/MemoryStatistics.cpp
@@ -28,7 +28,7 @@
#include "ExecutableAllocator.h"
#include "JSGlobalData.h"
-#include "RegisterFile.h"
+#include "JSStack.h"
namespace JSC {
@@ -36,7 +36,7 @@ GlobalMemoryStatistics globalMemoryStatistics()
{
GlobalMemoryStatistics stats;
- stats.stackBytes = RegisterFile::committedByteCount();
+ stats.stackBytes = JSStack::committedByteCount();
#if ENABLE(EXECUTABLE_ALLOCATOR_FIXED) || ((PLATFORM(BLACKBERRY) || PLATFORM(EFL)) && ENABLE(JIT))
stats.JITBytes = ExecutableAllocator::committedByteCount();
#else
diff --git a/Source/JavaScriptCore/runtime/NameConstructor.cpp b/Source/JavaScriptCore/runtime/NameConstructor.cpp
index 63f1f647a..b5facc7cf 100644
--- a/Source/JavaScriptCore/runtime/NameConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/NameConstructor.cpp
@@ -31,7 +31,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(NameConstructor);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(NameConstructor);
const ClassInfo NameConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(NameConstructor) };
diff --git a/Source/JavaScriptCore/runtime/NameInstance.h b/Source/JavaScriptCore/runtime/NameInstance.h
index c5931e8ef..129e7c407 100644
--- a/Source/JavaScriptCore/runtime/NameInstance.h
+++ b/Source/JavaScriptCore/runtime/NameInstance.h
@@ -26,14 +26,14 @@
#ifndef NameInstance_h
#define NameInstance_h
-#include "JSObject.h"
+#include "JSDestructibleObject.h"
#include "PrivateName.h"
namespace JSC {
-class NameInstance : public JSNonFinalObject {
+class NameInstance : public JSDestructibleObject {
public:
- typedef JSNonFinalObject Base;
+ typedef JSDestructibleObject Base;
static const ClassInfo s_info;
diff --git a/Source/JavaScriptCore/runtime/NamePrototype.cpp b/Source/JavaScriptCore/runtime/NamePrototype.cpp
index 3e52856b6..f14e58522 100644
--- a/Source/JavaScriptCore/runtime/NamePrototype.cpp
+++ b/Source/JavaScriptCore/runtime/NamePrototype.cpp
@@ -30,8 +30,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(NamePrototype);
-
static EncodedJSValue JSC_HOST_CALL privateNameProtoFuncToString(ExecState*);
}
@@ -48,8 +46,6 @@ const ClassInfo NamePrototype::s_info = { "Name", &Base::s_info, 0, ExecState::p
@end
*/
-ASSERT_CLASS_FITS_IN_CELL(NamePrototype);
-
NamePrototype::NamePrototype(ExecState* exec, Structure* structure)
: Base(exec->globalData(), structure, jsEmptyString(exec))
{
diff --git a/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp b/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp
index a4ba240fd..1f1730805 100644
--- a/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp
@@ -28,7 +28,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(NativeErrorConstructor);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(NativeErrorConstructor);
const ClassInfo NativeErrorConstructor::s_info = { "Function", &InternalFunction::s_info, 0, 0, CREATE_METHOD_TABLE(NativeErrorConstructor) };
diff --git a/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp b/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp
index 7fee213fa..296a86a22 100644
--- a/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp
@@ -27,8 +27,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(NativeErrorPrototype);
-
NativeErrorPrototype::NativeErrorPrototype(ExecState* exec, Structure* structure)
: ErrorPrototype(exec, structure)
{
diff --git a/Source/JavaScriptCore/runtime/NumberConstructor.cpp b/Source/JavaScriptCore/runtime/NumberConstructor.cpp
index 03d616073..daa643da7 100644
--- a/Source/JavaScriptCore/runtime/NumberConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/NumberConstructor.cpp
@@ -28,8 +28,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(NumberConstructor);
-
static JSValue numberConstructorNaNValue(ExecState*, JSValue, PropertyName);
static JSValue numberConstructorNegInfinity(ExecState*, JSValue, PropertyName);
static JSValue numberConstructorPosInfinity(ExecState*, JSValue, PropertyName);
diff --git a/Source/JavaScriptCore/runtime/NumberObject.cpp b/Source/JavaScriptCore/runtime/NumberObject.cpp
index 1fea25464..b87753d4d 100644
--- a/Source/JavaScriptCore/runtime/NumberObject.cpp
+++ b/Source/JavaScriptCore/runtime/NumberObject.cpp
@@ -27,7 +27,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(NumberObject);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(NumberObject);
const ClassInfo NumberObject::s_info = { "Number", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(NumberObject) };
diff --git a/Source/JavaScriptCore/runtime/NumberPrototype.cpp b/Source/JavaScriptCore/runtime/NumberPrototype.cpp
index 4a10efd6d..23c9dbfdd 100644
--- a/Source/JavaScriptCore/runtime/NumberPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/NumberPrototype.cpp
@@ -68,7 +68,6 @@ const ClassInfo NumberPrototype::s_info = { "Number", &NumberObject::s_info, 0,
@end
*/
-ASSERT_CLASS_FITS_IN_CELL(NumberPrototype);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(NumberPrototype);
NumberPrototype::NumberPrototype(ExecState* exec, Structure* structure)
diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
index 8614b9c45..7df047d28 100644
--- a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
@@ -35,8 +35,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(ObjectConstructor);
-
static EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState*);
static EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState*);
static EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState*);
diff --git a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp
index b1a5b9fb3..e94edfadf 100644
--- a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp
@@ -63,8 +63,6 @@ const ClassInfo ObjectPrototype::s_info = { "Object", &JSNonFinalObject::s_info,
@end
*/
-ASSERT_CLASS_FITS_IN_CELL(ObjectPrototype);
-
ObjectPrototype::ObjectPrototype(ExecState* exec, Structure* stucture)
: JSNonFinalObject(exec->globalData(), stucture)
{
diff --git a/Source/JavaScriptCore/runtime/Options.cpp b/Source/JavaScriptCore/runtime/Options.cpp
index ed0720b54..386eb4fcf 100644
--- a/Source/JavaScriptCore/runtime/Options.cpp
+++ b/Source/JavaScriptCore/runtime/Options.cpp
@@ -26,6 +26,7 @@
#include "config.h"
#include "Options.h"
+#include "HeapStatistics.h"
#include <algorithm>
#include <limits>
#include <stdio.h>
@@ -41,10 +42,6 @@
#include <sys/sysctl.h>
#endif
-// Set to 1 to control the heuristics using environment variables.
-#define ENABLE_RUN_TIME_HEURISTICS 0
-
-
namespace JSC {
static bool parse(const char* string, bool& value)
@@ -75,10 +72,10 @@ static bool parse(const char* string, double& value)
return sscanf(string, "%lf", &value) == 1;
}
-#if ENABLE(RUN_TIME_HEURISTICS)
template<typename T>
void overrideOptionWithHeuristic(T& variable, const char* name)
{
+#if !OS(WINCE)
const char* stringValue = getenv(name);
if (!stringValue)
return;
@@ -87,9 +84,8 @@ void overrideOptionWithHeuristic(T& variable, const char* name)
return;
fprintf(stderr, "WARNING: failed to parse %s=%s\n", name, stringValue);
-}
#endif
-
+}
static unsigned computeNumberOfGCMarkers(int maxNumberOfGCMarkers)
{
@@ -130,17 +126,19 @@ void Options::initialize()
#if USE(CF) || OS(UNIX)
objectsAreImmortal() = !!getenv("JSImmortalZombieEnabled");
useZombieMode() = !!getenv("JSImmortalZombieEnabled") || !!getenv("JSZombieEnabled");
+
+ gcMaxHeapSize() = getenv("GCMaxHeapSize") ? HeapStatistics::parseMemoryAmount(getenv("GCMaxHeapSize")) : 0;
+ recordGCPauseTimes() = !!getenv("JSRecordGCPauseTimes");
+ logHeapStatisticsAtExit() = gcMaxHeapSize() || recordGCPauseTimes();
#endif
// Allow environment vars to override options if applicable.
// The evn var should be the name of the option prefixed with
// "JSC_".
-#if ENABLE(RUN_TIME_HEURISTICS)
#define FOR_EACH_OPTION(type_, name_, defaultValue_) \
overrideOptionWithHeuristic(name_(), "JSC_" #name_);
JSC_OPTIONS(FOR_EACH_OPTION)
#undef FOR_EACH_OPTION
-#endif // RUN_TIME_HEURISTICS
#if 0
; // Deconfuse editors that do auto indentation
@@ -153,7 +151,7 @@ void Options::initialize()
#if !ENABLE(YARR_JIT)
useRegExpJIT() = false;
#endif
-
+
// Do range checks where needed and make corrections to the options:
ASSERT(thresholdForOptimizeAfterLongWarmUp() >= thresholdForOptimizeAfterWarmUp());
ASSERT(thresholdForOptimizeAfterWarmUp() >= thresholdForOptimizeSoon());
diff --git a/Source/JavaScriptCore/runtime/Options.h b/Source/JavaScriptCore/runtime/Options.h
index 7571f9138..d6d8c66c8 100644
--- a/Source/JavaScriptCore/runtime/Options.h
+++ b/Source/JavaScriptCore/runtime/Options.h
@@ -51,9 +51,8 @@ namespace JSC {
// purposes, you can do so in Options::initialize() after the default values
// are set.
//
-// Alternatively, you can enable RUN_TIME_HEURISTICS which will allow you
-// to override the default values by specifying environment variables of the
-// form: JSC_<name of JSC option>.
+// Alternatively, you can override the default values by specifying
+// environment variables of the form: JSC_<name of JSC option>.
//
// Note: Options::initialize() tries to ensure some sanity on the option values
// which are set by doing some range checks, and value corrections. These
@@ -116,14 +115,19 @@ namespace JSC {
v(unsigned, gcMarkStackSegmentSize, pageSize()) \
v(unsigned, numberOfGCMarkers, computeNumberOfGCMarkers(7)) \
v(unsigned, opaqueRootMergeThreshold, 1000) \
+ v(double, minHeapUtilization, 0.8) \
+ v(double, minCopiedBlockUtilization, 0.9) \
\
v(bool, forceWeakRandomSeed, false) \
v(unsigned, forcedWeakRandomSeed, 0) \
\
v(bool, useZombieMode, false) \
v(bool, objectsAreImmortal, false) \
- v(bool, showHeapStatistics, false)
-
+ v(bool, showObjectStatistics, false) \
+ \
+ v(unsigned, gcMaxHeapSize, 0) \
+ v(bool, recordGCPauseTimes, false) \
+ v(bool, logHeapStatisticsAtExit, false)
class Options {
public:
@@ -161,7 +165,7 @@ private:
boolType,
unsignedType,
doubleType,
- int32Type
+ int32Type,
};
// For storing for an option value:
diff --git a/Source/JavaScriptCore/runtime/PropertyMapHashTable.h b/Source/JavaScriptCore/runtime/PropertyMapHashTable.h
index 2d0f27a3e..9c6ddb20f 100644
--- a/Source/JavaScriptCore/runtime/PropertyMapHashTable.h
+++ b/Source/JavaScriptCore/runtime/PropertyMapHashTable.h
@@ -178,7 +178,7 @@ public:
PropertyOffset getDeletedOffset();
void addDeletedOffset(PropertyOffset);
- PropertyOffset nextOffset(JSType);
+ PropertyOffset nextOffset(PropertyOffset inlineCapacity);
// Copy this PropertyTable, ensuring the copy has at least the capacity provided.
PassOwnPtr<PropertyTable> copy(JSGlobalData&, JSCell* owner, unsigned newCapacity);
@@ -486,15 +486,12 @@ inline void PropertyTable::addDeletedOffset(PropertyOffset offset)
m_deletedOffsets->append(offset);
}
-inline PropertyOffset PropertyTable::nextOffset(JSType type)
+inline PropertyOffset PropertyTable::nextOffset(PropertyOffset inlineCapacity)
{
if (hasDeletedOffset())
return getDeletedOffset();
-
- if (type == FinalObjectType)
- return size();
-
- return size() + firstOutOfLineOffset;
+
+ return propertyOffsetFor(size(), inlineCapacity);
}
inline PassOwnPtr<PropertyTable> PropertyTable::copy(JSGlobalData& globalData, JSCell* owner, unsigned newCapacity)
diff --git a/Source/JavaScriptCore/runtime/PropertyOffset.h b/Source/JavaScriptCore/runtime/PropertyOffset.h
index 2aea2981e..1a2bba446 100644
--- a/Source/JavaScriptCore/runtime/PropertyOffset.h
+++ b/Source/JavaScriptCore/runtime/PropertyOffset.h
@@ -26,7 +26,6 @@
#ifndef PropertyOffset_h
#define PropertyOffset_h
-#include "JSType.h"
#include <wtf/Platform.h>
#include <wtf/StdLibExtras.h>
#include <wtf/UnusedParam.h>
@@ -42,14 +41,13 @@ namespace JSC {
typedef int PropertyOffset;
static const PropertyOffset invalidOffset = -1;
-static const PropertyOffset inlineStorageCapacity = INLINE_STORAGE_CAPACITY;
-static const PropertyOffset firstOutOfLineOffset = inlineStorageCapacity;
+static const PropertyOffset firstOutOfLineOffset = 100;
// Declare all of the functions because they tend to do forward calls.
inline void checkOffset(PropertyOffset);
-inline void checkOffset(PropertyOffset, JSType);
+inline void checkOffset(PropertyOffset, PropertyOffset inlineCapacity);
inline void validateOffset(PropertyOffset);
-inline void validateOffset(PropertyOffset, JSType);
+inline void validateOffset(PropertyOffset, PropertyOffset inlineCapacity);
inline bool isValidOffset(PropertyOffset);
inline bool isInlineOffset(PropertyOffset);
inline bool isOutOfLineOffset(PropertyOffset);
@@ -57,9 +55,7 @@ inline size_t offsetInInlineStorage(PropertyOffset);
inline size_t offsetInOutOfLineStorage(PropertyOffset);
inline size_t offsetInRespectiveStorage(PropertyOffset);
inline size_t numberOfOutOfLineSlotsForLastOffset(PropertyOffset);
-inline size_t numberOfSlotsForLastOffset(PropertyOffset, JSType);
-inline PropertyOffset nextPropertyOffsetFor(PropertyOffset, JSType);
-inline PropertyOffset firstPropertyOffsetFor(JSType);
+inline size_t numberOfSlotsForLastOffset(PropertyOffset, PropertyOffset inlineCapacity);
inline void checkOffset(PropertyOffset offset)
{
@@ -67,14 +63,14 @@ inline void checkOffset(PropertyOffset offset)
ASSERT(offset >= invalidOffset);
}
-inline void checkOffset(PropertyOffset offset, JSType type)
+inline void checkOffset(PropertyOffset offset, PropertyOffset inlineCapacity)
{
UNUSED_PARAM(offset);
- UNUSED_PARAM(type);
+ UNUSED_PARAM(inlineCapacity);
ASSERT(offset >= invalidOffset);
ASSERT(offset == invalidOffset
- || type == FinalObjectType
- || isOutOfLineOffset(offset));
+ || offset < inlineCapacity
+ || isOutOfLineOffset(offset));
}
inline void validateOffset(PropertyOffset offset)
@@ -83,9 +79,9 @@ inline void validateOffset(PropertyOffset offset)
ASSERT(isValidOffset(offset));
}
-inline void validateOffset(PropertyOffset offset, JSType type)
+inline void validateOffset(PropertyOffset offset, PropertyOffset inlineCapacity)
{
- checkOffset(offset, type);
+ checkOffset(offset, inlineCapacity);
ASSERT(isValidOffset(offset));
}
@@ -98,7 +94,7 @@ inline bool isValidOffset(PropertyOffset offset)
inline bool isInlineOffset(PropertyOffset offset)
{
checkOffset(offset);
- return offset < inlineStorageCapacity;
+ return offset < firstOutOfLineOffset;
}
inline bool isOutOfLineOffset(PropertyOffset offset)
@@ -136,28 +132,24 @@ inline size_t numberOfOutOfLineSlotsForLastOffset(PropertyOffset offset)
return offset - firstOutOfLineOffset + 1;
}
-inline size_t numberOfSlotsForLastOffset(PropertyOffset offset, JSType type)
+inline size_t numberOfSlotsForLastOffset(PropertyOffset offset, PropertyOffset inlineCapacity)
{
- checkOffset(offset, type);
- if (type == FinalObjectType)
+ checkOffset(offset, inlineCapacity);
+ if (offset < inlineCapacity)
return offset + 1;
- return numberOfOutOfLineSlotsForLastOffset(offset);
+ return inlineCapacity + numberOfOutOfLineSlotsForLastOffset(offset);
}
-inline PropertyOffset nextPropertyOffsetFor(PropertyOffset offset, JSType type)
+inline PropertyOffset propertyOffsetFor(PropertyOffset propertyNumber, PropertyOffset inlineCapacity)
{
- checkOffset(offset, type);
- if (type != FinalObjectType && offset == invalidOffset)
- return firstOutOfLineOffset;
- return offset + 1;
-}
-
-inline PropertyOffset firstPropertyOffsetFor(JSType type)
-{
- return nextPropertyOffsetFor(invalidOffset, type);
+ PropertyOffset offset = propertyNumber;
+ if (offset >= inlineCapacity) {
+ offset += firstOutOfLineOffset;
+ offset -= inlineCapacity;
+ }
+ return offset;
}
} // namespace JSC
#endif // PropertyOffset_h
-
diff --git a/Source/JavaScriptCore/runtime/RegExp.h b/Source/JavaScriptCore/runtime/RegExp.h
index 287444b95..b2b65d90c 100644
--- a/Source/JavaScriptCore/runtime/RegExp.h
+++ b/Source/JavaScriptCore/runtime/RegExp.h
@@ -47,6 +47,8 @@ namespace JSC {
typedef JSCell Base;
JS_EXPORT_PRIVATE static RegExp* create(JSGlobalData&, const String& pattern, RegExpFlags);
+ static const bool needsDestruction = true;
+ static const bool hasImmortalStructure = true;
static void destroy(JSCell*);
bool global() const { return m_flags & FlagGlobal; }
diff --git a/Source/JavaScriptCore/runtime/RegExpCache.cpp b/Source/JavaScriptCore/runtime/RegExpCache.cpp
index c67dab8e6..8acafba23 100644
--- a/Source/JavaScriptCore/runtime/RegExpCache.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpCache.cpp
@@ -80,7 +80,7 @@ void RegExpCache::invalidateCode()
RegExpCacheMap::iterator end = m_weakCache.end();
for (RegExpCacheMap::iterator it = m_weakCache.begin(); it != end; ++it) {
- RegExp* regExp = it->second.get();
+ RegExp* regExp = it->value.get();
if (!regExp) // Skip zombies.
continue;
regExp->invalidateCode();
diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
index b8c4cd0b3..cc6ceb1d1 100644
--- a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
@@ -53,8 +53,6 @@ static void setRegExpConstructorMultiline(ExecState*, JSObject*, JSValue);
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(RegExpConstructor);
-
const ClassInfo RegExpConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::regExpConstructorTable, CREATE_METHOD_TABLE(RegExpConstructor) };
/* Source for RegExpConstructor.lut.h
diff --git a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp
index 04fea60e8..ce9c2d2db 100644
--- a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp
@@ -30,8 +30,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(RegExpMatchesArray);
-
const ClassInfo RegExpMatchesArray::s_info = {"Array", &JSArray::s_info, 0, 0, CREATE_METHOD_TABLE(RegExpMatchesArray)};
RegExpMatchesArray::RegExpMatchesArray(JSGlobalData& globalData, Butterfly* butterfly, JSGlobalObject* globalObject, JSString* input, RegExp* regExp, MatchResult result)
diff --git a/Source/JavaScriptCore/runtime/RegExpObject.cpp b/Source/JavaScriptCore/runtime/RegExpObject.cpp
index bed44f22c..dfbf533f7 100644
--- a/Source/JavaScriptCore/runtime/RegExpObject.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpObject.cpp
@@ -49,9 +49,9 @@ static JSValue regExpObjectSource(ExecState*, JSValue, PropertyName);
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(RegExpObject);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(RegExpObject);
-const ClassInfo RegExpObject::s_info = { "RegExp", &JSNonFinalObject::s_info, 0, ExecState::regExpTable, CREATE_METHOD_TABLE(RegExpObject) };
+const ClassInfo RegExpObject::s_info = { "RegExp", &Base::s_info, 0, ExecState::regExpTable, CREATE_METHOD_TABLE(RegExpObject) };
/* Source for RegExpObject.lut.h
@begin regExpTable
diff --git a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp
index 3c742a0d3..e4bf2cf9a 100644
--- a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp
@@ -59,8 +59,6 @@ const ClassInfo RegExpPrototype::s_info = { "RegExp", &RegExpObject::s_info, 0,
@end
*/
-ASSERT_CLASS_FITS_IN_CELL(RegExpPrototype);
-
RegExpPrototype::RegExpPrototype(JSGlobalObject* globalObject, Structure* structure, RegExp* regExp)
: RegExpObject(globalObject, structure, regExp)
{
diff --git a/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp b/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp
index b9ba25735..7f21e2c9f 100644
--- a/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp
+++ b/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp
@@ -88,7 +88,7 @@ SparseArrayValueMap::AddResult SparseArrayValueMap::add(JSObject* array, unsigne
void SparseArrayValueMap::putEntry(ExecState* exec, JSObject* array, unsigned i, JSValue value, bool shouldThrow)
{
AddResult result = add(array, i);
- SparseArrayEntry& entry = result.iterator->second;
+ SparseArrayEntry& entry = result.iterator->value;
// 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
@@ -106,7 +106,7 @@ void SparseArrayValueMap::putEntry(ExecState* exec, JSObject* array, unsigned i,
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;
+ SparseArrayEntry& entry = result.iterator->value;
// 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
@@ -207,7 +207,7 @@ void SparseArrayValueMap::visitChildren(JSCell* thisObject, SlotVisitor& 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);
+ visitor.append(&it->value);
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/SparseArrayValueMap.h b/Source/JavaScriptCore/runtime/SparseArrayValueMap.h
index 5d8d0577a..366a7b8ba 100644
--- a/Source/JavaScriptCore/runtime/SparseArrayValueMap.h
+++ b/Source/JavaScriptCore/runtime/SparseArrayValueMap.h
@@ -81,6 +81,8 @@ public:
static SparseArrayValueMap* create(JSGlobalData&);
+ static const bool needsDestruction = true;
+ static const bool hasImmortalStructure = true;
static void destroy(JSCell*);
static Structure* createStructure(JSGlobalData&, JSGlobalObject*, JSValue prototype);
diff --git a/Source/JavaScriptCore/runtime/StringConstructor.cpp b/Source/JavaScriptCore/runtime/StringConstructor.cpp
index 460343761..7f36a84be 100644
--- a/Source/JavaScriptCore/runtime/StringConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/StringConstructor.cpp
@@ -45,7 +45,6 @@ const ClassInfo StringConstructor::s_info = { "Function", &InternalFunction::s_i
@end
*/
-ASSERT_CLASS_FITS_IN_CELL(StringConstructor);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(StringConstructor);
StringConstructor::StringConstructor(JSGlobalObject* globalObject, Structure* structure)
diff --git a/Source/JavaScriptCore/runtime/StringObject.cpp b/Source/JavaScriptCore/runtime/StringObject.cpp
index 15900913d..ab7d6cb23 100644
--- a/Source/JavaScriptCore/runtime/StringObject.cpp
+++ b/Source/JavaScriptCore/runtime/StringObject.cpp
@@ -27,7 +27,6 @@
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(StringObject);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(StringObject);
const ClassInfo StringObject::s_info = { "String", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(StringObject) };
diff --git a/Source/JavaScriptCore/runtime/StringPrototype.cpp b/Source/JavaScriptCore/runtime/StringPrototype.cpp
index 8daa0f335..1540177be 100644
--- a/Source/JavaScriptCore/runtime/StringPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp
@@ -47,7 +47,6 @@ using namespace WTF;
namespace JSC {
-ASSERT_CLASS_FITS_IN_CELL(StringPrototype);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(StringPrototype);
static EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState*);
diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp
index a59a0860d..a931def27 100644
--- a/Source/JavaScriptCore/runtime/Structure.cpp
+++ b/Source/JavaScriptCore/runtime/Structure.cpp
@@ -149,7 +149,7 @@ void Structure::dumpStatistics()
#endif
}
-Structure::Structure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType)
+Structure::Structure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, PropertyOffset inlineCapacity)
: JSCell(globalData, globalData.structureStructure.get())
, m_typeInfo(typeInfo)
, m_indexingType(indexingType)
@@ -158,6 +158,7 @@ Structure::Structure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSV
, m_classInfo(classInfo)
, m_transitionWatchpointSet(InitializedWatching)
, m_outOfLineCapacity(0)
+ , m_inlineCapacity(inlineCapacity)
, m_offset(invalidOffset)
, m_dictionaryKind(NoneDictionaryKind)
, m_isPinnedPropertyTable(false)
@@ -182,6 +183,7 @@ Structure::Structure(JSGlobalData& globalData)
, m_classInfo(&s_info)
, m_transitionWatchpointSet(InitializedWatching)
, m_outOfLineCapacity(0)
+ , m_inlineCapacity(0)
, m_offset(invalidOffset)
, m_dictionaryKind(NoneDictionaryKind)
, m_isPinnedPropertyTable(false)
@@ -204,6 +206,7 @@ Structure::Structure(JSGlobalData& globalData, const Structure* previous)
, m_classInfo(previous->m_classInfo)
, m_transitionWatchpointSet(InitializedWatching)
, m_outOfLineCapacity(previous->m_outOfLineCapacity)
+ , m_inlineCapacity(previous->m_inlineCapacity)
, m_offset(invalidOffset)
, m_dictionaryKind(previous->m_dictionaryKind)
, m_isPinnedPropertyTable(false)
@@ -323,11 +326,15 @@ bool Structure::anyObjectInChainMayInterceptIndexedAccesses() const
}
}
-NonPropertyTransition Structure::suggestedIndexingTransition() const
+bool Structure::needsSlowPutIndexing() const
{
- ASSERT(!hasIndexedProperties(indexingType()));
-
- if (anyObjectInChainMayInterceptIndexedAccesses() || globalObject()->isHavingABadTime())
+ return anyObjectInChainMayInterceptIndexedAccesses()
+ || globalObject()->isHavingABadTime();
+}
+
+NonPropertyTransition Structure::suggestedArrayStorageTransition() const
+{
+ if (needsSlowPutIndexing())
return AllocateSlowPutArrayStorage;
return AllocateArrayStorage;
@@ -546,6 +553,7 @@ Structure* Structure::nonPropertyTransition(JSGlobalData& globalData, Structure*
transition->m_previous.set(globalData, transition, structure);
transition->m_attributesInPrevious = attributes;
transition->m_indexingType = indexingType;
+ transition->m_offset = structure->m_offset;
if (structure->m_propertyTable) {
if (structure->m_isPinnedPropertyTable)
@@ -608,20 +616,21 @@ Structure* Structure::flattenDictionaryStructure(JSGlobalData& globalData, JSObj
ASSERT(m_propertyTable);
size_t propertyCount = m_propertyTable->size();
+
+ // Holds our values compacted by insertion order.
Vector<JSValue> values(propertyCount);
-
+
+ // Copies out our values from their hashed locations, compacting property table offsets as we go.
unsigned i = 0;
- PropertyOffset firstOffset = firstPropertyOffsetFor(m_typeInfo.type());
PropertyTable::iterator end = m_propertyTable->end();
for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter, ++i) {
values[i] = object->getDirectOffset(iter->offset);
- // Update property table to have the new property offsets
- iter->offset = i + firstOffset;
+ iter->offset = propertyOffsetFor(i, m_inlineCapacity);
}
- // Copy the original property values into their final locations
+ // Copies in our values to their compacted locations.
for (unsigned i = 0; i < propertyCount; i++)
- object->putDirectOffset(globalData, firstOffset + i, values[i]);
+ object->putDirectOffset(globalData, propertyOffsetFor(i, m_inlineCapacity), values[i]);
m_propertyTable->clearDeletedOffsets();
}
@@ -759,7 +768,7 @@ PropertyOffset Structure::putSpecificValue(JSGlobalData& globalData, PropertyNam
if (!m_propertyTable)
createPropertyMap();
- PropertyOffset newOffset = m_propertyTable->nextOffset(m_typeInfo.type());
+ PropertyOffset newOffset = m_propertyTable->nextOffset(m_inlineCapacity);
m_propertyTable->add(PropertyMapEntry(globalData, this, rep, newOffset, attributes, specificValue));
diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h
index e77287b20..f45e9f1d9 100644
--- a/Source/JavaScriptCore/runtime/Structure.h
+++ b/Source/JavaScriptCore/runtime/Structure.h
@@ -69,7 +69,7 @@ namespace JSC {
typedef JSCell Base;
- static Structure* create(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = 0);
+ static Structure* create(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, PropertyOffset inlineCapacity = 0);
protected:
void finishCreation(JSGlobalData& globalData)
@@ -128,6 +128,8 @@ namespace JSC {
Structure* flattenDictionaryStructure(JSGlobalData&, JSObject*);
+ static const bool needsDestruction = true;
+ static const bool hasImmortalStructure = true;
static void destroy(JSCell*);
// These should be used with caution.
@@ -152,7 +154,8 @@ namespace JSC {
bool anyObjectInChainMayInterceptIndexedAccesses() const;
- NonPropertyTransition suggestedIndexingTransition() const;
+ bool needsSlowPutIndexing() const;
+ NonPropertyTransition suggestedArrayStorageTransition() const;
JSGlobalObject* globalObject() const { return m_globalObject.get(); }
void setGlobalObject(JSGlobalData& globalData, JSGlobalObject* globalObject) { m_globalObject.set(globalData, this, globalObject); }
@@ -177,24 +180,6 @@ namespace JSC {
ASSERT(structure()->classInfo() == &s_info);
return m_outOfLineCapacity;
}
- unsigned outOfLineSizeForKnownFinalObject() const
- {
- ASSERT(m_typeInfo.type() == FinalObjectType);
- if (m_propertyTable) {
- unsigned totalSize = m_propertyTable->propertyStorageSize();
- if (totalSize < static_cast<unsigned>(inlineStorageCapacity))
- return 0;
- return totalSize - inlineStorageCapacity;
- }
- return numberOfOutOfLineSlotsForLastOffset(m_offset);
- }
- unsigned outOfLineSizeForKnownNonFinalObject() const
- {
- ASSERT(m_typeInfo.type() != FinalObjectType);
- if (m_propertyTable)
- return m_propertyTable->propertyStorageSize();
- return numberOfOutOfLineSlotsForLastOffset(m_offset);
- }
unsigned outOfLineSize() const
{
ASSERT(structure()->classInfo() == &s_info);
@@ -209,31 +194,20 @@ namespace JSC {
}
bool hasInlineStorage() const
{
- return m_typeInfo.type() == FinalObjectType;
+ return !!m_inlineCapacity;
}
unsigned inlineCapacity() const
{
- if (hasInlineStorage())
- return inlineStorageCapacity;
- return 0;
+ return m_inlineCapacity;
}
- unsigned inlineSizeForKnownFinalObject() const
+ unsigned inlineSize() const
{
- ASSERT(m_typeInfo.type() == FinalObjectType);
unsigned result;
if (m_propertyTable)
result = m_propertyTable->propertyStorageSize();
else
result = m_offset + 1;
- if (result > static_cast<unsigned>(inlineStorageCapacity))
- return inlineStorageCapacity;
- return result;
- }
- unsigned inlineSize() const
- {
- if (!hasInlineStorage())
- return 0;
- return inlineSizeForKnownFinalObject();
+ return std::min<unsigned>(result, m_inlineCapacity);
}
unsigned totalStorageSize() const
{
@@ -251,16 +225,12 @@ namespace JSC {
{
if (hasInlineStorage())
return 0;
- return inlineStorageCapacity;
+ return firstOutOfLineOffset;
}
PropertyOffset lastValidOffset() const
{
- if (m_propertyTable) {
- PropertyOffset size = m_propertyTable->propertyStorageSize();
- if (!hasInlineStorage())
- size += inlineStorageCapacity;
- return size - 1;
- }
+ if (m_propertyTable)
+ return propertyOffsetFor(m_propertyTable->propertyStorageSize() - 1, m_inlineCapacity);
return m_offset;
}
bool isValidOffset(PropertyOffset offset) const
@@ -381,7 +351,7 @@ namespace JSC {
private:
friend class LLIntOffsetsExtractor;
- JS_EXPORT_PRIVATE Structure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = 0);
+ JS_EXPORT_PRIVATE Structure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType, PropertyOffset inlineCapacity);
Structure(JSGlobalData&);
Structure(JSGlobalData&, const Structure*);
@@ -457,6 +427,8 @@ namespace JSC {
mutable InlineWatchpointSet m_transitionWatchpointSet;
uint32_t m_outOfLineCapacity;
+ uint8_t m_inlineCapacity;
+ COMPILE_ASSERT(firstOutOfLineOffset < 256, firstOutOfLineOffset_fits);
// m_offset does not account for anonymous slots
PropertyOffset m_offset;
@@ -473,22 +445,11 @@ namespace JSC {
unsigned m_staticFunctionReified;
};
- template <> inline void* allocateCell<Structure>(Heap& heap)
- {
-#if ENABLE(GC_VALIDATION)
- ASSERT(!heap.globalData()->isInitializingObject());
- heap.globalData()->setInitializingObjectClass(&Structure::s_info);
-#endif
- JSCell* result = static_cast<JSCell*>(heap.allocateStructure(sizeof(Structure)));
- result->clearStructure();
- return result;
- }
-
- inline Structure* Structure::create(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType)
+ inline Structure* Structure::create(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, PropertyOffset inlineCapacity)
{
ASSERT(globalData.structureStructure);
ASSERT(classInfo);
- Structure* structure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData, globalObject, prototype, typeInfo, classInfo, indexingType);
+ Structure* structure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData, globalObject, prototype, typeInfo, classInfo, indexingType, inlineCapacity);
structure->finishCreation(globalData);
return structure;
}
@@ -628,15 +589,6 @@ namespace JSC {
ASSERT(m_structure || !globalData.structureStructure);
}
- inline const ClassInfo* JSCell::classInfo() const
- {
-#if ENABLE(GC_VALIDATION)
- return m_structure.unvalidatedGet()->classInfo();
-#else
- return m_structure->classInfo();
-#endif
- }
-
} // namespace JSC
#endif // Structure_h
diff --git a/Source/JavaScriptCore/runtime/StructureChain.h b/Source/JavaScriptCore/runtime/StructureChain.h
index 3b19d4cf1..878f606b4 100644
--- a/Source/JavaScriptCore/runtime/StructureChain.h
+++ b/Source/JavaScriptCore/runtime/StructureChain.h
@@ -59,6 +59,10 @@ namespace JSC {
static ClassInfo s_info;
+ static const bool needsDestruction = true;
+ static const bool hasImmortalStructure = true;
+ static void destroy(JSCell*);
+
protected:
void finishCreation(JSGlobalData& globalData, Structure* head)
{
@@ -78,7 +82,6 @@ namespace JSC {
friend class LLIntOffsetsExtractor;
StructureChain(JSGlobalData&, Structure*);
- static void destroy(JSCell*);
OwnArrayPtr<WriteBarrier<Structure> > m_vector;
};
diff --git a/Source/JavaScriptCore/runtime/StructureTransitionTable.h b/Source/JavaScriptCore/runtime/StructureTransitionTable.h
index 90cb6a4db..3ab7b2014 100644
--- a/Source/JavaScriptCore/runtime/StructureTransitionTable.h
+++ b/Source/JavaScriptCore/runtime/StructureTransitionTable.h
@@ -43,6 +43,7 @@ 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 {
+ AllocateContiguous,
AllocateArrayStorage,
AllocateSlowPutArrayStorage,
SwitchToSlowPutArrayStorage,
@@ -57,13 +58,18 @@ inline unsigned toAttributes(NonPropertyTransition transition)
inline IndexingType newIndexingType(IndexingType oldType, NonPropertyTransition transition)
{
switch (transition) {
+ case AllocateContiguous:
+ ASSERT(!hasIndexedProperties(oldType));
+ return oldType | ContiguousShape;
case AllocateArrayStorage:
- return oldType | HasArrayStorage;
+ ASSERT(!hasIndexedProperties(oldType) || hasContiguous(oldType));
+ return (oldType & ~IndexingShapeMask) | ArrayStorageShape;
case AllocateSlowPutArrayStorage:
- return oldType | HasSlowPutArrayStorage;
+ ASSERT(!hasIndexedProperties(oldType) || hasContiguous(oldType));
+ return (oldType & ~IndexingShapeMask) | SlowPutArrayStorageShape;
case SwitchToSlowPutArrayStorage:
- ASSERT(oldType & HasArrayStorage);
- return (oldType & ~HasArrayStorage) | HasSlowPutArrayStorage;
+ ASSERT(hasFastArrayStorage(oldType));
+ return (oldType & ~IndexingShapeMask) | SlowPutArrayStorageShape;
case AddIndexedAccessors:
return oldType | MayHaveIndexedAccessors;
default:
diff --git a/Source/JavaScriptCore/runtime/SymbolTable.h b/Source/JavaScriptCore/runtime/SymbolTable.h
index 6063dbab4..debb76499 100644
--- a/Source/JavaScriptCore/runtime/SymbolTable.h
+++ b/Source/JavaScriptCore/runtime/SymbolTable.h
@@ -344,12 +344,16 @@ namespace JSC {
class SharedSymbolTable : public JSCell, public SymbolTable {
public:
+ typedef JSCell Base;
+
static SharedSymbolTable* create(JSGlobalData& globalData)
{
SharedSymbolTable* sharedSymbolTable = new (NotNull, allocateCell<SharedSymbolTable>(globalData.heap)) SharedSymbolTable(globalData);
sharedSymbolTable->finishCreation(globalData);
return sharedSymbolTable;
}
+ static const bool needsDestruction = true;
+ static const bool hasImmortalStructure = true;
static void destroy(JSCell*);
static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
@@ -396,6 +400,7 @@ namespace JSC {
OwnArrayPtr<SlowArgument> m_slowArguments;
};
+
} // namespace JSC
#endif // SymbolTable_h
diff --git a/Source/JavaScriptCore/runtime/TypedArrayDescriptor.h b/Source/JavaScriptCore/runtime/TypedArrayDescriptor.h
new file mode 100644
index 000000000..1ae4818be
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/TypedArrayDescriptor.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 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 TypedArrayDescriptor_h
+#define TypedArrayDescriptor_h
+
+namespace JSC {
+
+struct ClassInfo;
+
+enum TypedArrayType {
+ TypedArrayNone,
+ TypedArrayInt8,
+ TypedArrayInt16,
+ TypedArrayInt32,
+ TypedArrayUint8,
+ TypedArrayUint8Clamped,
+ TypedArrayUint16,
+ TypedArrayUint32,
+ TypedArrayFloat32,
+ TypedArrayFloat64
+};
+
+struct TypedArrayDescriptor {
+ TypedArrayDescriptor()
+ : m_classInfo(0)
+ , m_storageOffset(0)
+ , m_lengthOffset(0)
+ {
+ }
+ TypedArrayDescriptor(const ClassInfo* classInfo, size_t storageOffset, size_t lengthOffset)
+ : m_classInfo(classInfo)
+ , m_storageOffset(storageOffset)
+ , m_lengthOffset(lengthOffset)
+ {
+ }
+ const ClassInfo* m_classInfo;
+ size_t m_storageOffset;
+ size_t m_lengthOffset;
+};
+
+enum TypedArraySignedness {
+ SignedTypedArray,
+ UnsignedTypedArray
+};
+enum TypedArrayRounding {
+ TruncateRounding,
+ ClampRounding
+};
+
+} // namespace JSC
+
+#endif // TypedArrayDescriptor_h
+
diff --git a/Source/JavaScriptCore/runtime/WeakGCMap.h b/Source/JavaScriptCore/runtime/WeakGCMap.h
index 6926165a7..52e5e2946 100644
--- a/Source/JavaScriptCore/runtime/WeakGCMap.h
+++ b/Source/JavaScriptCore/runtime/WeakGCMap.h
@@ -63,7 +63,7 @@ public:
{
typename MapType::iterator end = m_map.end();
for (typename MapType::iterator ptr = m_map.begin(); ptr != end; ++ptr)
- WeakSet::deallocate(ptr->second);
+ WeakSet::deallocate(ptr->value);
m_map.clear();
}
@@ -80,8 +80,8 @@ public:
ASSERT_UNUSED(globalData, globalData.apiLock().currentThreadIsHoldingLock());
typename MapType::AddResult result = m_map.add(key, 0);
if (!result.isNewEntry)
- WeakSet::deallocate(result.iterator->second);
- result.iterator->second = WeakSet::allocate(value, this, FinalizerCallback::finalizerContextFor(key));
+ WeakSet::deallocate(result.iterator->value);
+ result.iterator->value = WeakSet::allocate(value, this, FinalizerCallback::finalizerContextFor(key));
}
void remove(const KeyType& key)