From 81bc750723a18f21cd17d1b173cd2a4dda9cea6e Mon Sep 17 00:00:00 2001 From: Ben Murdoch Date: Tue, 24 May 2011 11:24:40 +0100 Subject: Merge WebKit at r80534: Intial merge by Git Change-Id: Ia7a83357124c9e1cdb1debf55d9661ec0bd09a61 --- Source/JavaScriptCore/runtime/ArgList.cpp | 1 + Source/JavaScriptCore/runtime/ArgList.h | 4 +- Source/JavaScriptCore/runtime/Arguments.cpp | 42 +- Source/JavaScriptCore/runtime/Arguments.h | 62 +- Source/JavaScriptCore/runtime/ArrayConstructor.cpp | 7 +- Source/JavaScriptCore/runtime/ArrayPrototype.cpp | 11 +- Source/JavaScriptCore/runtime/ArrayPrototype.h | 5 +- Source/JavaScriptCore/runtime/BooleanObject.cpp | 3 +- Source/JavaScriptCore/runtime/BooleanObject.h | 7 +- Source/JavaScriptCore/runtime/BooleanPrototype.cpp | 11 +- Source/JavaScriptCore/runtime/BooleanPrototype.h | 2 +- Source/JavaScriptCore/runtime/CallData.h | 1 - Source/JavaScriptCore/runtime/CommonIdentifiers.h | 7 - Source/JavaScriptCore/runtime/Completion.cpp | 6 +- Source/JavaScriptCore/runtime/Completion.h | 4 +- Source/JavaScriptCore/runtime/DateConstructor.cpp | 15 +- Source/JavaScriptCore/runtime/DateConstructor.h | 2 +- Source/JavaScriptCore/runtime/DateConversion.cpp | 1 + Source/JavaScriptCore/runtime/DateInstance.cpp | 5 +- Source/JavaScriptCore/runtime/DateInstance.h | 7 +- Source/JavaScriptCore/runtime/DatePrototype.cpp | 70 +- Source/JavaScriptCore/runtime/DatePrototype.h | 5 +- Source/JavaScriptCore/runtime/ErrorInstance.cpp | 8 +- Source/JavaScriptCore/runtime/ErrorInstance.h | 9 +- Source/JavaScriptCore/runtime/ErrorPrototype.cpp | 5 +- Source/JavaScriptCore/runtime/ErrorPrototype.h | 2 +- Source/JavaScriptCore/runtime/ExceptionHelpers.cpp | 8 +- Source/JavaScriptCore/runtime/Executable.cpp | 24 +- Source/JavaScriptCore/runtime/Executable.h | 20 +- .../JavaScriptCore/runtime/FunctionConstructor.cpp | 4 +- .../JavaScriptCore/runtime/FunctionPrototype.cpp | 17 +- Source/JavaScriptCore/runtime/FunctionPrototype.h | 6 +- .../JavaScriptCore/runtime/GCActivityCallback.cpp | 2 +- Source/JavaScriptCore/runtime/GCActivityCallback.h | 4 +- .../runtime/GCActivityCallbackCF.cpp | 3 +- Source/JavaScriptCore/runtime/GCHandle.cpp | 86 -- Source/JavaScriptCore/runtime/GCHandle.h | 116 --- Source/JavaScriptCore/runtime/GetterSetter.h | 2 +- .../JavaScriptCore/runtime/GlobalEvalFunction.cpp | 48 - Source/JavaScriptCore/runtime/GlobalEvalFunction.h | 54 -- Source/JavaScriptCore/runtime/Heap.cpp | 78 +- Source/JavaScriptCore/runtime/Heap.h | 18 +- Source/JavaScriptCore/runtime/Identifier.cpp | 1 + .../JavaScriptCore/runtime/InitializeThreading.cpp | 1 + Source/JavaScriptCore/runtime/InternalFunction.cpp | 12 +- Source/JavaScriptCore/runtime/InternalFunction.h | 9 +- Source/JavaScriptCore/runtime/JSAPIValueWrapper.h | 2 +- Source/JavaScriptCore/runtime/JSActivation.cpp | 27 +- Source/JavaScriptCore/runtime/JSActivation.h | 13 +- Source/JavaScriptCore/runtime/JSArray.cpp | 18 +- Source/JavaScriptCore/runtime/JSArray.h | 10 +- Source/JavaScriptCore/runtime/JSByteArray.cpp | 12 +- Source/JavaScriptCore/runtime/JSByteArray.h | 36 +- Source/JavaScriptCore/runtime/JSCell.cpp | 5 - Source/JavaScriptCore/runtime/JSCell.h | 72 +- Source/JavaScriptCore/runtime/JSChunk.cpp | 28 + Source/JavaScriptCore/runtime/JSChunk.h | 31 + Source/JavaScriptCore/runtime/JSFunction.cpp | 37 +- Source/JavaScriptCore/runtime/JSFunction.h | 20 +- Source/JavaScriptCore/runtime/JSGlobalData.cpp | 22 +- Source/JavaScriptCore/runtime/JSGlobalData.h | 15 +- Source/JavaScriptCore/runtime/JSGlobalObject.cpp | 105 +- Source/JavaScriptCore/runtime/JSGlobalObject.h | 64 +- .../runtime/JSGlobalObjectFunctions.cpp | 5 +- Source/JavaScriptCore/runtime/JSLock.cpp | 12 +- Source/JavaScriptCore/runtime/JSNotAnObject.h | 6 +- Source/JavaScriptCore/runtime/JSNumberCell.cpp | 1 + Source/JavaScriptCore/runtime/JSONObject.cpp | 25 +- Source/JavaScriptCore/runtime/JSONObject.h | 5 +- Source/JavaScriptCore/runtime/JSObject.cpp | 50 +- Source/JavaScriptCore/runtime/JSObject.h | 172 ++-- .../runtime/JSObjectWithGlobalObject.cpp | 2 +- .../runtime/JSObjectWithGlobalObject.h | 6 +- .../runtime/JSPropertyNameIterator.cpp | 16 +- .../runtime/JSPropertyNameIterator.h | 16 +- .../JavaScriptCore/runtime/JSStaticScopeObject.cpp | 10 +- .../JavaScriptCore/runtime/JSStaticScopeObject.h | 2 +- Source/JavaScriptCore/runtime/JSString.h | 2 +- Source/JavaScriptCore/runtime/JSTypeInfo.h | 13 +- Source/JavaScriptCore/runtime/JSVariableObject.cpp | 2 +- Source/JavaScriptCore/runtime/JSVariableObject.h | 44 +- Source/JavaScriptCore/runtime/JSWrapperObject.h | 6 +- Source/JavaScriptCore/runtime/JSZombie.cpp | 3 +- Source/JavaScriptCore/runtime/JSZombie.h | 9 +- Source/JavaScriptCore/runtime/Lookup.cpp | 7 +- .../JavaScriptCore/runtime/MachineStackMarker.cpp | 67 ++ Source/JavaScriptCore/runtime/MarkedBlock.cpp | 33 +- Source/JavaScriptCore/runtime/MarkedBlock.h | 177 ++-- Source/JavaScriptCore/runtime/MarkedSpace.cpp | 103 +- Source/JavaScriptCore/runtime/MarkedSpace.h | 85 +- Source/JavaScriptCore/runtime/MathObject.cpp | 6 +- Source/JavaScriptCore/runtime/MathObject.h | 5 +- .../runtime/NativeErrorConstructor.cpp | 4 +- .../runtime/NativeErrorConstructor.h | 9 +- .../JavaScriptCore/runtime/NativeFunctionWrapper.h | 39 - .../JavaScriptCore/runtime/NumberConstructor.cpp | 6 +- Source/JavaScriptCore/runtime/NumberConstructor.h | 6 +- Source/JavaScriptCore/runtime/NumberObject.cpp | 3 +- Source/JavaScriptCore/runtime/NumberObject.h | 6 +- Source/JavaScriptCore/runtime/NumberPrototype.cpp | 15 +- Source/JavaScriptCore/runtime/NumberPrototype.h | 2 +- .../JavaScriptCore/runtime/ObjectConstructor.cpp | 110 ++- Source/JavaScriptCore/runtime/ObjectConstructor.h | 15 +- Source/JavaScriptCore/runtime/ObjectPrototype.cpp | 25 +- Source/JavaScriptCore/runtime/ObjectPrototype.h | 4 +- Source/JavaScriptCore/runtime/Operations.h | 7 +- .../JavaScriptCore/runtime/PropertyMapHashTable.h | 554 ++++++++++- .../JavaScriptCore/runtime/PropertyNameArray.cpp | 1 + Source/JavaScriptCore/runtime/PropertySlot.h | 9 - Source/JavaScriptCore/runtime/Protect.h | 149 --- .../JavaScriptCore/runtime/PrototypeFunction.cpp | 57 -- Source/JavaScriptCore/runtime/PrototypeFunction.h | 45 - .../JavaScriptCore/runtime/RegExpConstructor.cpp | 6 +- Source/JavaScriptCore/runtime/RegExpConstructor.h | 8 +- Source/JavaScriptCore/runtime/RegExpObject.cpp | 3 +- Source/JavaScriptCore/runtime/RegExpObject.h | 9 +- Source/JavaScriptCore/runtime/RegExpPrototype.cpp | 23 +- Source/JavaScriptCore/runtime/RegExpPrototype.h | 2 +- Source/JavaScriptCore/runtime/ScopeChain.cpp | 19 +- Source/JavaScriptCore/runtime/ScopeChain.h | 189 +--- Source/JavaScriptCore/runtime/ScopeChainMark.h | 6 - Source/JavaScriptCore/runtime/SmallStrings.h | 4 +- .../runtime/StrictEvalActivation.cpp | 2 +- .../JavaScriptCore/runtime/StrictEvalActivation.h | 2 +- .../JavaScriptCore/runtime/StringConstructor.cpp | 7 +- Source/JavaScriptCore/runtime/StringConstructor.h | 2 +- Source/JavaScriptCore/runtime/StringObject.cpp | 5 +- Source/JavaScriptCore/runtime/StringObject.h | 7 +- .../StringObjectThatMasqueradesAsUndefined.h | 2 +- Source/JavaScriptCore/runtime/StringPrototype.cpp | 14 +- Source/JavaScriptCore/runtime/StringPrototype.h | 8 +- Source/JavaScriptCore/runtime/Structure.cpp | 1017 +++++++------------- Source/JavaScriptCore/runtime/Structure.h | 134 +-- .../runtime/StructureTransitionTable.h | 65 +- Source/JavaScriptCore/runtime/WeakGCMap.h | 187 ++-- Source/JavaScriptCore/runtime/WeakGCPtr.h | 139 +-- Source/JavaScriptCore/runtime/WriteBarrier.h | 1 + 137 files changed, 2498 insertions(+), 2651 deletions(-) delete mode 100644 Source/JavaScriptCore/runtime/GCHandle.cpp delete mode 100644 Source/JavaScriptCore/runtime/GCHandle.h delete mode 100644 Source/JavaScriptCore/runtime/GlobalEvalFunction.cpp delete mode 100644 Source/JavaScriptCore/runtime/GlobalEvalFunction.h create mode 100644 Source/JavaScriptCore/runtime/JSChunk.cpp create mode 100644 Source/JavaScriptCore/runtime/JSChunk.h delete mode 100644 Source/JavaScriptCore/runtime/NativeFunctionWrapper.h delete mode 100644 Source/JavaScriptCore/runtime/PrototypeFunction.cpp delete mode 100644 Source/JavaScriptCore/runtime/PrototypeFunction.h (limited to 'Source/JavaScriptCore/runtime') diff --git a/Source/JavaScriptCore/runtime/ArgList.cpp b/Source/JavaScriptCore/runtime/ArgList.cpp index a862ea0..25a8916 100644 --- a/Source/JavaScriptCore/runtime/ArgList.cpp +++ b/Source/JavaScriptCore/runtime/ArgList.cpp @@ -23,6 +23,7 @@ #include "JSValue.h" #include "JSCell.h" +#include "ScopeChain.h" using std::min; diff --git a/Source/JavaScriptCore/runtime/ArgList.h b/Source/JavaScriptCore/runtime/ArgList.h index 57e3c20..5564d5b 100644 --- a/Source/JavaScriptCore/runtime/ArgList.h +++ b/Source/JavaScriptCore/runtime/ArgList.h @@ -67,12 +67,12 @@ namespace JSC { { } - void initialize(Register* buffer, size_t size) + void initialize(WriteBarrier* buffer, size_t size) { ASSERT(!m_markSet); ASSERT(isEmpty()); - m_buffer = buffer; + m_buffer = reinterpret_cast(buffer); m_size = size; #ifndef NDEBUG m_isReadOnly = true; diff --git a/Source/JavaScriptCore/runtime/Arguments.cpp b/Source/JavaScriptCore/runtime/Arguments.cpp index 305b247..e201b91 100644 --- a/Source/JavaScriptCore/runtime/Arguments.cpp +++ b/Source/JavaScriptCore/runtime/Arguments.cpp @@ -35,7 +35,7 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(Arguments); -const ClassInfo Arguments::info = { "Arguments", 0, 0, 0 }; +const ClassInfo Arguments::s_info = { "Arguments", &JSNonFinalObject::s_info, 0, 0 }; Arguments::~Arguments() { @@ -48,11 +48,11 @@ void Arguments::markChildren(MarkStack& markStack) JSObject::markChildren(markStack); if (d->registerArray) - markStack.deprecatedAppendValues(d->registerArray.get(), d->numParameters); + markStack.appendValues(d->registerArray.get(), d->numParameters); if (d->extraArguments) { unsigned numExtraArguments = d->numArguments - d->numParameters; - markStack.deprecatedAppendValues(d->extraArguments, numExtraArguments); + markStack.appendValues(d->extraArguments, numExtraArguments); } markStack.append(&d->callee); @@ -74,9 +74,9 @@ void Arguments::copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxS unsigned parametersLength = min(min(d->numParameters, d->numArguments), maxSize); unsigned i = 0; for (; i < parametersLength; ++i) - buffer[i] = d->registers[d->firstParameterIndex + i].jsValue(); + buffer[i] = d->registers[d->firstParameterIndex + i].get(); for (; i < d->numArguments; ++i) - buffer[i] = d->extraArguments[i - d->numParameters].jsValue(); + buffer[i] = d->extraArguments[i - d->numParameters].get(); return; } @@ -84,13 +84,13 @@ void Arguments::copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxS unsigned i = 0; for (; i < parametersLength; ++i) { if (!d->deletedArguments[i]) - buffer[i] = d->registers[d->firstParameterIndex + i].jsValue(); + buffer[i] = d->registers[d->firstParameterIndex + i].get(); else buffer[i] = get(exec, i); } for (; i < d->numArguments; ++i) { if (!d->deletedArguments[i]) - buffer[i] = d->extraArguments[i - d->numParameters].jsValue(); + buffer[i] = d->extraArguments[i - d->numParameters].get(); else buffer[i] = get(exec, i); } @@ -119,9 +119,9 @@ void Arguments::fillArgList(ExecState* exec, MarkedArgumentBuffer& args) unsigned parametersLength = min(d->numParameters, d->numArguments); unsigned i = 0; for (; i < parametersLength; ++i) - args.append(d->registers[d->firstParameterIndex + i].jsValue()); + args.append(d->registers[d->firstParameterIndex + i].get()); for (; i < d->numArguments; ++i) - args.append(d->extraArguments[i - d->numParameters].jsValue()); + args.append(d->extraArguments[i - d->numParameters].get()); return; } @@ -129,13 +129,13 @@ void Arguments::fillArgList(ExecState* exec, MarkedArgumentBuffer& args) unsigned i = 0; for (; i < parametersLength; ++i) { if (!d->deletedArguments[i]) - args.append(d->registers[d->firstParameterIndex + i].jsValue()); + args.append(d->registers[d->firstParameterIndex + i].get()); else args.append(get(exec, i)); } for (; i < d->numArguments; ++i) { if (!d->deletedArguments[i]) - args.append(d->extraArguments[i - d->numParameters].jsValue()); + args.append(d->extraArguments[i - d->numParameters].get()); else args.append(get(exec, i)); } @@ -145,9 +145,9 @@ bool Arguments::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& sl { if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) { if (i < d->numParameters) { - slot.setRegisterSlot(&d->registers[d->firstParameterIndex + i]); + slot.setValue(d->registers[d->firstParameterIndex + i].get()); } else - slot.setValue(d->extraArguments[i - d->numParameters].jsValue()); + slot.setValue(d->extraArguments[i - d->numParameters].get()); return true; } @@ -184,9 +184,9 @@ bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyNa unsigned i = propertyName.toArrayIndex(isArrayIndex); if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) { if (i < d->numParameters) { - slot.setRegisterSlot(&d->registers[d->firstParameterIndex + i]); + slot.setValue(d->registers[d->firstParameterIndex + i].get()); } else - slot.setValue(d->extraArguments[i - d->numParameters].jsValue()); + slot.setValue(d->extraArguments[i - d->numParameters].get()); return true; } @@ -215,9 +215,9 @@ bool Arguments::getOwnPropertyDescriptor(ExecState* exec, const Identifier& prop unsigned i = propertyName.toArrayIndex(isArrayIndex); if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) { if (i < d->numParameters) { - descriptor.setDescriptor(d->registers[d->firstParameterIndex + i].jsValue(), DontEnum); + descriptor.setDescriptor(d->registers[d->firstParameterIndex + i].get(), DontEnum); } else - descriptor.setDescriptor(d->extraArguments[i - d->numParameters].jsValue(), DontEnum); + descriptor.setDescriptor(d->extraArguments[i - d->numParameters].get(), DontEnum); return true; } @@ -257,9 +257,9 @@ void Arguments::put(ExecState* exec, unsigned i, JSValue value) { if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) { if (i < d->numParameters) - d->registers[d->firstParameterIndex + i] = JSValue(value); + d->registers[d->firstParameterIndex + i].set(exec->globalData(), d->activation ? static_cast(d->activation.get()) : static_cast(this), value); else - d->extraArguments[i - d->numParameters] = JSValue(value); + d->extraArguments[i - d->numParameters].set(exec->globalData(), this, value); return; } @@ -273,9 +273,9 @@ void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue val unsigned i = propertyName.toArrayIndex(isArrayIndex); if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) { if (i < d->numParameters) - d->registers[d->firstParameterIndex + i] = JSValue(value); + d->registers[d->firstParameterIndex + i].set(exec->globalData(), d->activation ? static_cast(d->activation.get()) : static_cast(this), value); else - d->extraArguments[i - d->numParameters] = JSValue(value); + d->extraArguments[i - d->numParameters].set(exec->globalData(), this, value); return; } diff --git a/Source/JavaScriptCore/runtime/Arguments.h b/Source/JavaScriptCore/runtime/Arguments.h index 658538b..007e0f1 100644 --- a/Source/JavaScriptCore/runtime/Arguments.h +++ b/Source/JavaScriptCore/runtime/Arguments.h @@ -29,7 +29,6 @@ #include "JSGlobalObject.h" #include "Interpreter.h" #include "ObjectConstructor.h" -#include "PrototypeFunction.h" namespace JSC { @@ -43,12 +42,12 @@ namespace JSC { ptrdiff_t firstParameterIndex; unsigned numArguments; - Register* registers; - OwnArrayPtr registerArray; + WriteBarrier* registers; + OwnArrayPtr > registerArray; - Register* extraArguments; + WriteBarrier* extraArguments; OwnArrayPtr deletedArguments; - Register extraArgumentsFixedBuffer[4]; + WriteBarrier extraArgumentsFixedBuffer[4]; WriteBarrier callee; bool overrodeLength : 1; @@ -58,7 +57,7 @@ namespace JSC { }; - class Arguments : public JSObject { + class Arguments : public JSNonFinalObject { public: // Use an enum because otherwise gcc insists on doing a memory // read. @@ -70,7 +69,7 @@ namespace JSC { Arguments(CallFrame*, NoParametersType); virtual ~Arguments(); - static const ClassInfo info; + static const ClassInfo s_info; virtual void markChildren(MarkStack&); @@ -84,17 +83,18 @@ namespace JSC { } void copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize); - void copyRegisters(); + void copyRegisters(JSGlobalData&); bool isTornOff() const { return d->registerArray; } void setActivation(JSGlobalData& globalData, JSActivation* activation) { + ASSERT(!d->registerArray); d->activation.set(globalData, this, activation); d->registers = &activation->registerAt(0); } static PassRefPtr createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: @@ -113,8 +113,6 @@ namespace JSC { void createStrictModeCallerIfNecessary(ExecState*); void createStrictModeCalleeIfNecessary(ExecState*); - virtual const ClassInfo* classInfo() const { return &info; } - void init(CallFrame*); OwnPtr d; @@ -124,7 +122,7 @@ namespace JSC { inline Arguments* asArguments(JSValue value) { - ASSERT(asObject(value)->inherits(&Arguments::info)); + ASSERT(asObject(value)->inherits(&Arguments::s_info)); return static_cast(asObject(value)); } @@ -145,9 +143,11 @@ namespace JSC { } inline Arguments::Arguments(CallFrame* callFrame) - : JSObject(callFrame->lexicalGlobalObject()->argumentsStructure()) + : JSNonFinalObject(callFrame->lexicalGlobalObject()->argumentsStructure()) , d(adoptPtr(new ArgumentsData)) { + ASSERT(inherits(&s_info)); + JSFunction* callee; ptrdiff_t firstParameterIndex; Register* argv; @@ -158,19 +158,19 @@ namespace JSC { d->firstParameterIndex = firstParameterIndex; d->numArguments = numArguments; - d->registers = callFrame->registers(); + d->registers = reinterpret_cast*>(callFrame->registers()); - Register* extraArguments; + WriteBarrier* extraArguments; if (d->numArguments <= d->numParameters) extraArguments = 0; else { unsigned numExtraArguments = d->numArguments - d->numParameters; - if (numExtraArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(Register)) - extraArguments = new Register[numExtraArguments]; + if (numExtraArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(WriteBarrier)) + extraArguments = new WriteBarrier[numExtraArguments]; else extraArguments = d->extraArgumentsFixedBuffer; for (unsigned i = 0; i < numExtraArguments; ++i) - extraArguments[i] = argv[d->numParameters + i]; + extraArguments[i].set(callFrame->globalData(), this, argv[d->numParameters + i].jsValue()); } d->extraArguments = extraArguments; @@ -181,13 +181,14 @@ namespace JSC { d->overrodeCaller = false; d->isStrictMode = callFrame->codeBlock()->isStrictMode(); if (d->isStrictMode) - copyRegisters(); + copyRegisters(callFrame->globalData()); } inline Arguments::Arguments(CallFrame* callFrame, NoParametersType) - : JSObject(callFrame->lexicalGlobalObject()->argumentsStructure()) + : JSNonFinalObject(callFrame->lexicalGlobalObject()->argumentsStructure()) , d(adoptPtr(new ArgumentsData)) { + ASSERT(inherits(&s_info)); ASSERT(!asFunction(callFrame->callee())->jsExecutable()->parameterCount()); unsigned numArguments = callFrame->argumentCount(); @@ -195,15 +196,15 @@ namespace JSC { d->numParameters = 0; d->numArguments = numArguments; - Register* extraArguments; + WriteBarrier* extraArguments; if (numArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(Register)) - extraArguments = new Register[numArguments]; + extraArguments = new WriteBarrier[numArguments]; else extraArguments = d->extraArgumentsFixedBuffer; Register* argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numArguments - 1; for (unsigned i = 0; i < numArguments; ++i) - extraArguments[i] = argv[i]; + extraArguments[i].set(callFrame->globalData(), this, argv[i].jsValue()); d->extraArguments = extraArguments; @@ -213,10 +214,10 @@ namespace JSC { d->overrodeCaller = false; d->isStrictMode = callFrame->codeBlock()->isStrictMode(); if (d->isStrictMode) - copyRegisters(); + copyRegisters(callFrame->globalData()); } - inline void Arguments::copyRegisters() + inline void Arguments::copyRegisters(JSGlobalData& globalData) { ASSERT(!isTornOff()); @@ -226,14 +227,15 @@ namespace JSC { int registerOffset = d->numParameters + RegisterFile::CallFrameHeaderSize; size_t registerArraySize = d->numParameters; - OwnArrayPtr registerArray = adoptArrayPtr(new Register[registerArraySize]); - memcpy(registerArray.get(), d->registers - registerOffset, registerArraySize * sizeof(Register)); + OwnArrayPtr > registerArray = adoptArrayPtr(new WriteBarrier[registerArraySize]); + for (size_t i = 0; i < registerArraySize; i++) + registerArray[i].set(globalData, this, d->registers[i - registerOffset].get()); d->registers = registerArray.get() + registerOffset; d->registerArray = registerArray.release(); } // This JSActivation function is defined here so it can get at Arguments::setRegisters. - inline void JSActivation::copyRegisters() + inline void JSActivation::copyRegisters(JSGlobalData& globalData) { ASSERT(!d()->registerArray); @@ -247,8 +249,8 @@ namespace JSC { int registerOffset = numParametersMinusThis + RegisterFile::CallFrameHeaderSize; size_t registerArraySize = numLocals + RegisterFile::CallFrameHeaderSize; - OwnArrayPtr registerArray = copyRegisterArray(d()->registers - registerOffset, registerArraySize); - Register* registers = registerArray.get() + registerOffset; + OwnArrayPtr > registerArray = copyRegisterArray(globalData, d()->registers - registerOffset, registerArraySize); + WriteBarrier* registers = registerArray.get() + registerOffset; setRegisters(registers, registerArray.release()); } diff --git a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp index 5d0adbd..af2afc6 100644 --- a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp @@ -30,7 +30,6 @@ #include "JSArray.h" #include "JSFunction.h" #include "Lookup.h" -#include "PrototypeFunction.h" namespace JSC { @@ -38,7 +37,7 @@ ASSERT_CLASS_FITS_IN_CELL(ArrayConstructor); static EncodedJSValue JSC_HOST_CALL arrayConstructorIsArray(ExecState*); -ArrayConstructor::ArrayConstructor(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure, ArrayPrototype* arrayPrototype, Structure* prototypeFunctionStructure) +ArrayConstructor::ArrayConstructor(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure, ArrayPrototype* arrayPrototype, Structure* functionStructure) : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, arrayPrototype->classInfo()->className)) { // ECMA 15.4.3.1 Array.prototype @@ -48,7 +47,7 @@ ArrayConstructor::ArrayConstructor(ExecState* exec, JSGlobalObject* globalObject putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontEnum | DontDelete); // ES5 - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 1, exec->propertyNames().isArray, arrayConstructorIsArray), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().isArray, arrayConstructorIsArray), DontEnum); } static inline JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgList& args) @@ -94,7 +93,7 @@ CallType ArrayConstructor::getCallData(CallData& callData) EncodedJSValue JSC_HOST_CALL arrayConstructorIsArray(ExecState* exec) { - return JSValue::encode(jsBoolean(exec->argument(0).inherits(&JSArray::info))); + return JSValue::encode(jsBoolean(exec->argument(0).inherits(&JSArray::s_info))); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp index 70c0d06..488effd 100644 --- a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -85,7 +85,7 @@ static inline bool isNumericCompareFunction(ExecState* exec, CallType callType, // ------------------------------ ArrayPrototype ---------------------------- -const ClassInfo ArrayPrototype::info = {"Array", &JSArray::info, 0, ExecState::arrayTable}; +const ClassInfo ArrayPrototype::s_info = {"Array", &JSArray::s_info, 0, ExecState::arrayTable}; /* Source for ArrayPrototype.lut.h @begin arrayTable 16 @@ -117,6 +117,7 @@ const ClassInfo ArrayPrototype::info = {"Array", &JSArray::info, 0, ExecState::a ArrayPrototype::ArrayPrototype(JSGlobalObject* globalObject, NonNullPassRefPtr structure) : JSArray(structure) { + ASSERT(inherits(&s_info)); putAnonymousValue(globalObject->globalData(), 0, globalObject); } @@ -165,7 +166,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); bool isRealArray = isJSArray(&exec->globalData(), thisValue); - if (!isRealArray && !thisValue.inherits(&JSArray::info)) + if (!isRealArray && !thisValue.inherits(&JSArray::s_info)) return throwVMTypeError(exec); JSArray* thisObj = asArray(thisValue); @@ -224,7 +225,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&JSArray::info)) + if (!thisValue.inherits(&JSArray::s_info)) return throwVMTypeError(exec); JSObject* thisObj = asArray(thisValue); @@ -330,7 +331,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec) size_t i = 0; size_t argCount = exec->argumentCount(); while (1) { - if (curArg.inherits(&JSArray::info)) { + if (curArg.inherits(&JSArray::s_info)) { unsigned length = curArg.get(exec, exec->propertyNames().length).toUInt32(exec); JSObject* curObject = curArg.toObject(exec); for (unsigned k = 0; k < length; ++k) { @@ -470,7 +471,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec) CallData callData; CallType callType = getCallData(function, callData); - if (thisObj->classInfo() == &JSArray::info) { + if (thisObj->classInfo() == &JSArray::s_info) { if (isNumericCompareFunction(exec, callType, callData)) asArray(thisObj)->sortNumeric(exec, function, callType, callData); else if (callType != CallTypeNone) diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.h b/Source/JavaScriptCore/runtime/ArrayPrototype.h index 42665e3..e41d8ca 100644 --- a/Source/JavaScriptCore/runtime/ArrayPrototype.h +++ b/Source/JavaScriptCore/runtime/ArrayPrototype.h @@ -33,12 +33,11 @@ namespace JSC { bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); - virtual const ClassInfo* classInfo() const { return &info; } - static const ClassInfo info; + static const ClassInfo s_info; static PassRefPtr createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: diff --git a/Source/JavaScriptCore/runtime/BooleanObject.cpp b/Source/JavaScriptCore/runtime/BooleanObject.cpp index 71ff2d2..16c4669 100644 --- a/Source/JavaScriptCore/runtime/BooleanObject.cpp +++ b/Source/JavaScriptCore/runtime/BooleanObject.cpp @@ -25,11 +25,12 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(BooleanObject); -const ClassInfo BooleanObject::info = { "Boolean", 0, 0, 0 }; +const ClassInfo BooleanObject::s_info = { "Boolean", &JSWrapperObject::s_info, 0, 0 }; BooleanObject::BooleanObject(JSGlobalData& globalData, NonNullPassRefPtr structure) : JSWrapperObject(globalData, structure) { + ASSERT(inherits(&s_info)); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/BooleanObject.h b/Source/JavaScriptCore/runtime/BooleanObject.h index ff10ef6..e2af0c2 100644 --- a/Source/JavaScriptCore/runtime/BooleanObject.h +++ b/Source/JavaScriptCore/runtime/BooleanObject.h @@ -29,12 +29,11 @@ namespace JSC { public: explicit BooleanObject(JSGlobalData& globalData, NonNullPassRefPtr); - virtual const ClassInfo* classInfo() const { return &info; } - static const ClassInfo info; + static const ClassInfo s_info; static PassRefPtr createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } }; @@ -42,7 +41,7 @@ namespace JSC { inline BooleanObject* asBooleanObject(JSValue value) { - ASSERT(asObject(value)->inherits(&BooleanObject::info)); + ASSERT(asObject(value)->inherits(&BooleanObject::s_info)); return static_cast(asObject(value)); } diff --git a/Source/JavaScriptCore/runtime/BooleanPrototype.cpp b/Source/JavaScriptCore/runtime/BooleanPrototype.cpp index 54d621c..d0a64af 100644 --- a/Source/JavaScriptCore/runtime/BooleanPrototype.cpp +++ b/Source/JavaScriptCore/runtime/BooleanPrototype.cpp @@ -26,7 +26,6 @@ #include "JSFunction.h" #include "JSString.h" #include "ObjectPrototype.h" -#include "PrototypeFunction.h" namespace JSC { @@ -38,13 +37,13 @@ static EncodedJSValue JSC_HOST_CALL booleanProtoFuncValueOf(ExecState*); // ECMA 15.6.4 -BooleanPrototype::BooleanPrototype(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure, Structure* prototypeFunctionStructure) +BooleanPrototype::BooleanPrototype(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure, Structure* functionStructure) : BooleanObject(exec->globalData(), structure) { setInternalValue(exec->globalData(), jsBoolean(false)); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 0, exec->propertyNames().toString, booleanProtoFuncToString), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 0, exec->propertyNames().valueOf, booleanProtoFuncValueOf), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().toString, booleanProtoFuncToString), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().valueOf, booleanProtoFuncValueOf), DontEnum); } @@ -61,7 +60,7 @@ EncodedJSValue JSC_HOST_CALL booleanProtoFuncToString(ExecState* exec) if (thisValue == jsBoolean(true)) return JSValue::encode(jsNontrivialString(exec, "true")); - if (!thisValue.inherits(&BooleanObject::info)) + if (!thisValue.inherits(&BooleanObject::s_info)) return throwVMTypeError(exec); if (asBooleanObject(thisValue)->internalValue() == jsBoolean(false)) @@ -77,7 +76,7 @@ EncodedJSValue JSC_HOST_CALL booleanProtoFuncValueOf(ExecState* exec) if (thisValue.isBoolean()) return JSValue::encode(thisValue); - if (!thisValue.inherits(&BooleanObject::info)) + if (!thisValue.inherits(&BooleanObject::s_info)) return throwVMTypeError(exec); return JSValue::encode(asBooleanObject(thisValue)->internalValue()); diff --git a/Source/JavaScriptCore/runtime/BooleanPrototype.h b/Source/JavaScriptCore/runtime/BooleanPrototype.h index ddadc43..d6d3d9f 100644 --- a/Source/JavaScriptCore/runtime/BooleanPrototype.h +++ b/Source/JavaScriptCore/runtime/BooleanPrototype.h @@ -27,7 +27,7 @@ namespace JSC { class BooleanPrototype : public BooleanObject { public: - BooleanPrototype(ExecState*, JSGlobalObject*, NonNullPassRefPtr, Structure* prototypeFunctionStructure); + BooleanPrototype(ExecState*, JSGlobalObject*, NonNullPassRefPtr, Structure* functionStructure); }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/CallData.h b/Source/JavaScriptCore/runtime/CallData.h index 32e1094..b138f54 100644 --- a/Source/JavaScriptCore/runtime/CallData.h +++ b/Source/JavaScriptCore/runtime/CallData.h @@ -30,7 +30,6 @@ #define CallData_h #include "JSValue.h" -#include "NativeFunctionWrapper.h" namespace JSC { diff --git a/Source/JavaScriptCore/runtime/CommonIdentifiers.h b/Source/JavaScriptCore/runtime/CommonIdentifiers.h index 6587a8f..478a639 100644 --- a/Source/JavaScriptCore/runtime/CommonIdentifiers.h +++ b/Source/JavaScriptCore/runtime/CommonIdentifiers.h @@ -39,25 +39,18 @@ macro(compile) \ macro(configurable) \ macro(constructor) \ - macro(create) \ - macro(defineProperty) \ - macro(defineProperties) \ macro(enumerable) \ macro(eval) \ macro(exec) \ macro(fromCharCode) \ macro(global) \ macro(get) \ - macro(getPrototypeOf) \ - macro(getOwnPropertyDescriptor) \ - macro(getOwnPropertyNames) \ macro(hasOwnProperty) \ macro(ignoreCase) \ macro(index) \ macro(input) \ macro(isArray) \ macro(isPrototypeOf) \ - macro(keys) \ macro(length) \ macro(message) \ macro(multiline) \ diff --git a/Source/JavaScriptCore/runtime/Completion.cpp b/Source/JavaScriptCore/runtime/Completion.cpp index eeb8b0d..83d8bd8 100644 --- a/Source/JavaScriptCore/runtime/Completion.cpp +++ b/Source/JavaScriptCore/runtime/Completion.cpp @@ -47,19 +47,19 @@ Completion checkSyntax(ExecState* exec, const SourceCode& source) return Completion(Normal); } -Completion evaluate(ExecState* exec, ScopeChain& scopeChain, const SourceCode& source, JSValue thisValue) +Completion evaluate(ExecState* exec, ScopeChainNode* scopeChain, const SourceCode& source, JSValue thisValue) { JSLock lock(exec); ASSERT(exec->globalData().identifierTable == wtfThreadData().currentIdentifierTable()); RefPtr program = ProgramExecutable::create(exec, source); - JSObject* error = program->compile(exec, scopeChain.node()); + JSObject* error = program->compile(exec, scopeChain); if (error) return Completion(Throw, error); JSObject* thisObj = (!thisValue || thisValue.isUndefinedOrNull()) ? exec->dynamicGlobalObject() : thisValue.toObject(exec); - JSValue result = exec->interpreter()->execute(program.get(), exec, scopeChain.node(), thisObj); + JSValue result = exec->interpreter()->execute(program.get(), exec, scopeChain, thisObj); if (exec->hadException()) { JSValue exception = exec->exception(); diff --git a/Source/JavaScriptCore/runtime/Completion.h b/Source/JavaScriptCore/runtime/Completion.h index 63b315e..1dd25fd 100644 --- a/Source/JavaScriptCore/runtime/Completion.h +++ b/Source/JavaScriptCore/runtime/Completion.h @@ -28,7 +28,7 @@ namespace JSC { class ExecState; - class ScopeChain; + class ScopeChainNode; class SourceCode; enum ComplType { Normal, Break, Continue, ReturnValue, Throw, Interrupted, Terminated }; @@ -56,7 +56,7 @@ namespace JSC { }; Completion checkSyntax(ExecState*, const SourceCode&); - Completion evaluate(ExecState*, ScopeChain&, const SourceCode&, JSValue thisValue = JSValue()); + Completion evaluate(ExecState*, ScopeChainNode*, const SourceCode&, JSValue thisValue = JSValue()); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/DateConstructor.cpp b/Source/JavaScriptCore/runtime/DateConstructor.cpp index f1f3956..efaeb0f 100644 --- a/Source/JavaScriptCore/runtime/DateConstructor.cpp +++ b/Source/JavaScriptCore/runtime/DateConstructor.cpp @@ -30,7 +30,6 @@ #include "JSString.h" #include "JSStringBuilder.h" #include "ObjectPrototype.h" -#include "PrototypeFunction.h" #include #include #include @@ -58,16 +57,16 @@ static EncodedJSValue JSC_HOST_CALL dateParse(ExecState*); static EncodedJSValue JSC_HOST_CALL dateNow(ExecState*); static EncodedJSValue JSC_HOST_CALL dateUTC(ExecState*); -DateConstructor::DateConstructor(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure, Structure* prototypeFunctionStructure, DatePrototype* datePrototype) +DateConstructor::DateConstructor(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure, Structure* functionStructure, DatePrototype* datePrototype) : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, datePrototype->classInfo()->className)) { - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, datePrototype, DontEnum | DontDelete | ReadOnly); + putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, datePrototype, DontEnum | DontDelete | ReadOnly); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 1, exec->propertyNames().parse, dateParse), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 7, exec->propertyNames().UTC, dateUTC), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 0, exec->propertyNames().now, dateNow), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().parse, dateParse), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 7, exec->propertyNames().UTC, dateUTC), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().now, dateNow), DontEnum); - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(7), ReadOnly | DontEnum | DontDelete); + putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(7), ReadOnly | DontEnum | DontDelete); } // ECMA 15.9.3 @@ -80,7 +79,7 @@ JSObject* constructDate(ExecState* exec, const ArgList& args) if (numArgs == 0) // new Date() ECMA 15.9.3.3 value = jsCurrentTime(); else if (numArgs == 1) { - if (args.at(0).inherits(&DateInstance::info)) + if (args.at(0).inherits(&DateInstance::s_info)) value = asDateInstance(args.at(0))->internalNumber(); else { JSValue primitive = args.at(0).toPrimitive(exec); diff --git a/Source/JavaScriptCore/runtime/DateConstructor.h b/Source/JavaScriptCore/runtime/DateConstructor.h index c8ca456..2adcd08 100644 --- a/Source/JavaScriptCore/runtime/DateConstructor.h +++ b/Source/JavaScriptCore/runtime/DateConstructor.h @@ -29,7 +29,7 @@ namespace JSC { class DateConstructor : public InternalFunction { public: - DateConstructor(ExecState*, JSGlobalObject*, NonNullPassRefPtr, Structure* prototypeFunctionStructure, DatePrototype*); + DateConstructor(ExecState*, JSGlobalObject*, NonNullPassRefPtr, Structure* functionStructure, DatePrototype*); private: virtual ConstructType getConstructData(ConstructData&); diff --git a/Source/JavaScriptCore/runtime/DateConversion.cpp b/Source/JavaScriptCore/runtime/DateConversion.cpp index d4b8232..597f1e9 100644 --- a/Source/JavaScriptCore/runtime/DateConversion.cpp +++ b/Source/JavaScriptCore/runtime/DateConversion.cpp @@ -44,6 +44,7 @@ #include "DateConversion.h" #include "CallFrame.h" +#include "ScopeChain.h" #include "UString.h" #include #include diff --git a/Source/JavaScriptCore/runtime/DateInstance.cpp b/Source/JavaScriptCore/runtime/DateInstance.cpp index 44e8b7d..95d5dc2 100644 --- a/Source/JavaScriptCore/runtime/DateInstance.cpp +++ b/Source/JavaScriptCore/runtime/DateInstance.cpp @@ -32,23 +32,26 @@ using namespace WTF; namespace JSC { -const ClassInfo DateInstance::info = {"Date", 0, 0, 0}; +const ClassInfo DateInstance::s_info = {"Date", &JSWrapperObject::s_info, 0, 0}; DateInstance::DateInstance(ExecState* exec, NonNullPassRefPtr structure) : JSWrapperObject(exec->globalData(), structure) { + ASSERT(inherits(&s_info)); setInternalValue(exec->globalData(), jsNaN()); } DateInstance::DateInstance(ExecState* exec, NonNullPassRefPtr structure, double time) : JSWrapperObject(exec->globalData(), structure) { + ASSERT(inherits(&s_info)); setInternalValue(exec->globalData(), jsNumber(timeClip(time))); } DateInstance::DateInstance(ExecState* exec, double time) : JSWrapperObject(exec->globalData(), exec->lexicalGlobalObject()->dateStructure()) { + ASSERT(inherits(&s_info)); setInternalValue(exec->globalData(), jsNumber(timeClip(time))); } diff --git a/Source/JavaScriptCore/runtime/DateInstance.h b/Source/JavaScriptCore/runtime/DateInstance.h index 77d46de..627b9e7 100644 --- a/Source/JavaScriptCore/runtime/DateInstance.h +++ b/Source/JavaScriptCore/runtime/DateInstance.h @@ -37,7 +37,7 @@ namespace JSC { double internalNumber() const { return internalValue().uncheckedGetNumber(); } - static JS_EXPORTDATA const ClassInfo info; + static JS_EXPORTDATA const ClassInfo s_info; const GregorianDateTime* gregorianDateTime(ExecState* exec) const { @@ -55,7 +55,7 @@ namespace JSC { static PassRefPtr createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: @@ -64,7 +64,6 @@ namespace JSC { private: const GregorianDateTime* calculateGregorianDateTime(ExecState*) const; const GregorianDateTime* calculateGregorianDateTimeUTC(ExecState*) const; - virtual const ClassInfo* classInfo() const { return &info; } mutable RefPtr m_data; }; @@ -73,7 +72,7 @@ namespace JSC { inline DateInstance* asDateInstance(JSValue value) { - ASSERT(asObject(value)->inherits(&DateInstance::info)); + ASSERT(asObject(value)->inherits(&DateInstance::s_info)); return static_cast(asObject(value)); } diff --git a/Source/JavaScriptCore/runtime/DatePrototype.cpp b/Source/JavaScriptCore/runtime/DatePrototype.cpp index 5838b60..314baa4 100644 --- a/Source/JavaScriptCore/runtime/DatePrototype.cpp +++ b/Source/JavaScriptCore/runtime/DatePrototype.cpp @@ -130,7 +130,7 @@ enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime }; #if PLATFORM(MAC) // FIXME: Since this is superior to the strftime-based version, why limit this to PLATFORM(MAC)? -// Instead we should consider using this whenever PLATFORM(CF) is true. +// Instead we should consider using this whenever USE(CF) is true. static CFDateFormatterStyle styleFromArgString(const UString& string, CFDateFormatterStyle defaultStyle) { @@ -374,7 +374,7 @@ static bool fillStructuresUsingDateArgs(ExecState *exec, int maxArgs, double *ms return ok; } -const ClassInfo DatePrototype::info = {"Date", &DateInstance::info, 0, ExecState::dateTable}; +const ClassInfo DatePrototype::s_info = {"Date", &DateInstance::s_info, 0, ExecState::dateTable}; /* Source for DatePrototype.lut.h @begin dateTable @@ -432,6 +432,8 @@ const ClassInfo DatePrototype::info = {"Date", &DateInstance::info, 0, ExecState DatePrototype::DatePrototype(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure) : DateInstance(exec, structure) { + ASSERT(inherits(&s_info)); + // The constructor will be added later, after DateConstructor has been built. putAnonymousValue(exec->globalData(), 0, globalObject); } @@ -452,7 +454,7 @@ bool DatePrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -470,7 +472,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -488,7 +490,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -507,7 +509,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -523,7 +525,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -539,7 +541,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -549,7 +551,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -559,7 +561,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -569,7 +571,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); return JSValue::encode(asDateInstance(thisValue)->internalValue()); @@ -578,7 +580,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -592,7 +594,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -606,7 +608,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -624,7 +626,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -638,7 +640,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -652,7 +654,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -666,7 +668,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -680,7 +682,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -694,7 +696,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -708,7 +710,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -722,7 +724,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -736,7 +738,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -750,7 +752,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -764,7 +766,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -778,7 +780,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -792,7 +794,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -808,7 +810,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -824,7 +826,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -838,7 +840,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -852,7 +854,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec) static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -889,7 +891,7 @@ static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -1013,7 +1015,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -1054,7 +1056,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); diff --git a/Source/JavaScriptCore/runtime/DatePrototype.h b/Source/JavaScriptCore/runtime/DatePrototype.h index e3672aa..dca90e3 100644 --- a/Source/JavaScriptCore/runtime/DatePrototype.h +++ b/Source/JavaScriptCore/runtime/DatePrototype.h @@ -34,12 +34,11 @@ namespace JSC { virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); - virtual const ClassInfo* classInfo() const { return &info; } - static const ClassInfo info; + static const ClassInfo s_info; static PassRefPtr createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: diff --git a/Source/JavaScriptCore/runtime/ErrorInstance.cpp b/Source/JavaScriptCore/runtime/ErrorInstance.cpp index a6208d5..0db2af8 100644 --- a/Source/JavaScriptCore/runtime/ErrorInstance.cpp +++ b/Source/JavaScriptCore/runtime/ErrorInstance.cpp @@ -23,19 +23,21 @@ namespace JSC { -const ClassInfo ErrorInstance::info = { "Error", 0, 0, 0 }; +const ClassInfo ErrorInstance::s_info = { "Error", &JSNonFinalObject::s_info, 0, 0 }; ErrorInstance::ErrorInstance(JSGlobalData* globalData, NonNullPassRefPtr structure) - : JSObject(structure) + : JSNonFinalObject(structure) , m_appendSourceToMessage(false) { + ASSERT(inherits(&s_info)); putDirect(*globalData, globalData->propertyNames->message, jsString(globalData, "")); } ErrorInstance::ErrorInstance(JSGlobalData* globalData, NonNullPassRefPtr structure, const UString& message) - : JSObject(structure) + : JSNonFinalObject(structure) , m_appendSourceToMessage(false) { + ASSERT(inherits(&s_info)); putDirect(*globalData, globalData->propertyNames->message, jsString(globalData, message)); } diff --git a/Source/JavaScriptCore/runtime/ErrorInstance.h b/Source/JavaScriptCore/runtime/ErrorInstance.h index b3bebec..c1beef7 100644 --- a/Source/JavaScriptCore/runtime/ErrorInstance.h +++ b/Source/JavaScriptCore/runtime/ErrorInstance.h @@ -25,11 +25,14 @@ namespace JSC { - class ErrorInstance : public JSObject { + class ErrorInstance : public JSNonFinalObject { public: + static const ClassInfo s_info; - virtual const ClassInfo* classInfo() const { return &info; } - static const ClassInfo info; + static PassRefPtr createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); + } static ErrorInstance* create(JSGlobalData*, NonNullPassRefPtr, const UString&); static ErrorInstance* create(ExecState* exec, NonNullPassRefPtr, JSValue message); diff --git a/Source/JavaScriptCore/runtime/ErrorPrototype.cpp b/Source/JavaScriptCore/runtime/ErrorPrototype.cpp index b4e0a7c..e13251c 100644 --- a/Source/JavaScriptCore/runtime/ErrorPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ErrorPrototype.cpp @@ -25,7 +25,6 @@ #include "JSString.h" #include "JSStringBuilder.h" #include "ObjectPrototype.h" -#include "PrototypeFunction.h" #include "StringRecursionChecker.h" #include "UString.h" @@ -36,13 +35,13 @@ ASSERT_CLASS_FITS_IN_CELL(ErrorPrototype); static EncodedJSValue JSC_HOST_CALL errorProtoFuncToString(ExecState*); // ECMA 15.9.4 -ErrorPrototype::ErrorPrototype(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure, Structure* prototypeFunctionStructure) +ErrorPrototype::ErrorPrototype(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure, Structure* functionStructure) : ErrorInstance(&exec->globalData(), structure) { // The constructor will be added later in ErrorConstructor's constructor putDirectWithoutTransition(exec->globalData(), exec->propertyNames().name, jsNontrivialString(exec, "Error"), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 0, exec->propertyNames().toString, errorProtoFuncToString), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().toString, errorProtoFuncToString), DontEnum); } EncodedJSValue JSC_HOST_CALL errorProtoFuncToString(ExecState* exec) diff --git a/Source/JavaScriptCore/runtime/ErrorPrototype.h b/Source/JavaScriptCore/runtime/ErrorPrototype.h index fce2742..3c2fed3 100644 --- a/Source/JavaScriptCore/runtime/ErrorPrototype.h +++ b/Source/JavaScriptCore/runtime/ErrorPrototype.h @@ -29,7 +29,7 @@ namespace JSC { class ErrorPrototype : public ErrorInstance { public: - ErrorPrototype(ExecState*, JSGlobalObject*, NonNullPassRefPtr, Structure* prototypeFunctionStructure); + ErrorPrototype(ExecState*, JSGlobalObject*, NonNullPassRefPtr, Structure* functionStructure); }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp index 4a58800..d3c637e 100644 --- a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp +++ b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp @@ -41,10 +41,10 @@ namespace JSC { -class InterruptedExecutionError : public JSObject { +class InterruptedExecutionError : public JSNonFinalObject { public: InterruptedExecutionError(JSGlobalData* globalData) - : JSObject(globalData->interruptedExecutionErrorStructure) + : JSNonFinalObject(globalData->interruptedExecutionErrorStructure) { } @@ -58,10 +58,10 @@ JSObject* createInterruptedExecutionException(JSGlobalData* globalData) return new (globalData) InterruptedExecutionError(globalData); } -class TerminatedExecutionError : public JSObject { +class TerminatedExecutionError : public JSNonFinalObject { public: TerminatedExecutionError(JSGlobalData* globalData) - : JSObject(globalData->terminatedExecutionErrorStructure) + : JSNonFinalObject(globalData->terminatedExecutionErrorStructure) { } diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp index 25c551b..607a2c2 100644 --- a/Source/JavaScriptCore/runtime/Executable.cpp +++ b/Source/JavaScriptCore/runtime/Executable.cpp @@ -35,11 +35,9 @@ namespace JSC { -#if ENABLE(JIT) NativeExecutable::~NativeExecutable() { } -#endif VPtrHackExecutable::~VPtrHackExecutable() { @@ -103,12 +101,11 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scope } recordParse(evalNode->features(), evalNode->hasCapturedVariables(), evalNode->lineNo(), evalNode->lastLine()); - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); + JSGlobalObject* globalObject = scopeChainNode->globalObject.get(); ASSERT(!m_evalCodeBlock); - m_evalCodeBlock = adoptPtr(new EvalCodeBlock(this, globalObject, source().provider(), scopeChain.localDepth())); - OwnPtr generator(adoptPtr(new BytecodeGenerator(evalNode.get(), scopeChain, m_evalCodeBlock->symbolTable(), m_evalCodeBlock.get()))); + m_evalCodeBlock = adoptPtr(new EvalCodeBlock(this, globalObject, source().provider(), scopeChainNode->localDepth())); + OwnPtr generator(adoptPtr(new BytecodeGenerator(evalNode.get(), scopeChainNode, m_evalCodeBlock->symbolTable(), m_evalCodeBlock.get()))); if ((exception = generator->generate())) { m_evalCodeBlock.clear(); evalNode->destroyData(); @@ -156,11 +153,10 @@ JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* sc } recordParse(programNode->features(), programNode->hasCapturedVariables(), programNode->lineNo(), programNode->lastLine()); - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); + JSGlobalObject* globalObject = scopeChainNode->globalObject.get(); m_programCodeBlock = adoptPtr(new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider())); - OwnPtr generator(adoptPtr(new BytecodeGenerator(programNode.get(), scopeChain, &globalObject->symbolTable(), m_programCodeBlock.get()))); + OwnPtr generator(adoptPtr(new BytecodeGenerator(programNode.get(), scopeChainNode, &globalObject->symbolTable(), m_programCodeBlock.get()))); if ((exception = generator->generate())) { m_programCodeBlock.clear(); programNode->destroyData(); @@ -196,12 +192,11 @@ JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChain body->finishParsing(m_parameters, m_name); recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine()); - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); + JSGlobalObject* globalObject = scopeChainNode->globalObject.get(); ASSERT(!m_codeBlockForCall); m_codeBlockForCall = adoptPtr(new FunctionCodeBlock(this, FunctionCode, globalObject, source().provider(), source().startOffset(), false)); - OwnPtr generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChain, m_codeBlockForCall->symbolTable(), m_codeBlockForCall.get()))); + OwnPtr generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChainNode, m_codeBlockForCall->symbolTable(), m_codeBlockForCall.get()))); if ((exception = generator->generate())) { m_codeBlockForCall.clear(); body->destroyData(); @@ -242,12 +237,11 @@ JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, Scope body->finishParsing(m_parameters, m_name); recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine()); - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); + JSGlobalObject* globalObject = scopeChainNode->globalObject.get(); ASSERT(!m_codeBlockForConstruct); m_codeBlockForConstruct = adoptPtr(new FunctionCodeBlock(this, FunctionCode, globalObject, source().provider(), source().startOffset(), true)); - OwnPtr generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChain, m_codeBlockForConstruct->symbolTable(), m_codeBlockForConstruct.get()))); + OwnPtr generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChainNode, m_codeBlockForConstruct->symbolTable(), m_codeBlockForConstruct.get()))); if ((exception = generator->generate())) { m_codeBlockForConstruct.clear(); body->destroyData(); diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h index 544e487..b2565a0 100644 --- a/Source/JavaScriptCore/runtime/Executable.h +++ b/Source/JavaScriptCore/runtime/Executable.h @@ -92,22 +92,29 @@ namespace JSC { #endif }; -#if ENABLE(JIT) class NativeExecutable : public ExecutableBase { friend class JIT; public: +#if ENABLE(JIT) static PassRefPtr create(MacroAssemblerCodePtr callThunk, NativeFunction function, MacroAssemblerCodePtr constructThunk, NativeFunction constructor) { if (!callThunk) return adoptRef(new NativeExecutable(JITCode(), function, JITCode(), constructor)); return adoptRef(new NativeExecutable(JITCode::HostFunction(callThunk), function, JITCode::HostFunction(constructThunk), constructor)); } +#else + static PassRefPtr create(NativeFunction function, NativeFunction constructor) + { + return adoptRef(new NativeExecutable(function, constructor)); + } +#endif ~NativeExecutable(); NativeFunction function() { return m_function; } private: +#if ENABLE(JIT) NativeExecutable(JITCode callThunk, NativeFunction function, JITCode constructThunk, NativeFunction constructor) : ExecutableBase(NUM_PARAMETERS_IS_HOST) , m_function(function) @@ -118,13 +125,20 @@ namespace JSC { m_jitCodeForCallWithArityCheck = callThunk.addressForCall(); m_jitCodeForConstructWithArityCheck = constructThunk.addressForCall(); } +#else + NativeExecutable(NativeFunction function, NativeFunction constructor) + : ExecutableBase(NUM_PARAMETERS_IS_HOST) + , m_function(function) + , m_constructor(constructor) + { + } +#endif NativeFunction m_function; // Probably should be a NativeConstructor, but this will currently require rewriting the JIT // trampoline. It may be easier to make NativeFunction be passed 'this' as a part of the ArgList. NativeFunction m_constructor; }; -#endif class VPtrHackExecutable : public ExecutableBase { public: @@ -398,13 +412,11 @@ namespace JSC { return m_executable->isHostFunction(); } -#if ENABLE(JIT) inline NativeFunction JSFunction::nativeFunction() { ASSERT(isHostFunction()); return static_cast(m_executable.get())->function(); } -#endif } #endif diff --git a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp index 933b11f..e642594 100644 --- a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp +++ b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp @@ -106,8 +106,8 @@ JSObject* constructFunction(ExecState* exec, const ArgList& args, const Identifi return throwError(exec, exception); } - ScopeChain scopeChain(globalObject, &globalData, globalObject, exec->globalThisValue()); - return new (exec) JSFunction(exec, function, scopeChain.node()); + ScopeChainNode* scopeChain = new (exec) ScopeChainNode(0, globalObject, &globalData, globalObject, exec->globalThisValue()); + return new (exec) JSFunction(exec, function, scopeChain); } // ECMA 15.3.2 The Function Constructor diff --git a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp index e651538..c2d8ad3 100644 --- a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp +++ b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp @@ -28,7 +28,6 @@ #include "JSStringBuilder.h" #include "Interpreter.h" #include "Lexer.h" -#include "PrototypeFunction.h" namespace JSC { @@ -44,12 +43,12 @@ FunctionPrototype::FunctionPrototype(ExecState* exec, JSGlobalObject* globalObje putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum); } -void FunctionPrototype::addFunctionProperties(ExecState* exec, JSGlobalObject* globalObject, Structure* prototypeFunctionStructure, NativeFunctionWrapper** callFunction, NativeFunctionWrapper** applyFunction) +void FunctionPrototype::addFunctionProperties(ExecState* exec, JSGlobalObject* globalObject, Structure* functionStructure, JSFunction** callFunction, JSFunction** applyFunction) { - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 0, exec->propertyNames().toString, functionProtoFuncToString), DontEnum); - *applyFunction = new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 2, exec->propertyNames().apply, functionProtoFuncApply); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().toString, functionProtoFuncToString), DontEnum); + *applyFunction = new (exec) JSFunction(exec, globalObject, functionStructure, 2, exec->propertyNames().apply, functionProtoFuncApply); putDirectFunctionWithoutTransition(exec, *applyFunction, DontEnum); - *callFunction = new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 1, exec->propertyNames().call, functionProtoFuncCall); + *callFunction = new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().call, functionProtoFuncCall); putDirectFunctionWithoutTransition(exec, *callFunction, DontEnum); } @@ -86,7 +85,7 @@ static inline void insertSemicolonIfNeeded(UString& functionBody) EncodedJSValue JSC_HOST_CALL functionProtoFuncToString(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (thisValue.inherits(&JSFunction::info)) { + if (thisValue.inherits(&JSFunction::s_info)) { JSFunction* function = asFunction(thisValue); if (function->isHostFunction()) return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "() {\n [native code]\n}")); @@ -96,7 +95,7 @@ EncodedJSValue JSC_HOST_CALL functionProtoFuncToString(ExecState* exec) return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "(", executable->paramString(), ") ", sourceString)); } - if (thisValue.inherits(&InternalFunction::info)) { + if (thisValue.inherits(&InternalFunction::s_info)) { InternalFunction* function = asInternalFunction(thisValue); return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "() {\n [native code]\n}")); } @@ -118,11 +117,11 @@ EncodedJSValue JSC_HOST_CALL functionProtoFuncApply(ExecState* exec) if (!array.isUndefinedOrNull()) { if (!array.isObject()) return throwVMTypeError(exec); - if (asObject(array)->classInfo() == &Arguments::info) + if (asObject(array)->classInfo() == &Arguments::s_info) asArguments(array)->fillArgList(exec, applyArgs); else if (isJSArray(&exec->globalData(), array)) asArray(array)->fillArgList(exec, applyArgs); - else if (asObject(array)->inherits(&JSArray::info)) { + else if (asObject(array)->inherits(&JSArray::s_info)) { unsigned length = asArray(array)->get(exec, exec->propertyNames().length).toUInt32(exec); for (unsigned i = 0; i < length; ++i) applyArgs.append(asArray(array)->get(exec, i)); diff --git a/Source/JavaScriptCore/runtime/FunctionPrototype.h b/Source/JavaScriptCore/runtime/FunctionPrototype.h index 5661194..fb0bb48 100644 --- a/Source/JavaScriptCore/runtime/FunctionPrototype.h +++ b/Source/JavaScriptCore/runtime/FunctionPrototype.h @@ -25,16 +25,14 @@ namespace JSC { - class PrototypeFunction; - class FunctionPrototype : public InternalFunction { public: FunctionPrototype(ExecState*, JSGlobalObject*, NonNullPassRefPtr); - void addFunctionProperties(ExecState*, JSGlobalObject*, Structure* prototypeFunctionStructure, NativeFunctionWrapper** callFunction, NativeFunctionWrapper** applyFunction); + void addFunctionProperties(ExecState*, JSGlobalObject*, Structure* functionStructure, JSFunction** callFunction, JSFunction** applyFunction); static PassRefPtr createStructure(JSValue proto) { - return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } private: diff --git a/Source/JavaScriptCore/runtime/GCActivityCallback.cpp b/Source/JavaScriptCore/runtime/GCActivityCallback.cpp index 161abfb..308d245 100644 --- a/Source/JavaScriptCore/runtime/GCActivityCallback.cpp +++ b/Source/JavaScriptCore/runtime/GCActivityCallback.cpp @@ -34,7 +34,7 @@ namespace JSC { struct DefaultGCActivityCallbackPlatformData { }; -DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap) +DefaultGCActivityCallback::DefaultGCActivityCallback(Heap*) { } diff --git a/Source/JavaScriptCore/runtime/GCActivityCallback.h b/Source/JavaScriptCore/runtime/GCActivityCallback.h index 9b6ef04..eabb4cc 100644 --- a/Source/JavaScriptCore/runtime/GCActivityCallback.h +++ b/Source/JavaScriptCore/runtime/GCActivityCallback.h @@ -32,7 +32,7 @@ #include #include -#if PLATFORM(CF) +#if USE(CF) #include #endif @@ -62,7 +62,7 @@ public: void operator()(); void synchronize(); -#if PLATFORM(CF) +#if USE(CF) protected: DefaultGCActivityCallback(Heap*, CFRunLoopRef); void commonConstructor(Heap*, CFRunLoopRef); diff --git a/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp b/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp index 211c423..a941cfa 100644 --- a/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp +++ b/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp @@ -33,10 +33,11 @@ #include "Heap.h" #include "JSGlobalData.h" #include "JSLock.h" +#include "ScopeChain.h" #include #include -#if !PLATFORM(CF) +#if !USE(CF) #error "This file should only be used on CF platforms." #endif diff --git a/Source/JavaScriptCore/runtime/GCHandle.cpp b/Source/JavaScriptCore/runtime/GCHandle.cpp deleted file mode 100644 index 297de38..0000000 --- a/Source/JavaScriptCore/runtime/GCHandle.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2010 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 "GCHandle.h" - -namespace JSC { - -WeakGCHandlePool* WeakGCHandle::pool() -{ - uintptr_t pool = (reinterpret_cast(this) & WeakGCHandlePool::poolMask); - return reinterpret_cast(pool); -} - -WeakGCHandlePool::WeakGCHandlePool() -{ - ASSERT(sizeof(WeakGCHandlePool) <= WeakGCHandlePool::poolSize); - m_entriesSize = 0; - m_initialAlloc = 1; - m_entries[0].setNextInFreeList(0); -} - -WeakGCHandle* WeakGCHandlePool::allocate(JSCell* cell) -{ - ASSERT(cell); - ASSERT(m_entries[0].isNext()); - unsigned freeList = m_entries[0].getNextInFreeList(); - ASSERT(freeList < WeakGCHandlePool::numPoolEntries); - ASSERT(m_entriesSize < WeakGCHandlePool::numPoolEntries); - - if (m_entriesSize == WeakGCHandlePool::numPoolEntries - 1) - return 0; - - if (freeList) { - unsigned i = freeList; - freeList = m_entries[i].getNextInFreeList(); - m_entries[i].set(cell); - m_entries[0].setNextInFreeList(freeList); - ++m_entriesSize; - return &m_entries[i]; - } - - ASSERT(m_initialAlloc < WeakGCHandlePool::numPoolEntries); - - unsigned i = m_initialAlloc; - ++m_initialAlloc; - m_entries[i].set(cell); - ++m_entriesSize; - return &m_entries[i]; - -} - -void WeakGCHandlePool::free(WeakGCHandle* handle) -{ - ASSERT(handle->pool() == this); - ASSERT(m_entries[0].isNext()); - unsigned freeList = m_entries[0].getNextInFreeList(); - ASSERT(freeList < WeakGCHandlePool::numPoolEntries); - handle->setNextInFreeList(freeList); - m_entries[0].setNextInFreeList(handle - m_entries); - --m_entriesSize; -} - -} diff --git a/Source/JavaScriptCore/runtime/GCHandle.h b/Source/JavaScriptCore/runtime/GCHandle.h deleted file mode 100644 index 8818f79..0000000 --- a/Source/JavaScriptCore/runtime/GCHandle.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#ifndef GCHandle_h -#define GCHandle_h - -#include - -namespace JSC { - -class Heap; -class JSCell; -class WeakGCHandle; -class WeakGCHandlePool; - -class WeakGCHandle { - friend class WeakGCHandlePool; - -public: - // Because JSCell objects are aligned, we can use the lower two bits as - // status flags. The least significant bit is set when the handle is not a - // pointer, i.e. when it's used as a offset for the free list in - // WeakGCHandlePool. The second least significant bit is set when the object - // the pointer corresponds to has been deleted by a garbage collection - - bool isValidPtr() { return !(m_ptr & 3); } - bool isPtr() { return !(m_ptr & 1); } - bool isNext() { return (m_ptr & 3) == 1; } - - void invalidate() - { - ASSERT(isValidPtr()); - m_ptr |= 2; - } - - JSCell* get() - { - ASSERT(isPtr()); - return reinterpret_cast(m_ptr & ~3); - } - - void set(JSCell* p) - { - m_ptr = reinterpret_cast(p); - ASSERT(isPtr()); - } - - WeakGCHandlePool* pool(); - -private: - uintptr_t getNextInFreeList() - { - ASSERT(isNext()); - return m_ptr >> 2; - } - - void setNextInFreeList(uintptr_t n) - { - m_ptr = (n << 2) | 1; - ASSERT(isNext()); - } - - uintptr_t m_ptr; -}; - -class WeakGCHandlePool { -public: - static const size_t poolSize = 32 * 1024; // 32k - static const size_t poolMask = ~(poolSize - 1); - static const size_t numPoolEntries = (poolSize - sizeof(Heap*) - 3 * sizeof(unsigned)) / sizeof(WeakGCHandle); - - WeakGCHandlePool(); - - WeakGCHandle* allocate(JSCell* cell); - void free(WeakGCHandle*); - - bool isFull() - { - ASSERT(m_entriesSize < WeakGCHandlePool::numPoolEntries); - return m_entriesSize == WeakGCHandlePool::numPoolEntries - 1; - } - - void update(); - -private: - Heap* m_heap; - unsigned m_entriesSize; - unsigned m_initialAlloc; - - WeakGCHandle m_entries[WeakGCHandlePool::numPoolEntries]; -}; - -} -#endif diff --git a/Source/JavaScriptCore/runtime/GetterSetter.h b/Source/JavaScriptCore/runtime/GetterSetter.h index ffab94d..68a8c70 100644 --- a/Source/JavaScriptCore/runtime/GetterSetter.h +++ b/Source/JavaScriptCore/runtime/GetterSetter.h @@ -49,7 +49,7 @@ namespace JSC { void setSetter(JSGlobalData& globalData, JSObject* setter) { m_setter.set(globalData, this, setter); } static PassRefPtr createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(GetterSetterType, OverridesMarkChildren), AnonymousSlotCount); + return Structure::create(prototype, TypeInfo(GetterSetterType, OverridesMarkChildren), AnonymousSlotCount, 0); } private: virtual bool isGetterSetter() const; diff --git a/Source/JavaScriptCore/runtime/GlobalEvalFunction.cpp b/Source/JavaScriptCore/runtime/GlobalEvalFunction.cpp deleted file mode 100644 index 27207e2..0000000 --- a/Source/JavaScriptCore/runtime/GlobalEvalFunction.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) - * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. - * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) - * Copyright (C) 2007 Maks Orlovich - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "GlobalEvalFunction.h" - -#include "JSGlobalObject.h" -#include - -namespace JSC { - -ASSERT_CLASS_FITS_IN_CELL(GlobalEvalFunction); - -GlobalEvalFunction::GlobalEvalFunction(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure, int len, const Identifier& name, NativeFunction function, JSGlobalObject* cachedGlobalObject) - : PrototypeFunction(exec, globalObject, structure, len, name, function) - , m_cachedGlobalObject(exec->globalData(), this, cachedGlobalObject) -{ - ASSERT_ARG(cachedGlobalObject, cachedGlobalObject); -} - -void GlobalEvalFunction::markChildren(MarkStack& markStack) -{ - PrototypeFunction::markChildren(markStack); - markStack.append(&m_cachedGlobalObject); -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/GlobalEvalFunction.h b/Source/JavaScriptCore/runtime/GlobalEvalFunction.h deleted file mode 100644 index 13f0946..0000000 --- a/Source/JavaScriptCore/runtime/GlobalEvalFunction.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. - * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) - * Copyright (C) 2007 Maks Orlovich - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#ifndef GlobalEvalFunction_h -#define GlobalEvalFunction_h - -#include "PrototypeFunction.h" - -namespace JSC { - - class JSGlobalObject; - - class GlobalEvalFunction : public PrototypeFunction { - public: - GlobalEvalFunction(ExecState*, JSGlobalObject*, NonNullPassRefPtr, int len, const Identifier&, NativeFunction, JSGlobalObject* expectedThisObject); - JSGlobalObject* cachedGlobalObject() const { return m_cachedGlobalObject.get(); } - - static PassRefPtr createStructure(JSValue prototype) - { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); - } - - protected: - static const unsigned StructureFlags = ImplementsHasInstance | OverridesMarkChildren | OverridesGetPropertyNames | PrototypeFunction::StructureFlags; - - private: - virtual void markChildren(MarkStack&); - - WriteBarrier m_cachedGlobalObject; - }; - -} // namespace JSC - -#endif // GlobalEvalFunction_h diff --git a/Source/JavaScriptCore/runtime/Heap.cpp b/Source/JavaScriptCore/runtime/Heap.cpp index c05233c..c52bcfe 100644 --- a/Source/JavaScriptCore/runtime/Heap.cpp +++ b/Source/JavaScriptCore/runtime/Heap.cpp @@ -24,7 +24,6 @@ #include "CodeBlock.h" #include "ConservativeSet.h" #include "GCActivityCallback.h" -#include "GCHandle.h" #include "Interpreter.h" #include "JSGlobalData.h" #include "JSGlobalObject.h" @@ -33,7 +32,7 @@ #include "Tracing.h" #include -#define COLLECT_ON_EVERY_ALLOCATION 0 +#define COLLECT_ON_EVERY_SLOW_ALLOCATION 0 using namespace std; @@ -49,8 +48,10 @@ Heap::Heap(JSGlobalData* globalData) , m_globalData(globalData) , m_machineStackMarker(this) , m_markStack(globalData->jsArrayVPtr) + , m_handleHeap(globalData) , m_extraCost(0) { + m_markedSpace.setHighWaterMark(minBytesPerCycle); (*m_activityCallback)(); } @@ -76,7 +77,8 @@ void Heap::destroy() delete m_markListSet; m_markListSet = 0; - + m_markedSpace.clearMarks(); + m_handleHeap.clearWeakPointers(); m_markedSpace.destroy(); m_globalData = 0; @@ -100,64 +102,29 @@ void Heap::reportExtraMemoryCostSlowCase(size_t cost) m_extraCost += cost; } -void* Heap::allocate(size_t s) +void* Heap::allocateSlowCase(size_t bytes) { ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable()); ASSERT(JSLock::lockCount() > 0); ASSERT(JSLock::currentThreadIsHoldingLock()); - ASSERT_UNUSED(s, s <= MarkedBlock::CELL_SIZE); + ASSERT(bytes <= MarkedSpace::maxCellSize); ASSERT(m_operationInProgress == NoOperation); -#if COLLECT_ON_EVERY_ALLOCATION +#if COLLECT_ON_EVERY_SLOW_ALLOCATION collectAllGarbage(); ASSERT(m_operationInProgress == NoOperation); #endif + reset(DoNotSweep); + m_operationInProgress = Allocation; - void* result = m_markedSpace.allocate(s); + void* result = m_markedSpace.allocate(bytes); m_operationInProgress = NoOperation; - if (!result) { - reset(DoNotSweep); - - m_operationInProgress = Allocation; - result = m_markedSpace.allocate(s); - m_operationInProgress = NoOperation; - } ASSERT(result); return result; } -void Heap::updateWeakGCHandles() -{ - for (unsigned i = 0; i < m_weakGCHandlePools.size(); ++i) - weakGCHandlePool(i)->update(); -} - -void WeakGCHandlePool::update() -{ - for (unsigned i = 1; i < WeakGCHandlePool::numPoolEntries; ++i) { - if (m_entries[i].isValidPtr()) { - JSCell* cell = m_entries[i].get(); - if (!cell || !Heap::isMarked(cell)) - m_entries[i].invalidate(); - } - } -} - -WeakGCHandle* Heap::addWeakGCHandle(JSCell* ptr) -{ - for (unsigned i = 0; i < m_weakGCHandlePools.size(); ++i) - if (!weakGCHandlePool(i)->isFull()) - return weakGCHandlePool(i)->allocate(ptr); - - PageAllocationAligned allocation = PageAllocationAligned::allocate(WeakGCHandlePool::poolSize, WeakGCHandlePool::poolSize, OSAllocator::JSGCHeapPages); - m_weakGCHandlePools.append(allocation); - - WeakGCHandlePool* pool = new (allocation.base()) WeakGCHandlePool(); - return pool->allocate(ptr); -} - void Heap::protect(JSValue k) { ASSERT(k); @@ -269,14 +236,16 @@ void Heap::markRoots() JSONObject::markStringifiers(markStack, m_globalData->firstStringifierToMark); markStack.drain(); + m_handleHeap.markStrongHandles(markStack); + // Mark the small strings cache last, since it will clear itself if nothing // else has marked it. m_globalData->smallStrings.markChildren(markStack); markStack.drain(); markStack.compact(); - - updateWeakGCHandles(); + + m_handleHeap.updateAfterMark(); m_operationInProgress = NoOperation; } @@ -298,18 +267,17 @@ size_t Heap::capacity() const size_t Heap::globalObjectCount() { - return m_globalData->globalObjects.uncheckedSize(); + return m_globalData->globalObjectCount; } size_t Heap::protectedGlobalObjectCount() { - size_t count = 0; + size_t count = m_handleHeap.protectedGlobalObjectCount(); - GlobalObjectMap& map = m_globalData->globalObjects; - GlobalObjectMap::iterator end = map.uncheckedEnd(); - for (GlobalObjectMap::iterator it = map.uncheckedBegin(); it != end; ++it) { - if (map.isValid(it) && m_protectedValues.contains(it->second.get())) - ++count; + ProtectCountSet::iterator end = m_protectedValues.end(); + for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) { + if (it->first->isObject() && asObject(it->first)->isGlobalObject()) + count++; } return count; @@ -402,6 +370,10 @@ void Heap::reset(SweepToggle sweepToggle) m_markedSpace.reset(); m_extraCost = 0; +#if ENABLE(JSC_ZOMBIES) + sweep(); +#endif + if (sweepToggle == DoSweep) { m_markedSpace.sweep(); m_markedSpace.shrink(); diff --git a/Source/JavaScriptCore/runtime/Heap.h b/Source/JavaScriptCore/runtime/Heap.h index 6591a5b..eb8af70 100644 --- a/Source/JavaScriptCore/runtime/Heap.h +++ b/Source/JavaScriptCore/runtime/Heap.h @@ -22,9 +22,11 @@ #ifndef Heap_h #define Heap_h +#include "HandleHeap.h" #include "MarkStack.h" #include "MarkedSpace.h" #include +#include #include namespace JSC { @@ -34,7 +36,6 @@ namespace JSC { class JSCell; class JSGlobalData; class JSValue; - class JSValue; class LiveObjectIterator; class MarkStack; class MarkedArgumentBuffer; @@ -89,8 +90,6 @@ namespace JSC { PassOwnPtr protectedObjectTypeCounts(); PassOwnPtr objectTypeCounts(); - WeakGCHandle* addWeakGCHandle(JSCell*); - void pushTempSortVector(Vector*); void popTempSortVector(Vector*); @@ -100,21 +99,21 @@ namespace JSC { template void forEach(Functor&); + HandleSlot allocateGlobalHandle() { return m_handleHeap.allocate(); } + private: friend class JSGlobalData; static const size_t minExtraCost = 256; static const size_t maxExtraCost = 1024 * 1024; + void* allocateSlowCase(size_t); void reportExtraMemoryCostSlowCase(size_t); void markRoots(); void markProtectedObjects(MarkStack&); void markTempSortVectors(MarkStack&); - void updateWeakGCHandles(); - WeakGCHandlePool* weakGCHandlePool(size_t index); - enum SweepToggle { DoNotSweep, DoSweep }; void reset(SweepToggle); @@ -124,7 +123,6 @@ namespace JSC { MarkedSpace m_markedSpace; ProtectCountSet m_protectedValues; - Vector m_weakGCHandlePools; Vector* > m_tempSortingVectors; HashSet m_codeBlocks; @@ -136,6 +134,7 @@ namespace JSC { MachineStackMarker m_machineStackMarker; MarkStack m_markStack; + HandleHeap m_handleHeap; size_t m_extraCost; }; @@ -165,11 +164,6 @@ namespace JSC { if (cost > minExtraCost) reportExtraMemoryCostSlowCase(cost); } - - inline WeakGCHandlePool* Heap::weakGCHandlePool(size_t index) - { - return static_cast(m_weakGCHandlePools[index].base()); - } template inline void Heap::forEach(Functor& functor) { diff --git a/Source/JavaScriptCore/runtime/Identifier.cpp b/Source/JavaScriptCore/runtime/Identifier.cpp index 28cfd0a..3992418 100644 --- a/Source/JavaScriptCore/runtime/Identifier.cpp +++ b/Source/JavaScriptCore/runtime/Identifier.cpp @@ -23,6 +23,7 @@ #include "CallFrame.h" #include "NumericStrings.h" +#include "ScopeChain.h" #include // for placement new #include // for strlen #include diff --git a/Source/JavaScriptCore/runtime/InitializeThreading.cpp b/Source/JavaScriptCore/runtime/InitializeThreading.cpp index 27611b7..aef60c8 100644 --- a/Source/JavaScriptCore/runtime/InitializeThreading.cpp +++ b/Source/JavaScriptCore/runtime/InitializeThreading.cpp @@ -59,6 +59,7 @@ static void initializeThreadingOnce() s_dtoaP5Mutex = new Mutex; initializeDates(); RegisterFile::initializeThreading(); + Structure::initializeThreading(); #endif } diff --git a/Source/JavaScriptCore/runtime/InternalFunction.cpp b/Source/JavaScriptCore/runtime/InternalFunction.cpp index f19ae0d..27106a1 100644 --- a/Source/JavaScriptCore/runtime/InternalFunction.cpp +++ b/Source/JavaScriptCore/runtime/InternalFunction.cpp @@ -29,23 +29,23 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(InternalFunction); +// Ensure the compiler generates a vtable for InternalFunction! +void InternalFunction::vtableAnchor() {} -const ClassInfo InternalFunction::info = { "Function", 0, 0, 0 }; +ASSERT_CLASS_FITS_IN_CELL(InternalFunction); -const ClassInfo* InternalFunction::classInfo() const -{ - return &info; -} +const ClassInfo InternalFunction::s_info = { "Function", &JSObjectWithGlobalObject::s_info, 0, 0 }; InternalFunction::InternalFunction(NonNullPassRefPtr structure) : JSObjectWithGlobalObject(structure) { + ASSERT(inherits(&s_info)); } InternalFunction::InternalFunction(JSGlobalData* globalData, JSGlobalObject* globalObject, NonNullPassRefPtr structure, const Identifier& name) : JSObjectWithGlobalObject(globalObject, structure) { + ASSERT(inherits(&s_info)); putDirect(*globalData, globalData->propertyNames->name, jsString(globalData, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum); } diff --git a/Source/JavaScriptCore/runtime/InternalFunction.h b/Source/JavaScriptCore/runtime/InternalFunction.h index 401f17b..8427b8c 100644 --- a/Source/JavaScriptCore/runtime/InternalFunction.h +++ b/Source/JavaScriptCore/runtime/InternalFunction.h @@ -33,8 +33,7 @@ namespace JSC { class InternalFunction : public JSObjectWithGlobalObject { public: - virtual const ClassInfo* classInfo() const; - static JS_EXPORTDATA const ClassInfo info; + static JS_EXPORTDATA const ClassInfo s_info; const UString& name(ExecState*); const UString displayName(ExecState*); @@ -42,7 +41,7 @@ namespace JSC { static PassRefPtr createStructure(JSValue proto) { - return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: @@ -55,13 +54,15 @@ namespace JSC { private: virtual CallType getCallData(CallData&) = 0; + + virtual void vtableAnchor(); }; InternalFunction* asInternalFunction(JSValue); inline InternalFunction* asInternalFunction(JSValue value) { - ASSERT(asObject(value)->inherits(&InternalFunction::info)); + ASSERT(asObject(value)->inherits(&InternalFunction::s_info)); return static_cast(asObject(value)); } diff --git a/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h b/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h index a113e91..43dd0d3 100644 --- a/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h +++ b/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h @@ -37,7 +37,7 @@ namespace JSC { static PassRefPtr createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(CompoundType, OverridesMarkChildren | OverridesGetPropertyNames), AnonymousSlotCount); + return Structure::create(prototype, TypeInfo(CompoundType, OverridesMarkChildren | OverridesGetPropertyNames), AnonymousSlotCount, 0); } diff --git a/Source/JavaScriptCore/runtime/JSActivation.cpp b/Source/JavaScriptCore/runtime/JSActivation.cpp index 6fb5ced..eb9c7c1 100644 --- a/Source/JavaScriptCore/runtime/JSActivation.cpp +++ b/Source/JavaScriptCore/runtime/JSActivation.cpp @@ -37,11 +37,12 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(JSActivation); -const ClassInfo JSActivation::info = { "JSActivation", 0, 0, 0 }; +const ClassInfo JSActivation::s_info = { "JSActivation", &Base::s_info, 0, 0 }; JSActivation::JSActivation(CallFrame* callFrame, NonNullPassRefPtr functionExecutable) : Base(callFrame->globalData().activationStructure, new JSActivationData(functionExecutable, callFrame->registers())) { + ASSERT(inherits(&s_info)); } JSActivation::~JSActivation() @@ -54,19 +55,19 @@ void JSActivation::markChildren(MarkStack& markStack) Base::markChildren(markStack); // No need to mark our registers if they're still in the RegisterFile. - Register* registerArray = d()->registerArray.get(); + WriteBarrier* registerArray = d()->registerArray.get(); if (!registerArray) return; size_t numParametersMinusThis = d()->functionExecutable->parameterCount(); size_t count = numParametersMinusThis; - markStack.deprecatedAppendValues(registerArray, count); + markStack.appendValues(registerArray, count); size_t numVars = d()->functionExecutable->capturedVariableCount(); // Skip the call frame, which sits between the parameters and vars. - markStack.deprecatedAppendValues(registerArray + count + RegisterFile::CallFrameHeaderSize, numVars, MayContainNullValues); + markStack.appendValues(registerArray + count + RegisterFile::CallFrameHeaderSize, numVars, MayContainNullValues); } inline bool JSActivation::symbolTableGet(const Identifier& propertyName, PropertySlot& slot) @@ -74,13 +75,13 @@ inline bool JSActivation::symbolTableGet(const Identifier& propertyName, Propert SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl()); if (!entry.isNull()) { ASSERT(entry.getIndex() < static_cast(d()->functionExecutable->capturedVariableCount())); - slot.setRegisterSlot(®isterAt(entry.getIndex())); + slot.setValue(registerAt(entry.getIndex()).get()); return true; } return false; } -inline bool JSActivation::symbolTablePut(const Identifier& propertyName, JSValue value) +inline bool JSActivation::symbolTablePut(JSGlobalData& globalData, const Identifier& propertyName, JSValue value) { ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); @@ -90,7 +91,7 @@ inline bool JSActivation::symbolTablePut(const Identifier& propertyName, JSValue if (entry.isReadOnly()) return true; ASSERT(entry.getIndex() < static_cast(d()->functionExecutable->capturedVariableCount())); - registerAt(entry.getIndex()) = value; + registerAt(entry.getIndex()).set(globalData, this, value); return true; } @@ -106,7 +107,7 @@ void JSActivation::getOwnPropertyNames(ExecState* exec, PropertyNameArray& prope JSObject::getOwnPropertyNames(exec, propertyNames, mode); } -inline bool JSActivation::symbolTablePutWithAttributes(const Identifier& propertyName, JSValue value, unsigned attributes) +inline bool JSActivation::symbolTablePutWithAttributes(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes) { ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); @@ -118,7 +119,7 @@ inline bool JSActivation::symbolTablePutWithAttributes(const Identifier& propert if (entry.getIndex() >= static_cast(d()->functionExecutable->capturedVariableCount())) return false; entry.setAttributes(attributes); - registerAt(entry.getIndex()) = value; + registerAt(entry.getIndex()).set(globalData, this, value); return true; } @@ -148,7 +149,7 @@ void JSActivation::put(ExecState* exec, const Identifier& propertyName, JSValue { ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); - if (symbolTablePut(propertyName, value)) + if (symbolTablePut(exec->globalData(), propertyName, value)) return; // We don't call through to JSObject because __proto__ and getter/setter @@ -163,7 +164,7 @@ void JSActivation::putWithAttributes(ExecState* exec, const Identifier& property { ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); - if (symbolTablePutWithAttributes(propertyName, value, attributes)) + if (symbolTablePutWithAttributes(exec->globalData(), propertyName, value, attributes)) return; // We don't call through to JSObject because __proto__ and getter/setter @@ -201,7 +202,7 @@ bool JSActivation::isDynamicScope(bool& requiresDynamicChecks) const JSValue JSActivation::argumentsGetter(ExecState*, JSValue slotBase, const Identifier&) { JSActivation* activation = asActivation(slotBase); - CallFrame* callFrame = CallFrame::create(activation->d()->registers); + CallFrame* callFrame = CallFrame::create(reinterpret_cast(activation->d()->registers)); int argumentsRegister = activation->d()->functionExecutable->generatedBytecode().argumentsRegister(); if (JSValue arguments = callFrame->uncheckedR(argumentsRegister).jsValue()) return arguments; @@ -211,7 +212,7 @@ JSValue JSActivation::argumentsGetter(ExecState*, JSValue slotBase, const Identi callFrame->uncheckedR(argumentsRegister) = arguments; callFrame->uncheckedR(realArgumentsRegister) = arguments; - ASSERT(callFrame->uncheckedR(realArgumentsRegister).jsValue().inherits(&Arguments::info)); + ASSERT(callFrame->uncheckedR(realArgumentsRegister).jsValue().inherits(&Arguments::s_info)); return callFrame->uncheckedR(realArgumentsRegister).jsValue(); } diff --git a/Source/JavaScriptCore/runtime/JSActivation.h b/Source/JavaScriptCore/runtime/JSActivation.h index 6dd6d70..6e04041 100644 --- a/Source/JavaScriptCore/runtime/JSActivation.h +++ b/Source/JavaScriptCore/runtime/JSActivation.h @@ -62,12 +62,11 @@ namespace JSC { virtual JSObject* toThisObject(ExecState*) const; virtual JSValue toStrictThisObject(ExecState*) const; - void copyRegisters(); + void copyRegisters(JSGlobalData&); - virtual const ClassInfo* classInfo() const { return &info; } - static const ClassInfo info; + static const ClassInfo s_info; - static PassRefPtr createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); } + static PassRefPtr createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: static const unsigned StructureFlags = OverridesGetOwnPropertySlot | NeedsThisConversion | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags; @@ -93,8 +92,8 @@ namespace JSC { bool symbolTableGet(const Identifier&, PropertySlot&); bool symbolTableGet(const Identifier&, PropertyDescriptor&); bool symbolTableGet(const Identifier&, PropertySlot&, bool& slotIsWriteable); - bool symbolTablePut(const Identifier&, JSValue); - bool symbolTablePutWithAttributes(const Identifier&, JSValue, unsigned attributes); + bool symbolTablePut(JSGlobalData&, const Identifier&, JSValue); + bool symbolTablePutWithAttributes(JSGlobalData&, const Identifier&, JSValue, unsigned attributes); static JSValue argumentsGetter(ExecState*, JSValue, const Identifier&); NEVER_INLINE PropertySlot::GetValueFunc getArgumentsGetter(); @@ -106,7 +105,7 @@ namespace JSC { inline JSActivation* asActivation(JSValue value) { - ASSERT(asObject(value)->inherits(&JSActivation::info)); + ASSERT(asObject(value)->inherits(&JSActivation::s_info)); return static_cast(asObject(value)); } diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp index ded6d87..822b84c 100644 --- a/Source/JavaScriptCore/runtime/JSArray.cpp +++ b/Source/JavaScriptCore/runtime/JSArray.cpp @@ -92,7 +92,7 @@ ASSERT_CLASS_FITS_IN_CELL(JSArray); // as long as it is 1/8 full. If more sparse than that, we use a map. static const unsigned minDensityMultiplier = 8; -const ClassInfo JSArray::info = {"Array", 0, 0, 0}; +const ClassInfo JSArray::s_info = {"Array", &JSNonFinalObject::s_info, 0, 0}; // We keep track of the size of the last array after it was grown. We use this // as a simple heuristic for as the value to grow the next array from size 0. @@ -127,8 +127,10 @@ inline void JSArray::checkConsistency(ConsistencyCheckType) #endif JSArray::JSArray(VPtrStealingHackType) - : JSObject(createStructure(jsNull())) + : JSNonFinalObject(createStructure(jsNull())) { + ASSERT(inherits(&s_info)); + unsigned initialCapacity = 0; m_storage = static_cast(fastZeroedMalloc(storageSize(initialCapacity))); @@ -144,8 +146,10 @@ JSArray::JSArray(VPtrStealingHackType) } JSArray::JSArray(NonNullPassRefPtr structure) - : JSObject(structure) + : JSNonFinalObject(structure) { + ASSERT(inherits(&s_info)); + unsigned initialCapacity = 0; m_storage = static_cast(fastZeroedMalloc(storageSize(initialCapacity))); @@ -159,8 +163,10 @@ JSArray::JSArray(NonNullPassRefPtr structure) } JSArray::JSArray(NonNullPassRefPtr structure, unsigned initialLength, ArrayCreationMode creationMode) - : JSObject(structure) + : JSNonFinalObject(structure) { + ASSERT(inherits(&s_info)); + unsigned initialCapacity; if (creationMode == CreateCompact) initialCapacity = initialLength; @@ -199,8 +205,10 @@ JSArray::JSArray(NonNullPassRefPtr structure, unsigned initialLength, } JSArray::JSArray(JSGlobalData& globalData, NonNullPassRefPtr structure, const ArgList& list) - : JSObject(structure) + : JSNonFinalObject(structure) { + ASSERT(inherits(&s_info)); + unsigned initialCapacity = list.size(); unsigned initialStorage; diff --git a/Source/JavaScriptCore/runtime/JSArray.h b/Source/JavaScriptCore/runtime/JSArray.h index b5caa47..ede3c61 100644 --- a/Source/JavaScriptCore/runtime/JSArray.h +++ b/Source/JavaScriptCore/runtime/JSArray.h @@ -57,7 +57,7 @@ namespace JSC { enum ArrayCreationMode { CreateCompact, CreateInitialized }; - class JSArray : public JSObject { + class JSArray : public JSNonFinalObject { friend class JIT; friend class Walker; @@ -75,7 +75,7 @@ namespace JSC { virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); virtual void put(ExecState*, unsigned propertyName, JSValue); // FIXME: Make protected and add setItem. - static JS_EXPORTDATA const ClassInfo info; + static JS_EXPORTDATA const ClassInfo s_info; unsigned length() const { return m_storage->m_length; } void setLength(unsigned); // OK to use on new arrays, but not if it might be a RegExpMatchArray. @@ -127,7 +127,7 @@ namespace JSC { static PassRefPtr createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } inline void markChildrenDirect(MarkStack& markStack); @@ -144,8 +144,6 @@ namespace JSC { void setSubclassData(void*); private: - virtual const ClassInfo* classInfo() const { return &info; } - bool getOwnPropertySlotSlowCase(ExecState*, unsigned propertyName, PropertySlot&); void putSlowCase(ExecState*, unsigned propertyName, JSValue); @@ -167,7 +165,7 @@ namespace JSC { inline JSArray* asArray(JSCell* cell) { - ASSERT(cell->inherits(&JSArray::info)); + ASSERT(cell->inherits(&JSArray::s_info)); return static_cast(cell); } diff --git a/Source/JavaScriptCore/runtime/JSByteArray.cpp b/Source/JavaScriptCore/runtime/JSByteArray.cpp index 3f7d806..ae735dc 100644 --- a/Source/JavaScriptCore/runtime/JSByteArray.cpp +++ b/Source/JavaScriptCore/runtime/JSByteArray.cpp @@ -33,12 +33,11 @@ using namespace WTF; namespace JSC { -const ClassInfo JSByteArray::s_defaultInfo = { "ByteArray", 0, 0, 0 }; +const ClassInfo JSByteArray::s_defaultInfo = { "ByteArray", &Base::s_info, 0, 0 }; -JSByteArray::JSByteArray(ExecState* exec, NonNullPassRefPtr structure, ByteArray* storage, const JSC::ClassInfo* classInfo) - : JSObject(structure) +JSByteArray::JSByteArray(ExecState* exec, NonNullPassRefPtr structure, ByteArray* storage) + : JSNonFinalObject(structure) , m_storage(storage) - , m_classInfo(classInfo) { putDirect(exec->globalData(), exec->globalData().propertyNames->length, jsNumber(m_storage->length()), ReadOnly | DontDelete); } @@ -51,10 +50,9 @@ JSByteArray::~JSByteArray() #endif -PassRefPtr JSByteArray::createStructure(JSValue prototype) +PassRefPtr JSByteArray::createStructure(JSValue prototype, const JSC::ClassInfo* classInfo) { - PassRefPtr result = Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); - return result; + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, classInfo); } bool JSByteArray::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) diff --git a/Source/JavaScriptCore/runtime/JSByteArray.h b/Source/JavaScriptCore/runtime/JSByteArray.h index 44bae2d..6e91594 100644 --- a/Source/JavaScriptCore/runtime/JSByteArray.h +++ b/Source/JavaScriptCore/runtime/JSByteArray.h @@ -32,9 +32,11 @@ namespace JSC { - class JSByteArray : public JSObject { + class JSByteArray : public JSNonFinalObject { friend class JSGlobalData; public: + typedef JSNonFinalObject Base; + bool canAccessIndex(unsigned i) { return i < m_storage->length(); } JSValue getIndex(ExecState*, unsigned i) { @@ -45,18 +47,25 @@ namespace JSC { void setIndex(unsigned i, int value) { ASSERT(canAccessIndex(i)); + if (value & ~0xFF) { + if (value < 0) + value = 0; + else + value = 255; + } m_storage->data()[i] = static_cast(value); } - + void setIndex(unsigned i, double value) { ASSERT(canAccessIndex(i)); - // The largest integer value that a double can represent without loss of precision - // is 2^53. long long is the smallest integral type that gives correct results - // when casting numbers larger than 2^31 from a value of type double. - m_storage->data()[i] = static_cast(static_cast(value)); + if (!(value > 0)) // Clamp NaN to 0 + value = 0; + else if (value > 255) + value = 255; + m_storage->data()[i] = static_cast(value + 0.5); } - + void setIndex(ExecState* exec, unsigned i, JSValue value) { double byteValue = value.toNumber(exec); @@ -66,8 +75,8 @@ namespace JSC { setIndex(i, byteValue); } - JSByteArray(ExecState* exec, NonNullPassRefPtr, WTF::ByteArray* storage, const JSC::ClassInfo* = &s_defaultInfo); - static PassRefPtr createStructure(JSValue prototype); + JSByteArray(ExecState*, NonNullPassRefPtr, WTF::ByteArray* storage); + static PassRefPtr createStructure(JSValue prototype, const JSC::ClassInfo* = &s_defaultInfo); virtual bool getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot&); virtual bool getOwnPropertySlot(JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&); @@ -77,9 +86,8 @@ namespace JSC { virtual void getOwnPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties); - virtual const ClassInfo* classInfo() const { return m_classInfo; } static const ClassInfo s_defaultInfo; - + size_t length() const { return m_storage->length(); } WTF::ByteArray* storage() const { return m_storage.get(); } @@ -94,15 +102,13 @@ namespace JSC { private: enum VPtrStealingHackType { VPtrStealingHack }; JSByteArray(VPtrStealingHackType) - : JSObject(createStructure(jsNull())) - , m_classInfo(0) + : JSNonFinalObject(createStructure(jsNull())) { } RefPtr m_storage; - const ClassInfo* m_classInfo; }; - + JSByteArray* asByteArray(JSValue value); inline JSByteArray* asByteArray(JSValue value) { diff --git a/Source/JavaScriptCore/runtime/JSCell.cpp b/Source/JavaScriptCore/runtime/JSCell.cpp index 0cc1ab1..9acb777 100644 --- a/Source/JavaScriptCore/runtime/JSCell.cpp +++ b/Source/JavaScriptCore/runtime/JSCell.cpp @@ -163,11 +163,6 @@ JSObject* JSCell::toThisObject(ExecState* exec) const return toObject(exec); } -const ClassInfo* JSCell::classInfo() const -{ - return 0; -} - JSValue JSCell::getJSNumber() { return JSValue(); diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h index 66f6197..7313d52 100644 --- a/Source/JavaScriptCore/runtime/JSCell.h +++ b/Source/JavaScriptCore/runtime/JSCell.h @@ -27,6 +27,7 @@ #include "ConstructData.h" #include "Heap.h" #include "JSImmediate.h" +#include "JSLock.h" #include "JSValue.h" #include "MarkStack.h" #include "Structure.h" @@ -65,6 +66,7 @@ namespace JSC { friend class JSGlobalData; friend class MarkedSpace; friend class MarkedBlock; + friend class ScopeChainNode; private: explicit JSCell(Structure*); @@ -73,7 +75,7 @@ namespace JSC { public: static PassRefPtr createDummyStructure() { - return Structure::create(jsNull(), TypeInfo(UnspecifiedType), AnonymousSlotCount); + return Structure::create(jsNull(), TypeInfo(UnspecifiedType), AnonymousSlotCount, 0); } // Querying the type. @@ -118,7 +120,7 @@ namespace JSC { #endif // Object operations, with the toObject operation included. - virtual const ClassInfo* classInfo() const; + const ClassInfo* classInfo() const { return m_structure->classInfo(); } virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); virtual void put(ExecState*, unsigned propertyName, JSValue); virtual bool deleteProperty(ExecState*, const Identifier& propertyName); @@ -174,16 +176,6 @@ namespace JSC { { } - inline void* JSCell::operator new(size_t size, JSGlobalData* globalData) - { - return globalData->heap.allocate(size); - } - - inline void* JSCell::operator new(size_t size, ExecState* exec) - { - return exec->heap()->allocate(size); - } - // --- JSValue inlines ---------------------------- inline bool JSValue::isString() const @@ -402,21 +394,59 @@ namespace JSC { } #endif - inline void* MarkedBlock::allocate(size_t& nextCell) + inline void* MarkedBlock::allocate() { - do { - ASSERT(nextCell < CELLS_PER_BLOCK); - if (!marked.testAndSet(nextCell)) { // Always false for the last cell in the block - JSCell* cell = reinterpret_cast(&cells[nextCell++]); + while (m_nextAtom < m_endAtom) { + if (!m_marks.testAndSet(m_nextAtom)) { + JSCell* cell = reinterpret_cast(&atoms()[m_nextAtom]); + m_nextAtom += m_atomsPerCell; cell->~JSCell(); return cell; } - nextCell = marked.nextPossiblyUnset(nextCell); - } while (nextCell != CELLS_PER_BLOCK); - - nextCell = 0; + m_nextAtom += m_atomsPerCell; + } + return 0; } + + inline MarkedSpace::SizeClass& MarkedSpace::sizeClassFor(size_t bytes) + { + ASSERT(bytes && bytes <= preciseCutoff); + return m_preciseSizeClasses[(bytes - 1) / preciseStep]; + } + + inline void* MarkedSpace::allocate(size_t bytes) + { + SizeClass& sizeClass = sizeClassFor(bytes); + return allocateFromSizeClass(sizeClass); + } + + inline void* Heap::allocate(size_t bytes) + { + ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable()); + ASSERT(JSLock::lockCount() > 0); + ASSERT(JSLock::currentThreadIsHoldingLock()); + ASSERT(bytes <= MarkedSpace::maxCellSize); + ASSERT(m_operationInProgress == NoOperation); + + m_operationInProgress = Allocation; + void* result = m_markedSpace.allocate(bytes); + m_operationInProgress = NoOperation; + if (result) + return result; + + return allocateSlowCase(bytes); + } + + inline void* JSCell::operator new(size_t size, JSGlobalData* globalData) + { + return globalData->heap.allocate(size); + } + + inline void* JSCell::operator new(size_t size, ExecState* exec) + { + return exec->heap()->allocate(size); + } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSChunk.cpp b/Source/JavaScriptCore/runtime/JSChunk.cpp new file mode 100644 index 0000000..f064de8 --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSChunk.cpp @@ -0,0 +1,28 @@ +/* + * 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 "JSChunk.h" + diff --git a/Source/JavaScriptCore/runtime/JSChunk.h b/Source/JavaScriptCore/runtime/JSChunk.h new file mode 100644 index 0000000..bae2bc7 --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSChunk.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef JSChunk_h +#define JSChunk_h + + + +#endif // JSChunk_h diff --git a/Source/JavaScriptCore/runtime/JSFunction.cpp b/Source/JavaScriptCore/runtime/JSFunction.cpp index c569722..2ade441 100644 --- a/Source/JavaScriptCore/runtime/JSFunction.cpp +++ b/Source/JavaScriptCore/runtime/JSFunction.cpp @@ -42,16 +42,14 @@ using namespace WTF; using namespace Unicode; namespace JSC { -#if ENABLE(JIT) EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState* exec) { return throwVMError(exec, createNotAConstructorError(exec, exec->callee())); } -#endif ASSERT_CLASS_FITS_IN_CELL(JSFunction); -const ClassInfo JSFunction::info = { "Function", 0, 0, 0 }; +const ClassInfo JSFunction::s_info = { "Function", &Base::s_info, 0, 0 }; bool JSFunction::isHostFunctionNonInline() const { @@ -61,43 +59,36 @@ bool JSFunction::isHostFunctionNonInline() const JSFunction::JSFunction(NonNullPassRefPtr structure) : Base(structure) , m_executable(adoptRef(new VPtrHackExecutable())) - , m_scopeChain(NoScopeChain()) { + ASSERT(inherits(&s_info)); } -#if ENABLE(JIT) JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure, int length, const Identifier& name, PassRefPtr thunk) : Base(globalObject, structure) , m_executable(thunk) - , m_scopeChain(globalObject->globalScopeChain()) + , m_scopeChain(exec->globalData(), this, globalObject->globalScopeChain()) { + ASSERT(inherits(&s_info)); putDirect(exec->globalData(), exec->globalData().propertyNames->name, jsString(exec, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum); putDirect(exec->globalData(), exec->propertyNames().length, jsNumber(length), DontDelete | ReadOnly | DontEnum); } -#endif JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure, int length, const Identifier& name, NativeFunction func) : Base(globalObject, structure) -#if ENABLE(JIT) , m_executable(exec->globalData().getHostFunction(func)) -#endif - , m_scopeChain(globalObject->globalScopeChain()) + , m_scopeChain(exec->globalData(), this, globalObject->globalScopeChain()) { + ASSERT(inherits(&s_info)); putDirect(exec->globalData(), exec->globalData().propertyNames->name, jsString(exec, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum); -#if ENABLE(JIT) putDirect(exec->globalData(), exec->propertyNames().length, jsNumber(length), DontDelete | ReadOnly | DontEnum); -#else - UNUSED_PARAM(length); - UNUSED_PARAM(func); - ASSERT_NOT_REACHED(); -#endif } JSFunction::JSFunction(ExecState* exec, NonNullPassRefPtr executable, ScopeChainNode* scopeChainNode) - : Base(scopeChainNode->globalObject, scopeChainNode->globalObject->functionStructure()) + : Base(scopeChainNode->globalObject.get(), scopeChainNode->globalObject->functionStructure()) , m_executable(executable) - , m_scopeChain(scopeChainNode) + , m_scopeChain(exec->globalData(), this, scopeChainNode) { + ASSERT(inherits(&s_info)); const Identifier& name = static_cast(m_executable.get())->name(); putDirect(exec->globalData(), exec->globalData().propertyNames->name, jsString(exec, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum); } @@ -159,20 +150,18 @@ void JSFunction::markChildren(MarkStack& markStack) Base::markChildren(markStack); if (!isHostFunction()) { jsExecutable()->markAggregate(markStack); - scope().markAggregate(markStack); + markStack.append(&m_scopeChain); } } CallType JSFunction::getCallData(CallData& callData) { -#if ENABLE(JIT) if (isHostFunction()) { callData.native.function = nativeFunction(); return CallTypeHost; } -#endif callData.js.functionExecutable = jsExecutable(); - callData.js.scopeChain = scope().node(); + callData.js.scopeChain = scope(); return CallTypeJS; } @@ -206,7 +195,7 @@ bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyN WriteBarrierBase* location = getDirectLocation(propertyName); if (!location) { - JSObject* prototype = new (exec) JSObject(scope().globalObject()->emptyObjectStructure()); + JSObject* prototype = constructEmptyObject(exec, scope()->globalObject->emptyObjectStructure()); prototype->putDirect(exec->globalData(), exec->propertyNames().constructor, this, DontEnum); putDirect(exec->globalData(), exec->propertyNames().prototype, prototype, DontDelete | DontEnum); location = getDirectLocation(propertyName); @@ -336,7 +325,7 @@ ConstructType JSFunction::getConstructData(ConstructData& constructData) if (isHostFunction()) return ConstructTypeNone; constructData.js.functionExecutable = jsExecutable(); - constructData.js.scopeChain = scope().node(); + constructData.js.scopeChain = scope(); return ConstructTypeJS; } diff --git a/Source/JavaScriptCore/runtime/JSFunction.h b/Source/JavaScriptCore/runtime/JSFunction.h index 3a2fe30..089f42e 100644 --- a/Source/JavaScriptCore/runtime/JSFunction.h +++ b/Source/JavaScriptCore/runtime/JSFunction.h @@ -45,9 +45,7 @@ namespace JSC { public: JSFunction(ExecState*, JSGlobalObject*, NonNullPassRefPtr, int length, const Identifier&, NativeFunction); -#if ENABLE(JIT) JSFunction(ExecState*, JSGlobalObject*, NonNullPassRefPtr, int length, const Identifier&, PassRefPtr); -#endif JSFunction(ExecState*, NonNullPassRefPtr, ScopeChainNode*); virtual ~JSFunction(); @@ -55,15 +53,15 @@ namespace JSC { const UString displayName(ExecState*); const UString calculatedDisplayName(ExecState*); - ScopeChain& scope() + ScopeChainNode* scope() { ASSERT(!isHostFunctionNonInline()); - return m_scopeChain; + return m_scopeChain.get(); } - void setScope(const ScopeChain& scopeChain) + void setScope(JSGlobalData& globalData, ScopeChainNode* scopeChain) { ASSERT(!isHostFunctionNonInline()); - m_scopeChain = scopeChain; + m_scopeChain.set(globalData, this, scopeChain); } ExecutableBase* executable() const { return m_executable.get(); } @@ -72,11 +70,11 @@ namespace JSC { inline bool isHostFunction() const; FunctionExecutable* jsExecutable() const; - static JS_EXPORTDATA const ClassInfo info; + static JS_EXPORTDATA const ClassInfo s_info; static PassRefPtr createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } NativeFunction nativeFunction(); @@ -100,21 +98,19 @@ namespace JSC { virtual void markChildren(MarkStack&); - virtual const ClassInfo* classInfo() const { return &info; } - static JSValue argumentsGetter(ExecState*, JSValue, const Identifier&); static JSValue callerGetter(ExecState*, JSValue, const Identifier&); static JSValue lengthGetter(ExecState*, JSValue, const Identifier&); RefPtr m_executable; - ScopeChain m_scopeChain; + WriteBarrier m_scopeChain; }; JSFunction* asFunction(JSValue); inline JSFunction* asFunction(JSValue value) { - ASSERT(asObject(value)->inherits(&JSFunction::info)); + ASSERT(asObject(value)->inherits(&JSFunction::s_info)); return static_cast(asObject(value)); } diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/Source/JavaScriptCore/runtime/JSGlobalData.cpp index ff88048..e25040c 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalData.cpp @@ -75,6 +75,7 @@ extern JSC_CONST_HASHTABLE HashTable jsonTable; extern JSC_CONST_HASHTABLE HashTable dateTable; extern JSC_CONST_HASHTABLE HashTable mathTable; extern JSC_CONST_HASHTABLE HashTable numberTable; +extern JSC_CONST_HASHTABLE HashTable objectConstructorTable; extern JSC_CONST_HASHTABLE HashTable regExpTable; extern JSC_CONST_HASHTABLE HashTable regExpConstructorTable; extern JSC_CONST_HASHTABLE HashTable stringTable; @@ -119,12 +120,13 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread , jsonTable(fastNew(JSC::jsonTable)) , mathTable(fastNew(JSC::mathTable)) , numberTable(fastNew(JSC::numberTable)) + , objectConstructorTable(fastNew(JSC::objectConstructorTable)) , regExpTable(fastNew(JSC::regExpTable)) , regExpConstructorTable(fastNew(JSC::regExpConstructorTable)) , stringTable(fastNew(JSC::stringTable)) , activationStructure(JSActivation::createStructure(jsNull())) - , interruptedExecutionErrorStructure(JSObject::createStructure(jsNull())) - , terminatedExecutionErrorStructure(JSObject::createStructure(jsNull())) + , interruptedExecutionErrorStructure(JSNonFinalObject::createStructure(jsNull())) + , terminatedExecutionErrorStructure(JSNonFinalObject::createStructure(jsNull())) , staticScopeStructure(JSStaticScopeObject::createStructure(jsNull())) , strictEvalActivationStructure(StrictEvalActivation::createStructure(jsNull())) , stringStructure(JSString::createStructure(jsNull())) @@ -132,14 +134,16 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread , propertyNameIteratorStructure(JSPropertyNameIterator::createStructure(jsNull())) , getterSetterStructure(GetterSetter::createStructure(jsNull())) , apiWrapperStructure(JSAPIValueWrapper::createStructure(jsNull())) + , scopeChainNodeStructure(ScopeChainNode::createStructure(jsNull())) , dummyMarkableCellStructure(JSCell::createDummyStructure()) , identifierTable(globalDataType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable()) , propertyNames(new CommonIdentifiers(this)) , emptyList(new MarkedArgumentBuffer) , lexer(new Lexer(this)) , parser(new Parser) - , interpreter(new Interpreter) + , interpreter(0) , heap(this) + , globalObjectCount(0) , dynamicGlobalObject(0) , firstStringifierToMark(0) , cachedUTCOffset(NaN) @@ -152,6 +156,7 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread , exclusiveThread(0) #endif { + interpreter = new Interpreter(*this); if (globalDataType == Default) m_stack = wtfThreadData().stack(); @@ -159,7 +164,7 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread startProfilerServerIfNeeded(); #endif #if ENABLE(JIT) && ENABLE(INTERPRETER) -#if PLATFORM(CF) +#if USE(CF) CFStringRef canUseJITKey = CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman); CFBooleanRef canUseJIT = (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication); if (canUseJIT) { @@ -201,6 +206,7 @@ JSGlobalData::~JSGlobalData() jsonTable->deleteTable(); mathTable->deleteTable(); numberTable->deleteTable(); + objectConstructorTable->deleteTable(); regExpTable->deleteTable(); regExpConstructorTable->deleteTable(); stringTable->deleteTable(); @@ -210,6 +216,7 @@ JSGlobalData::~JSGlobalData() fastDelete(const_cast(jsonTable)); fastDelete(const_cast(mathTable)); fastDelete(const_cast(numberTable)); + fastDelete(const_cast(objectConstructorTable)); fastDelete(const_cast(regExpTable)); fastDelete(const_cast(regExpConstructorTable)); fastDelete(const_cast(stringTable)); @@ -283,6 +290,11 @@ PassRefPtr JSGlobalData::getHostFunction(NativeFunction functi { return jitStubs->hostFunctionStub(this, function, generator); } +#else +PassRefPtr JSGlobalData::getHostFunction(NativeFunction function) +{ + return NativeExecutable::create(function, callHostFunctionAsConstructor); +} #endif JSGlobalData::ClientData::~ClientData() @@ -320,7 +332,7 @@ public: inline void Recompiler::operator()(JSCell* cell) { - if (!cell->inherits(&JSFunction::info)) + if (!cell->inherits(&JSFunction::s_info)) return; JSFunction* function = asFunction(cell); if (function->executable()->isHostFunction()) diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.h b/Source/JavaScriptCore/runtime/JSGlobalData.h index 7b69055..ee3e067 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.h +++ b/Source/JavaScriptCore/runtime/JSGlobalData.h @@ -39,7 +39,6 @@ #include "SmallStrings.h" #include "Terminator.h" #include "TimeoutChecker.h" -#include "WeakGCMap.h" #include "WeakRandom.h" #include #include @@ -63,6 +62,7 @@ namespace JSC { class JSGlobalObject; class JSObject; class Lexer; + class NativeExecutable; class Parser; class RegExpCache; class Stringifier; @@ -75,8 +75,6 @@ namespace JSC { struct HashTable; struct Instruction; - typedef WeakGCMap GlobalObjectMap; // FIXME: Would be nice to use a WeakGCSet here. - struct DSTOffsetCache { DSTOffsetCache() { @@ -141,6 +139,7 @@ namespace JSC { const HashTable* jsonTable; const HashTable* mathTable; const HashTable* numberTable; + const HashTable* objectConstructorTable; const HashTable* regExpTable; const HashTable* regExpConstructorTable; const HashTable* stringTable; @@ -155,6 +154,7 @@ namespace JSC { RefPtr propertyNameIteratorStructure; RefPtr getterSetterStructure; RefPtr apiWrapperStructure; + RefPtr scopeChainNodeStructure; RefPtr dummyMarkableCellStructure; static void storeVPtrs(); @@ -199,9 +199,10 @@ namespace JSC { { return jitStubs->ctiStub(this, generator); } - PassRefPtr getHostFunction(NativeFunction function); - PassRefPtr getHostFunction(NativeFunction function, ThunkGenerator generator); + PassRefPtr getHostFunction(NativeFunction, ThunkGenerator); #endif + PassRefPtr getHostFunction(NativeFunction); + TimeoutChecker timeoutChecker; Terminator terminator; Heap heap; @@ -213,7 +214,7 @@ namespace JSC { HashMap opaqueJSClassData; - GlobalObjectMap globalObjects; + unsigned globalObjectCount; JSGlobalObject* dynamicGlobalObject; HashSet stringRecursionCheckVisitedObjects; @@ -253,6 +254,8 @@ namespace JSC { void addRegExpToTrace(PassRefPtr regExp); #endif void dumpRegExpTrace(); + HandleSlot allocateGlobalHandle() { return heap.allocateGlobalHandle(); } + private: JSGlobalData(GlobalDataType, ThreadStackType); static JSGlobalData*& sharedInstanceInternal(); diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp index f303196..28fc07d 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -46,7 +46,6 @@ #include "ErrorPrototype.h" #include "FunctionConstructor.h" #include "FunctionPrototype.h" -#include "GlobalEvalFunction.h" #include "JSFunction.h" #include "JSGlobalObjectFunctions.h" #include "JSLock.h" @@ -60,7 +59,6 @@ #include "ObjectConstructor.h" #include "ObjectPrototype.h" #include "Profiler.h" -#include "PrototypeFunction.h" #include "RegExpConstructor.h" #include "RegExpMatchesArray.h" #include "RegExpObject.h" @@ -104,11 +102,6 @@ JSGlobalObject::~JSGlobalObject() (*profiler)->stopProfiling(globalExec(), UString()); } - d()->globalData->globalObjects.take(this); - - RegisterFile& registerFile = globalData().interpreter->registerFile(); - if (registerFile.clearGlobalObject(this)) - registerFile.setNumGlobals(0); d()->destructor(d()); } @@ -119,10 +112,9 @@ void JSGlobalObject::init(JSObject* thisValue) structure()->disableSpecificFunctionTracking(); d()->globalData = Heap::heap(this)->globalData(); - d()->globalData->globalObjects.set(this, this); - d()->globalScopeChain = ScopeChain(this, d()->globalData.get(), this, thisValue); + d()->globalScopeChain.set(*d()->globalData, this, new (d()->globalData.get()) ScopeChainNode(0, this, d()->globalData.get(), this, thisValue)); - JSGlobalObject::globalExec()->init(0, 0, d()->globalScopeChain.node(), CallFrame::noCaller(), 0, 0); + JSGlobalObject::globalExec()->init(0, 0, d()->globalScopeChain.get(), CallFrame::noCaller(), 0, 0); d()->debugger = 0; @@ -135,7 +127,7 @@ void JSGlobalObject::put(ExecState* exec, const Identifier& propertyName, JSValu { ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); - if (symbolTablePut(propertyName, value)) + if (symbolTablePut(exec->globalData(), propertyName, value)) return; JSVariableObject::put(exec, propertyName, value, slot); } @@ -144,7 +136,7 @@ void JSGlobalObject::putWithAttributes(ExecState* exec, const Identifier& proper { ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); - if (symbolTablePutWithAttributes(propertyName, value, attributes)) + if (symbolTablePutWithAttributes(exec->globalData(), propertyName, value, attributes)) return; JSValue valueBefore = getDirect(propertyName); @@ -186,19 +178,18 @@ void JSGlobalObject::reset(JSValue prototype) // Prototypes d()->functionPrototype.set(exec->globalData(), this, new (exec) FunctionPrototype(exec, this, FunctionPrototype::createStructure(jsNull()))); // The real prototype will be set once ObjectPrototype is created. - d()->prototypeFunctionStructure = PrototypeFunction::createStructure(d()->functionPrototype.get()); + d()->functionStructure = JSFunction::createStructure(d()->functionPrototype.get()); d()->internalFunctionStructure = InternalFunction::createStructure(d()->functionPrototype.get()); - NativeFunctionWrapper* callFunction = 0; - NativeFunctionWrapper* applyFunction = 0; - d()->functionPrototype->addFunctionProperties(exec, this, d()->prototypeFunctionStructure.get(), &callFunction, &applyFunction); + JSFunction* callFunction = 0; + JSFunction* applyFunction = 0; + d()->functionPrototype->addFunctionProperties(exec, this, d()->functionStructure.get(), &callFunction, &applyFunction); d()->callFunction.set(exec->globalData(), this, callFunction); d()->applyFunction.set(exec->globalData(), this, applyFunction); - d()->objectPrototype.set(exec->globalData(), this, new (exec) ObjectPrototype(exec, this, ObjectPrototype::createStructure(jsNull()), d()->prototypeFunctionStructure.get())); + d()->objectPrototype.set(exec->globalData(), this, new (exec) ObjectPrototype(exec, this, ObjectPrototype::createStructure(jsNull()), d()->functionStructure.get())); d()->functionPrototype->structure()->setPrototypeWithoutTransition(d()->objectPrototype.get()); d()->emptyObjectStructure = d()->objectPrototype->inheritorID(); - d()->functionStructure = JSFunction::createStructure(d()->functionPrototype.get()); d()->callbackFunctionStructure = JSCallbackFunction::createStructure(d()->functionPrototype.get()); d()->argumentsStructure = Arguments::createStructure(d()->objectPrototype.get()); d()->callbackConstructorStructure = JSCallbackConstructor::createStructure(d()->objectPrototype.get()); @@ -211,32 +202,32 @@ void JSGlobalObject::reset(JSValue prototype) d()->stringPrototype.set(exec->globalData(), this, new (exec) StringPrototype(exec, this, StringPrototype::createStructure(d()->objectPrototype.get()))); d()->stringObjectStructure = StringObject::createStructure(d()->stringPrototype.get()); - d()->booleanPrototype.set(exec->globalData(), this, new (exec) BooleanPrototype(exec, this, BooleanPrototype::createStructure(d()->objectPrototype.get()), d()->prototypeFunctionStructure.get())); + d()->booleanPrototype.set(exec->globalData(), this, new (exec) BooleanPrototype(exec, this, BooleanPrototype::createStructure(d()->objectPrototype.get()), d()->functionStructure.get())); d()->booleanObjectStructure = BooleanObject::createStructure(d()->booleanPrototype.get()); - d()->numberPrototype.set(exec->globalData(), this, new (exec) NumberPrototype(exec, this, NumberPrototype::createStructure(d()->objectPrototype.get()), d()->prototypeFunctionStructure.get())); + d()->numberPrototype.set(exec->globalData(), this, new (exec) NumberPrototype(exec, this, NumberPrototype::createStructure(d()->objectPrototype.get()), d()->functionStructure.get())); d()->numberObjectStructure = NumberObject::createStructure(d()->numberPrototype.get()); d()->datePrototype.set(exec->globalData(), this, new (exec) DatePrototype(exec, this, DatePrototype::createStructure(d()->objectPrototype.get()))); d()->dateStructure = DateInstance::createStructure(d()->datePrototype.get()); - d()->regExpPrototype.set(exec->globalData(), this, new (exec) RegExpPrototype(exec, this, RegExpPrototype::createStructure(d()->objectPrototype.get()), d()->prototypeFunctionStructure.get())); + d()->regExpPrototype.set(exec->globalData(), this, new (exec) RegExpPrototype(exec, this, RegExpPrototype::createStructure(d()->objectPrototype.get()), d()->functionStructure.get())); d()->regExpStructure = RegExpObject::createStructure(d()->regExpPrototype.get()); d()->methodCallDummy.set(exec->globalData(), this, constructEmptyObject(exec)); - ErrorPrototype* errorPrototype = new (exec) ErrorPrototype(exec, this, ErrorPrototype::createStructure(d()->objectPrototype.get()), d()->prototypeFunctionStructure.get()); + ErrorPrototype* errorPrototype = new (exec) ErrorPrototype(exec, this, ErrorPrototype::createStructure(d()->objectPrototype.get()), d()->functionStructure.get()); d()->errorStructure = ErrorInstance::createStructure(errorPrototype); // Constructors - JSCell* objectConstructor = new (exec) ObjectConstructor(exec, this, ObjectConstructor::createStructure(d()->functionPrototype.get()), d()->objectPrototype.get(), d()->prototypeFunctionStructure.get()); + JSCell* objectConstructor = new (exec) ObjectConstructor(exec, this, ObjectConstructor::createStructure(d()->functionPrototype.get()), d()->objectPrototype.get()); JSCell* functionConstructor = new (exec) FunctionConstructor(exec, this, FunctionConstructor::createStructure(d()->functionPrototype.get()), d()->functionPrototype.get()); - JSCell* arrayConstructor = new (exec) ArrayConstructor(exec, this, ArrayConstructor::createStructure(d()->functionPrototype.get()), d()->arrayPrototype.get(), d()->prototypeFunctionStructure.get()); - JSCell* stringConstructor = new (exec) StringConstructor(exec, this, StringConstructor::createStructure(d()->functionPrototype.get()), d()->prototypeFunctionStructure.get(), d()->stringPrototype.get()); + JSCell* arrayConstructor = new (exec) ArrayConstructor(exec, this, ArrayConstructor::createStructure(d()->functionPrototype.get()), d()->arrayPrototype.get(), d()->functionStructure.get()); + JSCell* stringConstructor = new (exec) StringConstructor(exec, this, StringConstructor::createStructure(d()->functionPrototype.get()), d()->functionStructure.get(), d()->stringPrototype.get()); JSCell* booleanConstructor = new (exec) BooleanConstructor(exec, this, BooleanConstructor::createStructure(d()->functionPrototype.get()), d()->booleanPrototype.get()); JSCell* numberConstructor = new (exec) NumberConstructor(exec, this, NumberConstructor::createStructure(d()->functionPrototype.get()), d()->numberPrototype.get()); - JSCell* dateConstructor = new (exec) DateConstructor(exec, this, DateConstructor::createStructure(d()->functionPrototype.get()), d()->prototypeFunctionStructure.get(), d()->datePrototype.get()); + JSCell* dateConstructor = new (exec) DateConstructor(exec, this, DateConstructor::createStructure(d()->functionPrototype.get()), d()->functionStructure.get(), d()->datePrototype.get()); d()->regExpConstructor.set(exec->globalData(), this, new (exec) RegExpConstructor(exec, this, RegExpConstructor::createStructure(d()->functionPrototype.get()), d()->regExpPrototype.get())); @@ -294,20 +285,20 @@ void JSGlobalObject::reset(JSValue prototype) // Set global functions. - d()->evalFunction.set(exec->globalData(), this, new (exec) GlobalEvalFunction(exec, this, GlobalEvalFunction::createStructure(d()->functionPrototype.get()), 1, exec->propertyNames().eval, globalFuncEval, this)); + d()->evalFunction.set(exec->globalData(), this, new (exec) JSFunction(exec, this, d()->functionStructure.get(), 1, exec->propertyNames().eval, globalFuncEval)); putDirectFunctionWithoutTransition(exec, d()->evalFunction.get(), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, this, d()->prototypeFunctionStructure.get(), 2, Identifier(exec, "parseInt"), globalFuncParseInt), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, this, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "parseFloat"), globalFuncParseFloat), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, this, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "isNaN"), globalFuncIsNaN), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, this, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "isFinite"), globalFuncIsFinite), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, this, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "escape"), globalFuncEscape), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, this, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "unescape"), globalFuncUnescape), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, this, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "decodeURI"), globalFuncDecodeURI), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, this, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "decodeURIComponent"), globalFuncDecodeURIComponent), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, this, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "encodeURI"), globalFuncEncodeURI), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, this, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "encodeURIComponent"), globalFuncEncodeURIComponent), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, this, d()->functionStructure.get(), 2, Identifier(exec, "parseInt"), globalFuncParseInt), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, this, d()->functionStructure.get(), 1, Identifier(exec, "parseFloat"), globalFuncParseFloat), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, this, d()->functionStructure.get(), 1, Identifier(exec, "isNaN"), globalFuncIsNaN), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, this, d()->functionStructure.get(), 1, Identifier(exec, "isFinite"), globalFuncIsFinite), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, this, d()->functionStructure.get(), 1, Identifier(exec, "escape"), globalFuncEscape), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, this, d()->functionStructure.get(), 1, Identifier(exec, "unescape"), globalFuncUnescape), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, this, d()->functionStructure.get(), 1, Identifier(exec, "decodeURI"), globalFuncDecodeURI), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, this, d()->functionStructure.get(), 1, Identifier(exec, "decodeURIComponent"), globalFuncDecodeURIComponent), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, this, d()->functionStructure.get(), 1, Identifier(exec, "encodeURI"), globalFuncEncodeURI), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, this, d()->functionStructure.get(), 1, Identifier(exec, "encodeURIComponent"), globalFuncEncodeURIComponent), DontEnum); #ifndef NDEBUG - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, this, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "jscprint"), globalFuncJSCPrint), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, this, d()->functionStructure.get(), 1, Identifier(exec, "jscprint"), globalFuncJSCPrint), DontEnum); #endif resetPrototype(prototype); @@ -328,6 +319,8 @@ void JSGlobalObject::markChildren(MarkStack& markStack) { JSVariableObject::markChildren(markStack); + markIfNeeded(markStack, &d()->globalScopeChain); + markIfNeeded(markStack, &d()->regExpConstructor); markIfNeeded(markStack, &d()->errorConstructor); markIfNeeded(markStack, &d()->evalErrorConstructor); @@ -364,7 +357,6 @@ void JSGlobalObject::markChildren(MarkStack& markStack) markIfNeeded(markStack, d()->errorStructure); markIfNeeded(markStack, d()->functionStructure); markIfNeeded(markStack, d()->numberObjectStructure); - markIfNeeded(markStack, d()->prototypeFunctionStructure); markIfNeeded(markStack, d()->regExpMatchesArrayStructure); markIfNeeded(markStack, d()->regExpStructure); markIfNeeded(markStack, d()->stringObjectStructure); @@ -375,12 +367,12 @@ void JSGlobalObject::markChildren(MarkStack& markStack) if (d()->registerArray) { // Outside the execution of global code, when our variables are torn off, // we can mark the torn-off array. - markStack.deprecatedAppendValues(d()->registerArray.get(), d()->registerArraySize); + markStack.appendValues(d()->registerArray.get(), d()->registerArraySize); } else if (d()->registers) { // During execution of global code, when our variables are in the register file, // the symbol table tells us how many variables there are, and registers // points to where they end, and the registers used for execution begin. - markStack.deprecatedAppendValues(d()->registers - symbolTable().size(), symbolTable().size()); + markStack.appendValues(d()->registers - symbolTable().size(), symbolTable().size()); } } @@ -405,8 +397,8 @@ void JSGlobalObject::copyGlobalsFrom(RegisterFile& registerFile) return; } - OwnArrayPtr registerArray = copyRegisterArray(registerFile.lastGlobal(), numGlobals); - Register* registers = registerArray.get() + numGlobals; + OwnArrayPtr > registerArray = copyRegisterArray(globalData(), reinterpret_cast*>(registerFile.lastGlobal()), numGlobals); + WriteBarrier* registers = registerArray.get() + numGlobals; setRegisters(registers, registerArray.release(), numGlobals); } @@ -420,9 +412,32 @@ void JSGlobalObject::copyGlobalsTo(RegisterFile& registerFile) registerFile.setNumGlobals(symbolTable().size()); if (d()->registerArray) { - memcpy(registerFile.start() - d()->registerArraySize, d()->registerArray.get(), d()->registerArraySize * sizeof(Register)); - setRegisters(registerFile.start(), 0, 0); + // The register file is always a gc root so no barrier is needed here + memcpy(registerFile.start() - d()->registerArraySize, d()->registerArray.get(), d()->registerArraySize * sizeof(WriteBarrier)); + setRegisters(reinterpret_cast*>(registerFile.start()), nullptr, 0); + } +} + +void JSGlobalObject::resizeRegisters(int oldSize, int newSize) +{ + ASSERT(symbolTable().size() == newSize); + if (newSize == oldSize) + return; + ASSERT(newSize && newSize > oldSize); + if (d()->registerArray || !d()->registers) { + ASSERT(static_cast(oldSize) == d()->registerArraySize); + OwnArrayPtr > registerArray = adoptArrayPtr(new WriteBarrier[newSize]); + for (int i = 0; i < oldSize; i++) + registerArray[newSize - oldSize + i].set(globalData(), this, d()->registerArray[i].get()); + WriteBarrier* registers = registerArray.get() + newSize; + setRegisters(registers, registerArray.release(), newSize); + } else { + ASSERT(static_cast(newSize) < globalData().interpreter->registerFile().maxGlobals()); + globalData().interpreter->registerFile().setNumGlobals(newSize); } + + for (int i = -newSize; i < -oldSize; ++i) + d()->registers[i].setUndefined(); } void* JSGlobalObject::operator new(size_t size, JSGlobalData* globalData) diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h index d13d2da..03b39fc 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.h +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h @@ -26,7 +26,6 @@ #include "JSGlobalData.h" #include "JSVariableObject.h" #include "JSWeakObjectMapRefInternal.h" -#include "NativeFunctionWrapper.h" #include "NumberPrototype.h" #include "StringPrototype.h" #include @@ -42,10 +41,8 @@ namespace JSC { class ErrorConstructor; class FunctionPrototype; class GlobalCodeBlock; - class GlobalEvalFunction; class NativeErrorConstructor; class ProgramCodeBlock; - class PrototypeFunction; class RegExpConstructor; class RegExpPrototype; class RegisterFile; @@ -72,7 +69,7 @@ namespace JSC { : JSVariableObjectData(&symbolTable, 0) , destructor(destructor) , registerArraySize(0) - , globalScopeChain(NoScopeChain()) + , globalScopeChain() , weakRandom(static_cast(randomNumber() * (std::numeric_limits::max() + 1.0))) { } @@ -86,7 +83,7 @@ namespace JSC { Debugger* debugger; - ScopeChain globalScopeChain; + WriteBarrier globalScopeChain; Register globalCallFrame[RegisterFile::CallFrameHeaderSize]; WriteBarrier regExpConstructor; @@ -98,9 +95,9 @@ namespace JSC { WriteBarrier typeErrorConstructor; WriteBarrier URIErrorConstructor; - WriteBarrier evalFunction; - WriteBarrier callFunction; - WriteBarrier applyFunction; + WriteBarrier evalFunction; + WriteBarrier callFunction; + WriteBarrier applyFunction; WriteBarrier objectPrototype; WriteBarrier functionPrototype; @@ -124,7 +121,6 @@ namespace JSC { RefPtr errorStructure; RefPtr functionStructure; RefPtr numberObjectStructure; - RefPtr prototypeFunctionStructure; RefPtr regExpMatchesArrayStructure; RefPtr regExpStructure; RefPtr stringObjectStructure; @@ -181,6 +177,10 @@ namespace JSC { virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunc, unsigned attributes); virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunc, unsigned attributes); + // We use this in the code generator as we perform symbol table + // lookups prior to initializing the properties + bool symbolTableHasProperty(const Identifier& propertyName); + // The following accessors return pristine values, even if a script // replaces the global object's associated property. @@ -194,7 +194,7 @@ namespace JSC { NativeErrorConstructor* typeErrorConstructor() const { return d()->typeErrorConstructor.get(); } NativeErrorConstructor* URIErrorConstructor() const { return d()->URIErrorConstructor.get(); } - GlobalEvalFunction* evalFunction() const { return d()->evalFunction.get(); } + JSFunction* evalFunction() const { return d()->evalFunction.get(); } ObjectPrototype* objectPrototype() const { return d()->objectPrototype.get(); } FunctionPrototype* functionPrototype() const { return d()->functionPrototype.get(); } @@ -218,7 +218,6 @@ namespace JSC { Structure* errorStructure() const { return d()->errorStructure.get(); } Structure* functionStructure() const { return d()->functionStructure.get(); } Structure* numberObjectStructure() const { return d()->numberObjectStructure.get(); } - Structure* prototypeFunctionStructure() const { return d()->prototypeFunctionStructure.get(); } Structure* internalFunctionStructure() const { return d()->internalFunctionStructure.get(); } Structure* regExpMatchesArrayStructure() const { return d()->regExpMatchesArrayStructure.get(); } Structure* regExpStructure() const { return d()->regExpStructure.get(); } @@ -233,7 +232,7 @@ namespace JSC { virtual bool supportsProfiling() const { return false; } virtual bool supportsRichSourceInfo() const { return true; } - ScopeChain& globalScopeChain() { return d()->globalScopeChain; } + ScopeChainNode* globalScopeChain() { return d()->globalScopeChain.get(); } virtual bool isGlobalObject() const { return true; } @@ -247,7 +246,8 @@ namespace JSC { void copyGlobalsFrom(RegisterFile&); void copyGlobalsTo(RegisterFile&); - + void resizeRegisters(int oldSize, int newSize); + void resetPrototype(JSValue prototype); JSGlobalData& globalData() const { return *d()->globalData.get(); } @@ -255,7 +255,7 @@ namespace JSC { static PassRefPtr createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } void registerWeakMap(OpaqueJSWeakObjectMap* map) @@ -295,7 +295,7 @@ namespace JSC { void init(JSObject* thisValue); void reset(JSValue prototype); - void setRegisters(Register* registers, PassOwnArrayPtr registerArray, size_t count); + void setRegisters(WriteBarrier* registers, PassOwnArrayPtr > registerArray, size_t count); void* operator new(size_t); // can only be allocated with JSGlobalData }; @@ -308,7 +308,7 @@ namespace JSC { return static_cast(asObject(value)); } - inline void JSGlobalObject::setRegisters(Register* registers, PassOwnArrayPtr registerArray, size_t count) + inline void JSGlobalObject::setRegisters(WriteBarrier* registers, PassOwnArrayPtr > registerArray, size_t count) { JSVariableObject::setRegisters(registers, registerArray); d()->registerArraySize = count; @@ -318,17 +318,21 @@ namespace JSC { { size_t oldSize = d()->registerArraySize; size_t newSize = oldSize + count; - Register* registerArray = new Register[newSize]; - if (d()->registerArray) - memcpy(registerArray + count, d()->registerArray.get(), oldSize * sizeof(Register)); - setRegisters(registerArray + newSize, registerArray, newSize); + OwnArrayPtr > registerArray = adoptArrayPtr(new WriteBarrier[newSize]); + if (d()->registerArray) { + // memcpy is safe here as we're copying barriers we already own from the existing array + memcpy(registerArray.get() + count, d()->registerArray.get(), oldSize * sizeof(Register)); + } + + WriteBarrier* registers = registerArray.get() + newSize; + setRegisters(registers, registerArray.release(), newSize); for (int i = 0, index = -static_cast(oldSize) - 1; i < count; ++i, --index) { GlobalPropertyInfo& global = globals[i]; ASSERT(global.attributes & DontDelete); SymbolTableEntry newEntry(index, global.attributes); symbolTable().add(global.identifier.impl(), newEntry); - registerAt(index) = global.value; + registerAt(index).set(globalData(), this, global.value); } } @@ -355,6 +359,12 @@ namespace JSC { return symbolTableGet(propertyName, slot, slotIsWriteable); } + inline bool JSGlobalObject::symbolTableHasProperty(const Identifier& propertyName) + { + SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl()); + return !entry.isNull(); + } + inline JSValue Structure::prototypeForLookup(ExecState* exec) const { if (typeInfo().type() == ObjectType) @@ -401,16 +411,16 @@ namespace JSC { return globalData().dynamicGlobalObject; } - inline JSObject* constructEmptyObject(ExecState* exec) - { - return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure()); - } - inline JSObject* constructEmptyObject(ExecState* exec, JSGlobalObject* globalObject) { - return new (exec) JSObject(globalObject->emptyObjectStructure()); + return constructEmptyObject(exec, globalObject->emptyObjectStructure()); } + inline JSObject* constructEmptyObject(ExecState* exec) + { + return constructEmptyObject(exec, exec->lexicalGlobalObject()); + } + inline JSArray* constructEmptyArray(ExecState* exec) { return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure()); diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp index 284806e..de1300a 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp @@ -26,7 +26,6 @@ #include "JSGlobalObjectFunctions.h" #include "CallFrame.h" -#include "GlobalEvalFunction.h" #include "Interpreter.h" #include "JSGlobalObject.h" #include "JSString.h" @@ -451,11 +450,11 @@ EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec) return JSValue::encode(parsedObject); RefPtr eval = EvalExecutable::create(exec, makeSource(s), false); - JSObject* error = eval->compile(exec, static_cast(unwrappedObject)->globalScopeChain().node()); + JSObject* error = eval->compile(exec, static_cast(unwrappedObject)->globalScopeChain()); if (error) return throwVMError(exec, error); - return JSValue::encode(exec->interpreter()->execute(eval.get(), exec, thisObject, static_cast(unwrappedObject)->globalScopeChain().node())); + return JSValue::encode(exec->interpreter()->execute(eval.get(), exec, thisObject, static_cast(unwrappedObject)->globalScopeChain())); } EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec) diff --git a/Source/JavaScriptCore/runtime/JSLock.cpp b/Source/JavaScriptCore/runtime/JSLock.cpp index 918141f..64dcb08 100644 --- a/Source/JavaScriptCore/runtime/JSLock.cpp +++ b/Source/JavaScriptCore/runtime/JSLock.cpp @@ -23,14 +23,18 @@ #include "Heap.h" #include "CallFrame.h" +#include "ScopeChain.h" -#if ENABLE(JSC_MULTIPLE_THREADS) +#if USE(PTHREADS) #include #endif namespace JSC { -#if ENABLE(JSC_MULTIPLE_THREADS) +// JSLock is only needed to support an obsolete execution model where JavaScriptCore +// automatically protected against concurrent access from multiple threads. +// So it's safe to disable it on non-mac platforms where we don't have native pthreads. +#if ENABLE(JSC_MULTIPLE_THREADS) && (OS(DARWIN) || USE(PTHREADS)) // Acquire this mutex before accessing lock-related data. static pthread_mutex_t JSMutex = PTHREAD_MUTEX_INITIALIZER; @@ -208,7 +212,7 @@ JSLock::DropAllLocks::~DropAllLocks() --lockDropDepth; } -#else +#else // ENABLE(JSC_MULTIPLE_THREADS) && (OS(DARWIN) || USE(PTHREADS)) JSLock::JSLock(ExecState*) : m_lockBehavior(SilenceAssertionsOnly) @@ -255,6 +259,6 @@ JSLock::DropAllLocks::~DropAllLocks() { } -#endif // USE(MULTIPLE_THREADS) +#endif // ENABLE(JSC_MULTIPLE_THREADS) && (OS(DARWIN) || USE(PTHREADS)) } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSNotAnObject.h b/Source/JavaScriptCore/runtime/JSNotAnObject.h index 9f527cf..7e70a98 100644 --- a/Source/JavaScriptCore/runtime/JSNotAnObject.h +++ b/Source/JavaScriptCore/runtime/JSNotAnObject.h @@ -36,16 +36,16 @@ namespace JSC { // This unholy class is used to allow us to avoid multiple exception checks // in certain SquirrelFish bytecodes -- effectively it just silently consumes // any operations performed on the result of a failed toObject call. - class JSNotAnObject : public JSObject { + class JSNotAnObject : public JSNonFinalObject { public: JSNotAnObject(ExecState* exec) - : JSObject(exec->globalData().notAnObjectStructure) + : JSNonFinalObject(exec->globalData().notAnObjectStructure) { } static PassRefPtr createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } private: diff --git a/Source/JavaScriptCore/runtime/JSNumberCell.cpp b/Source/JavaScriptCore/runtime/JSNumberCell.cpp index 6fa6b2a..3172cc9 100644 --- a/Source/JavaScriptCore/runtime/JSNumberCell.cpp +++ b/Source/JavaScriptCore/runtime/JSNumberCell.cpp @@ -22,6 +22,7 @@ #include "config.h" #include "JSNumberCell.h" +#include "ScopeChain.h" // Keep our exported symbols lists happy. namespace JSC { diff --git a/Source/JavaScriptCore/runtime/JSONObject.cpp b/Source/JavaScriptCore/runtime/JSONObject.cpp index 0f7a576..7d18e08 100644 --- a/Source/JavaScriptCore/runtime/JSONObject.cpp +++ b/Source/JavaScriptCore/runtime/JSONObject.cpp @@ -54,6 +54,7 @@ namespace JSC { JSONObject::JSONObject(JSGlobalObject* globalObject, NonNullPassRefPtr structure) : JSObjectWithGlobalObject(globalObject, structure) { + ASSERT(inherits(&s_info)); } // PropertyNameForFunctionCall objects must be on the stack, since the JSValue that they create is not marked. @@ -134,11 +135,11 @@ static inline JSValue unwrapBoxedPrimitive(ExecState* exec, JSValue value) if (!value.isObject()) return value; JSObject* object = asObject(value); - if (object->inherits(&NumberObject::info)) + if (object->inherits(&NumberObject::s_info)) return jsNumber(object->toNumber(exec)); - if (object->inherits(&StringObject::info)) + if (object->inherits(&StringObject::s_info)) return jsString(exec, object->toString(exec)); - if (object->inherits(&BooleanObject::info)) + if (object->inherits(&BooleanObject::s_info)) return object->toPrimitive(exec); return value; } @@ -212,7 +213,7 @@ Stringifier::Stringifier(ExecState* exec, JSValue replacer, JSValue space) if (!m_replacer.isObject()) return; - if (asObject(m_replacer)->inherits(&JSArray::info)) { + if (asObject(m_replacer)->inherits(&JSArray::s_info)) { m_usingArrayReplacer = true; JSObject* array = asObject(m_replacer); unsigned length = array->get(exec, exec->globalData().propertyNames->length).toUInt32(exec); @@ -234,7 +235,7 @@ Stringifier::Stringifier(ExecState* exec, JSValue replacer, JSValue space) } if (name.isObject()) { - if (!asObject(name)->inherits(&NumberObject::info) && !asObject(name)->inherits(&StringObject::info)) + if (!asObject(name)->inherits(&NumberObject::s_info) && !asObject(name)->inherits(&StringObject::s_info)) continue; propertyName = name.toString(exec); if (exec->hadException()) @@ -376,7 +377,7 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(UStringBuilder& return StringifyFailed; } - if (value.isUndefined() && !holder->inherits(&JSArray::info)) + if (value.isUndefined() && !holder->inherits(&JSArray::s_info)) return StringifyFailedDueToUndefinedValue; if (value.isNull()) { @@ -416,7 +417,7 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(UStringBuilder& CallData callData; if (object->getCallData(callData) != CallTypeNone) { - if (holder->inherits(&JSArray::info)) { + if (holder->inherits(&JSArray::s_info)) { builder.append("null"); return StringifySucceeded; } @@ -486,7 +487,7 @@ inline void Stringifier::startNewLine(UStringBuilder& builder) const inline Stringifier::Holder::Holder(JSObject* object) : m_object(object) - , m_isArray(object->inherits(&JSArray::info)) + , m_isArray(object->inherits(&JSArray::s_info)) , m_index(0) { } @@ -601,7 +602,7 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, UStringBu // ------------------------------ JSONObject -------------------------------- -const ClassInfo JSONObject::info = { "JSON", 0, 0, ExecState::jsonTable }; +const ClassInfo JSONObject::s_info = { "JSON", &JSObjectWithGlobalObject::s_info, 0, ExecState::jsonTable }; /* Source for JSONObject.lut.h @begin jsonTable @@ -678,7 +679,7 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) arrayStartState: case ArrayStartState: { ASSERT(inValue.isObject()); - ASSERT(isJSArray(&m_exec->globalData(), asObject(inValue)) || asObject(inValue)->inherits(&JSArray::info)); + ASSERT(isJSArray(&m_exec->globalData(), asObject(inValue)) || asObject(inValue)->inherits(&JSArray::s_info)); if (objectStack.size() + arrayStack.size() > maximumFilterRecursion) return throwError(m_exec, createStackOverflowError(m_exec)); @@ -739,7 +740,7 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) objectStartState: case ObjectStartState: { ASSERT(inValue.isObject()); - ASSERT(!isJSArray(&m_exec->globalData(), asObject(inValue)) && !asObject(inValue)->inherits(&JSArray::info)); + ASSERT(!isJSArray(&m_exec->globalData(), asObject(inValue)) && !asObject(inValue)->inherits(&JSArray::s_info)); if (objectStack.size() + arrayStack.size() > maximumFilterRecursion) return throwError(m_exec, createStackOverflowError(m_exec)); @@ -806,7 +807,7 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) break; } JSObject* object = asObject(inValue); - if (isJSArray(&m_exec->globalData(), object) || object->inherits(&JSArray::info)) + if (isJSArray(&m_exec->globalData(), object) || object->inherits(&JSArray::s_info)) goto arrayStartState; goto objectStartState; } diff --git a/Source/JavaScriptCore/runtime/JSONObject.h b/Source/JavaScriptCore/runtime/JSONObject.h index f64be12..acffeca 100644 --- a/Source/JavaScriptCore/runtime/JSONObject.h +++ b/Source/JavaScriptCore/runtime/JSONObject.h @@ -38,7 +38,7 @@ namespace JSC { static PassRefPtr createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } static void markStringifiers(MarkStack&, Stringifier*); @@ -50,8 +50,7 @@ namespace JSC { virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); - virtual const ClassInfo* classInfo() const { return &info; } - static const ClassInfo info; + static const ClassInfo s_info; }; UString JSONStringify(ExecState* exec, JSValue value, unsigned indent); diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp index 277ffff..87fbb67 100644 --- a/Source/JavaScriptCore/runtime/JSObject.cpp +++ b/Source/JavaScriptCore/runtime/JSObject.cpp @@ -42,9 +42,13 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(JSObject); +ASSERT_CLASS_FITS_IN_CELL(JSNonFinalObject); +ASSERT_CLASS_FILLS_CELL(JSFinalObject); const char* StrictModeReadonlyPropertyWriteError = "Attempted to assign to readonly property."; +const ClassInfo JSObject::s_info = { "Object", 0, 0, 0 }; + static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode) { // Add properties from the static hashtables of properties @@ -81,9 +85,8 @@ void JSObject::markChildren(MarkStack& markStack) UString JSObject::className() const { const ClassInfo* info = classInfo(); - if (info) - return info->className; - return "Object"; + ASSERT(info); + return info->className; } bool JSObject::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) @@ -506,6 +509,22 @@ JSObject* JSObject::unwrappedObject() return this; } +void JSObject::seal() +{ + setStructure(Structure::sealTransition(m_structure)); +} + +void JSObject::freeze() +{ + setStructure(Structure::freezeTransition(m_structure)); +} + +void JSObject::preventExtensions() +{ + if (isExtensible()) + setStructure(Structure::preventExtensionsTransition(m_structure)); +} + void JSObject::removeDirect(const Identifier& propertyName) { size_t offset; @@ -555,13 +574,28 @@ NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, WriteBarr Structure* JSObject::createInheritorID() { - m_inheritorID = JSObject::createStructure(this); + m_inheritorID = createEmptyObjectStructure(this); return m_inheritorID.get(); } void JSObject::allocatePropertyStorage(size_t oldSize, size_t newSize) { - allocatePropertyStorageInline(oldSize, newSize); + ASSERT(newSize > oldSize); + + // It's important that this function not rely on m_structure, since + // we might be in the middle of a transition. + bool wasInline = (oldSize < JSObject::baseExternalStorageCapacity); + + PropertyStorage oldPropertyStorage = m_propertyStorage; + PropertyStorage newPropertyStorage = new WriteBarrierBase[newSize]; + + for (unsigned i = 0; i < oldSize; ++i) + newPropertyStorage[i] = oldPropertyStorage[i]; + + if (!wasInline) + delete [] oldPropertyStorage; + + m_propertyStorage = newPropertyStorage; } bool JSObject::getOwnPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor& descriptor) @@ -627,6 +661,12 @@ bool JSObject::defineOwnProperty(ExecState* exec, const Identifier& propertyName // If we have a new property we can just put it on normally PropertyDescriptor current; if (!getOwnPropertyDescriptor(exec, propertyName, current)) { + // unless extensions are prevented! + if (!isExtensible()) { + if (throwException) + throwError(exec, createTypeError(exec, "Attempting to define property on object that is not extensible.")); + return false; + } PropertyDescriptor oldDescriptor; oldDescriptor.setValue(jsUndefined()); return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributes(), oldDescriptor); diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h index b79249c..2b4db43 100644 --- a/Source/JavaScriptCore/runtime/JSObject.h +++ b/Source/JavaScriptCore/runtime/JSObject.h @@ -80,8 +80,6 @@ namespace JSC { friend void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot); public: - explicit JSObject(NonNullPassRefPtr); - virtual void markChildren(MarkStack&); ALWAYS_INLINE void markChildrenDirect(MarkStack& markStack); @@ -212,19 +210,19 @@ namespace JSC { virtual bool isStrictModeFunction() const { return false; } virtual bool isErrorInstance() const { return false; } + void seal(); + void freeze(); + void preventExtensions(); + bool isSealed() { return m_structure->isSealed(); } + bool isFrozen() { return m_structure->isFrozen(); } + bool isExtensible() { return m_structure->isExtensible(); } + virtual ComplType exceptionType() const { return Throw; } void allocatePropertyStorage(size_t oldSize, size_t newSize); - void allocatePropertyStorageInline(size_t oldSize, size_t newSize); bool isUsingInlineStorage() const { return m_structure->isUsingInlineStorage(); } - static const unsigned inlineStorageCapacity = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 4 : 3; - static const unsigned nonInlineBaseStorageCapacity = 16; - - static PassRefPtr createStructure(JSValue prototype) - { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); - } + static const unsigned baseExternalStorageCapacity = 16; void flattenDictionaryObject(JSGlobalData& globalData) { @@ -246,15 +244,28 @@ namespace JSC { ASSERT(index < m_structure->anonymousSlotCount()); return locationForOffset(index)->get(); } + + static size_t offsetOfInlineStorage(); + static JS_EXPORTDATA const ClassInfo s_info; + protected: + static PassRefPtr createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); + } + static const unsigned StructureFlags = 0; - + void putThisToAnonymousValue(unsigned index) { locationForOffset(index)->setWithoutWriteBarrier(this); } - + + // To instantiate objects you likely want JSFinalObject, below. + // To create derived types you likely want JSNonFinalObject, below. + JSObject(NonNullPassRefPtr, PropertyStorage inlineStorage); + private: // Nobody should ever ask any of these questions on something already known to be a JSObject. using JSCell::isAPIValueWrapper; @@ -265,8 +276,8 @@ namespace JSC { void isObject(); void isString(); - ConstPropertyStorage propertyStorage() const { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); } - PropertyStorage propertyStorage() { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); } + ConstPropertyStorage propertyStorage() const { return m_propertyStorage; } + PropertyStorage propertyStorage() { return m_propertyStorage; } const WriteBarrierBase* locationForOffset(size_t offset) const { @@ -287,14 +298,90 @@ namespace JSC { const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const; Structure* createInheritorID(); - union { - PropertyStorage m_externalStorage; - WriteBarrierBase m_inlineStorage[inlineStorageCapacity]; - }; - + PropertyStorage m_propertyStorage; RefPtr m_inheritorID; }; - + + +#if USE(JSVALUE32_64) +#define JSNonFinalObject_inlineStorageCapacity 4 +#define JSFinalObject_inlineStorageCapacity 6 +#else +#define JSNonFinalObject_inlineStorageCapacity 2 +#define JSFinalObject_inlineStorageCapacity 4 +#endif + +COMPILE_ASSERT((JSFinalObject_inlineStorageCapacity >= JSNonFinalObject_inlineStorageCapacity), final_storage_is_at_least_as_large_as_non_final); + + // JSNonFinalObject is a type of JSObject that has some internal storage, + // but also preserves some space in the collector cell for additional + // data members in derived types. + class JSNonFinalObject : public JSObject { + friend class JSObject; + + public: + static PassRefPtr createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); + } + + protected: + explicit JSNonFinalObject(NonNullPassRefPtr structure) + : JSObject(structure, m_inlineStorage) + { + ASSERT(!(OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage) % sizeof(double))); + ASSERT(this->structure()->propertyStorageCapacity() == JSNonFinalObject_inlineStorageCapacity); + } + + private: + WriteBarrierBase m_inlineStorage[JSNonFinalObject_inlineStorageCapacity]; + }; + + // JSFinalObject is a type of JSObject that contains sufficent internal + // storage to fully make use of the colloctor cell containing it. + class JSFinalObject : public JSObject { + friend class JSObject; + + public: + static JSFinalObject* create(ExecState* exec, NonNullPassRefPtr structure) + { + return new (exec) JSFinalObject(structure); + } + + static PassRefPtr createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); + } + + private: + explicit JSFinalObject(NonNullPassRefPtr structure) + : JSObject(structure, m_inlineStorage) + { + ASSERT(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) % sizeof(double) == 0); + ASSERT(this->structure()->propertyStorageCapacity() == JSFinalObject_inlineStorageCapacity); + } + + static const unsigned StructureFlags = JSObject::StructureFlags | IsJSFinalObject; + + WriteBarrierBase m_inlineStorage[JSFinalObject_inlineStorageCapacity]; + }; + +inline size_t JSObject::offsetOfInlineStorage() +{ + ASSERT(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) == OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage)); + return OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage); +} + +inline JSObject* constructEmptyObject(ExecState* exec, NonNullPassRefPtr structure) +{ + return JSFinalObject::create(exec, structure); +} + +inline PassRefPtr createEmptyObjectStructure(JSValue prototype) +{ + return JSFinalObject::createStructure(prototype); +} + inline JSObject* asObject(JSCell* cell) { ASSERT(cell->isObject()); @@ -306,20 +393,21 @@ inline JSObject* asObject(JSValue value) return asObject(value.asCell()); } -inline JSObject::JSObject(NonNullPassRefPtr structure) +inline JSObject::JSObject(NonNullPassRefPtr structure, PropertyStorage inlineStorage) : JSCell(structure.releaseRef()) // ~JSObject balances this ref() + , m_propertyStorage(inlineStorage) { - ASSERT(m_structure->propertyStorageCapacity() == inlineStorageCapacity); + ASSERT(inherits(&s_info)); + ASSERT(m_structure->propertyStorageCapacity() < baseExternalStorageCapacity); ASSERT(m_structure->isEmpty()); ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype())); - ASSERT(OBJECT_OFFSETOF(JSObject, m_inlineStorage) % sizeof(double) == 0); } inline JSObject::~JSObject() { ASSERT(m_structure); if (!isUsingInlineStorage()) - delete [] m_externalStorage; + delete [] m_propertyStorage; m_structure->deref(); } @@ -363,7 +451,7 @@ inline Structure* JSObject::inheritorID() inline bool Structure::isUsingInlineStorage() const { - return (propertyStorageCapacity() == JSObject::inlineStorageCapacity); + return propertyStorageCapacity() < JSObject::baseExternalStorageCapacity; } inline bool JSCell::inherits(const ClassInfo* info) const @@ -490,6 +578,9 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi return true; } + if (!isExtensible()) + return false; + size_t currentCapacity = m_structure->propertyStorageCapacity(); offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, specificFunction); if (currentCapacity != m_structure->propertyStorageCapacity()) @@ -551,15 +642,8 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi return true; } - // If we have a specific function, we may have got to this point if there is - // already a transition with the correct property name and attributes, but - // specialized to a different function. In this case we just want to give up - // and despecialize the transition. - // In this case we clear the value of specificFunction which will result - // in us adding a non-specific transition, and any subsequent lookup in - // Structure::addPropertyTransitionToExistingStructure will just use that. - if (specificFunction && m_structure->hasTransition(propertyName, attributes)) - specificFunction = 0; + if (!isExtensible()) + return false; RefPtr structure = Structure::addPropertyTransition(m_structure, propertyName, attributes, specificFunction, offset); @@ -727,26 +811,6 @@ inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue value) asCell()->put(exec, propertyName, value); } -ALWAYS_INLINE void JSObject::allocatePropertyStorageInline(size_t oldSize, size_t newSize) -{ - ASSERT(newSize > oldSize); - - // It's important that this function not rely on m_structure, since - // we might be in the middle of a transition. - bool wasInline = (oldSize == JSObject::inlineStorageCapacity); - - PropertyStorage oldPropertyStorage = (wasInline ? m_inlineStorage : m_externalStorage); - PropertyStorage newPropertyStorage = new WriteBarrierBase[newSize]; - - for (unsigned i = 0; i < oldSize; ++i) - newPropertyStorage[i] = oldPropertyStorage[i]; - - if (!wasInline) - delete [] oldPropertyStorage; - - m_externalStorage = newPropertyStorage; -} - ALWAYS_INLINE void JSObject::markChildrenDirect(MarkStack& markStack) { JSCell::markChildren(markStack); diff --git a/Source/JavaScriptCore/runtime/JSObjectWithGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSObjectWithGlobalObject.cpp index c16acb1..9370139 100644 --- a/Source/JavaScriptCore/runtime/JSObjectWithGlobalObject.cpp +++ b/Source/JavaScriptCore/runtime/JSObjectWithGlobalObject.cpp @@ -31,7 +31,7 @@ namespace JSC { JSObjectWithGlobalObject::JSObjectWithGlobalObject(JSGlobalObject* globalObject, NonNullPassRefPtr structure) - : JSObject(structure) + : JSNonFinalObject(structure) { COMPILE_ASSERT(AnonymousSlotCount == 1, AnonymousSlotCount_must_be_one); ASSERT(!globalObject || globalObject->isGlobalObject()); diff --git a/Source/JavaScriptCore/runtime/JSObjectWithGlobalObject.h b/Source/JavaScriptCore/runtime/JSObjectWithGlobalObject.h index 9416a62..c5e3047 100644 --- a/Source/JavaScriptCore/runtime/JSObjectWithGlobalObject.h +++ b/Source/JavaScriptCore/runtime/JSObjectWithGlobalObject.h @@ -32,11 +32,11 @@ namespace JSC { class JSGlobalObject; -class JSObjectWithGlobalObject : public JSObject { +class JSObjectWithGlobalObject : public JSNonFinalObject { public: static PassRefPtr createStructure(JSValue proto) { - return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } JSGlobalObject* globalObject() const; @@ -45,7 +45,7 @@ protected: JSObjectWithGlobalObject(JSGlobalObject*, NonNullPassRefPtr); JSObjectWithGlobalObject(NonNullPassRefPtr structure) - : JSObject(structure) + : JSNonFinalObject(structure) { // Should only be used by JSFunction when we aquire the JSFunction vptr. } diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp index 6fd28e3..0d759cf 100644 --- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp +++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp @@ -47,12 +47,6 @@ inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, PropertyN m_jsStrings[i].set(exec->globalData(), this, jsOwnedString(exec, propertyNameVector[i].ustring())); } -JSPropertyNameIterator::~JSPropertyNameIterator() -{ - if (m_cachedStructure) - m_cachedStructure->clearEnumerationCache(this); -} - JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSObject* o) { ASSERT(!o->structure()->enumerationCache() || @@ -85,7 +79,7 @@ JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSObject jsPropertyNameIterator->setCachedPrototypeChain(structureChain); jsPropertyNameIterator->setCachedStructure(o->structure()); - o->structure()->setEnumerationCache(jsPropertyNameIterator); + o->structure()->setEnumerationCache(exec->globalData(), jsPropertyNameIterator); return jsPropertyNameIterator; } @@ -105,4 +99,12 @@ void JSPropertyNameIterator::markChildren(MarkStack& markStack) markStack.appendValues(m_jsStrings.get(), m_jsStringsSize, MayContainNullValues); } +#if !ASSERT_DISABLED + +JSPropertyNameIterator::~JSPropertyNameIterator() +{ + ASSERT(!m_cachedStructure || m_cachedStructure->enumerationCache() != this); +} + +#endif } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h index cd46243..d51cba8 100644 --- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h +++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h @@ -47,10 +47,8 @@ namespace JSC { static PassRefPtr createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(CompoundType, OverridesMarkChildren), AnonymousSlotCount); + return Structure::create(prototype, TypeInfo(CompoundType, OverridesMarkChildren), AnonymousSlotCount, 0); } - - virtual ~JSPropertyNameIterator(); virtual bool isPropertyNameIterator() const { return true; } @@ -80,6 +78,10 @@ namespace JSC { private: JSPropertyNameIterator(ExecState*, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlot); + +#if !ASSERT_DISABLED + virtual ~JSPropertyNameIterator(); +#endif RefPtr m_cachedStructure; RefPtr m_cachedPrototypeChain; @@ -88,15 +90,15 @@ namespace JSC { OwnArrayPtr > m_jsStrings; }; - inline void Structure::setEnumerationCache(JSPropertyNameIterator* enumerationCache) + inline void Structure::setEnumerationCache(JSGlobalData& globalData, JSPropertyNameIterator* enumerationCache) { ASSERT(!isDictionary()); - m_enumerationCache = enumerationCache; + m_enumerationCache.set(globalData, enumerationCache, 0); } - inline void Structure::clearEnumerationCache(JSPropertyNameIterator* enumerationCache) + inline void Structure::clearEnumerationCache() { - m_enumerationCache.clear(enumerationCache); + m_enumerationCache.clear(); } inline JSPropertyNameIterator* Structure::enumerationCache() diff --git a/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp b/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp index 80b048e..727ac28 100644 --- a/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp +++ b/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp @@ -47,17 +47,17 @@ JSValue JSStaticScopeObject::toStrictThisObject(ExecState*) const return jsNull(); } -void JSStaticScopeObject::put(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot&) +void JSStaticScopeObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot&) { - if (symbolTablePut(propertyName, value)) + if (symbolTablePut(exec->globalData(), propertyName, value)) return; ASSERT_NOT_REACHED(); } -void JSStaticScopeObject::putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes) +void JSStaticScopeObject::putWithAttributes(ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes) { - if (symbolTablePutWithAttributes(propertyName, value, attributes)) + if (symbolTablePutWithAttributes(exec->globalData(), propertyName, value, attributes)) return; ASSERT_NOT_REACHED(); @@ -74,7 +74,7 @@ JSStaticScopeObject::~JSStaticScopeObject() delete d(); } -inline bool JSStaticScopeObject::getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot& slot) +bool JSStaticScopeObject::getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot& slot) { return symbolTableGet(propertyName, slot); } diff --git a/Source/JavaScriptCore/runtime/JSStaticScopeObject.h b/Source/JavaScriptCore/runtime/JSStaticScopeObject.h index e69356a..b3c0695 100644 --- a/Source/JavaScriptCore/runtime/JSStaticScopeObject.h +++ b/Source/JavaScriptCore/runtime/JSStaticScopeObject.h @@ -58,7 +58,7 @@ namespace JSC{ virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&); void putWithAttributes(ExecState*, const Identifier&, JSValue, unsigned attributes); - static PassRefPtr createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); } + static PassRefPtr createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: static const unsigned StructureFlags = OverridesGetOwnPropertySlot | NeedsThisConversion | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags; diff --git a/Source/JavaScriptCore/runtime/JSString.h b/Source/JavaScriptCore/runtime/JSString.h index 6696404..3672300 100644 --- a/Source/JavaScriptCore/runtime/JSString.h +++ b/Source/JavaScriptCore/runtime/JSString.h @@ -349,7 +349,7 @@ namespace JSC { JSValue replaceCharacter(ExecState*, UChar, const UString& replacement); - static PassRefPtr createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion), AnonymousSlotCount); } + static PassRefPtr createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion), AnonymousSlotCount, 0); } private: enum VPtrStealingHackType { VPtrStealingHack }; diff --git a/Source/JavaScriptCore/runtime/JSTypeInfo.h b/Source/JavaScriptCore/runtime/JSTypeInfo.h index e225bc7..fdcaf31 100644 --- a/Source/JavaScriptCore/runtime/JSTypeInfo.h +++ b/Source/JavaScriptCore/runtime/JSTypeInfo.h @@ -43,20 +43,21 @@ namespace JSC { static const unsigned OverridesGetOwnPropertySlot = 1 << 5; static const unsigned OverridesMarkChildren = 1 << 6; static const unsigned OverridesGetPropertyNames = 1 << 7; + static const unsigned IsJSFinalObject = 1 << 8; class TypeInfo { friend class JIT; public: TypeInfo(JSType type, unsigned flags = 0) : m_type(type) + , m_flags(flags & 0xFF) + , m_flags2(flags >> 8) { - ASSERT(flags <= 0xFF); + ASSERT(flags <= 0x1FF); ASSERT(type <= 0xFF); // ImplementsDefaultHasInstance means (ImplementsHasInstance & !OverridesHasInstance) - if ((flags & (ImplementsHasInstance | OverridesHasInstance)) == ImplementsHasInstance) - m_flags = flags | ImplementsDefaultHasInstance; - else - m_flags = flags; + if ((m_flags & (ImplementsHasInstance | OverridesHasInstance)) == ImplementsHasInstance) + m_flags |= ImplementsDefaultHasInstance; } JSType type() const { return (JSType)m_type; } @@ -69,10 +70,12 @@ namespace JSC { bool overridesMarkChildren() const { return m_flags & OverridesMarkChildren; } bool overridesGetPropertyNames() const { return m_flags & OverridesGetPropertyNames; } unsigned flags() const { return m_flags; } + unsigned isFinal() const { return m_flags2 && (IsJSFinalObject >> 8); } private: unsigned char m_type; unsigned char m_flags; + unsigned char m_flags2; }; } diff --git a/Source/JavaScriptCore/runtime/JSVariableObject.cpp b/Source/JavaScriptCore/runtime/JSVariableObject.cpp index 81d05ba..abe9bbb 100644 --- a/Source/JavaScriptCore/runtime/JSVariableObject.cpp +++ b/Source/JavaScriptCore/runtime/JSVariableObject.cpp @@ -62,7 +62,7 @@ bool JSVariableObject::symbolTableGet(const Identifier& propertyName, PropertyDe { SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl()); if (!entry.isNull()) { - descriptor.setDescriptor(registerAt(entry.getIndex()).jsValue(), entry.getAttributes() | DontDelete); + descriptor.setDescriptor(registerAt(entry.getIndex()).get(), entry.getAttributes() | DontDelete); return true; } return false; diff --git a/Source/JavaScriptCore/runtime/JSVariableObject.h b/Source/JavaScriptCore/runtime/JSVariableObject.h index 96a0ec4..e94d277 100644 --- a/Source/JavaScriptCore/runtime/JSVariableObject.h +++ b/Source/JavaScriptCore/runtime/JSVariableObject.h @@ -40,7 +40,7 @@ namespace JSC { class Register; - class JSVariableObject : public JSObject { + class JSVariableObject : public JSNonFinalObject { friend class JIT; public: @@ -54,11 +54,11 @@ namespace JSC { virtual bool isVariableObject() const; virtual bool isDynamicScope(bool& requiresDynamicChecks) const = 0; - Register& registerAt(int index) const { return d->registers[index]; } + WriteBarrier& registerAt(int index) const { return d->registers[index]; } static PassRefPtr createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: @@ -69,14 +69,14 @@ namespace JSC { struct JSVariableObjectData { JSVariableObjectData(SymbolTable* symbolTable, Register* registers) : symbolTable(symbolTable) - , registers(registers) + , registers(reinterpret_cast*>(registers)) { ASSERT(symbolTable); } SymbolTable* symbolTable; // Maps name -> offset from "r" in register file. - Register* registers; // "r" in the register file. - OwnArrayPtr registerArray; // Independent copy of registers, used when a variable object copies its registers out of the register file. + WriteBarrier* registers; // "r" in the register file. + OwnArrayPtr > registerArray; // Independent copy of registers, used when a variable object copies its registers out of the register file. private: JSVariableObjectData(const JSVariableObjectData&); @@ -84,19 +84,20 @@ namespace JSC { }; JSVariableObject(NonNullPassRefPtr structure, JSVariableObjectData* data) - : JSObject(structure) + : JSNonFinalObject(structure) , d(data) // Subclass owns this pointer. { + COMPILE_ASSERT(sizeof(WriteBarrier) == sizeof(Register), Register_should_be_same_size_as_WriteBarrier); } - PassOwnArrayPtr copyRegisterArray(Register* src, size_t count); - void setRegisters(Register* registers, PassOwnArrayPtr registerArray); + PassOwnArrayPtr > copyRegisterArray(JSGlobalData&, WriteBarrier* src, size_t count); + void setRegisters(WriteBarrier* registers, PassOwnArrayPtr > registerArray); bool symbolTableGet(const Identifier&, PropertySlot&); bool symbolTableGet(const Identifier&, PropertyDescriptor&); bool symbolTableGet(const Identifier&, PropertySlot&, bool& slotIsWriteable); - bool symbolTablePut(const Identifier&, JSValue); - bool symbolTablePutWithAttributes(const Identifier&, JSValue, unsigned attributes); + bool symbolTablePut(JSGlobalData&, const Identifier&, JSValue); + bool symbolTablePutWithAttributes(JSGlobalData&, const Identifier&, JSValue, unsigned attributes); JSVariableObjectData* d; }; @@ -105,7 +106,7 @@ namespace JSC { { SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl()); if (!entry.isNull()) { - slot.setRegisterSlot(®isterAt(entry.getIndex())); + slot.setValue(registerAt(entry.getIndex()).get()); return true; } return false; @@ -115,14 +116,14 @@ namespace JSC { { SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl()); if (!entry.isNull()) { - slot.setRegisterSlot(®isterAt(entry.getIndex())); + slot.setValue(registerAt(entry.getIndex()).get()); slotIsWriteable = !entry.isReadOnly(); return true; } return false; } - inline bool JSVariableObject::symbolTablePut(const Identifier& propertyName, JSValue value) + inline bool JSVariableObject::symbolTablePut(JSGlobalData& globalData, const Identifier& propertyName, JSValue value) { ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); @@ -131,11 +132,11 @@ namespace JSC { return false; if (entry.isReadOnly()) return true; - registerAt(entry.getIndex()) = value; + registerAt(entry.getIndex()).set(globalData, this, value); return true; } - inline bool JSVariableObject::symbolTablePutWithAttributes(const Identifier& propertyName, JSValue value, unsigned attributes) + inline bool JSVariableObject::symbolTablePutWithAttributes(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes) { ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); @@ -145,19 +146,20 @@ namespace JSC { SymbolTableEntry& entry = iter->second; ASSERT(!entry.isNull()); entry.setAttributes(attributes); - registerAt(entry.getIndex()) = value; + registerAt(entry.getIndex()).set(globalData, this, value); return true; } - inline PassOwnArrayPtr JSVariableObject::copyRegisterArray(Register* src, size_t count) + inline PassOwnArrayPtr > JSVariableObject::copyRegisterArray(JSGlobalData& globalData, WriteBarrier* src, size_t count) { - OwnArrayPtr registerArray = adoptArrayPtr(new Register[count]); - memcpy(registerArray.get(), src, count * sizeof(Register)); + OwnArrayPtr > registerArray = adoptArrayPtr(new WriteBarrier[count]); + for (size_t i = 0; i < count; i++) + registerArray[i].set(globalData, this, src[i].get()); return registerArray.release(); } - inline void JSVariableObject::setRegisters(Register* registers, PassOwnArrayPtr registerArray) + inline void JSVariableObject::setRegisters(WriteBarrier* registers, PassOwnArrayPtr > registerArray) { ASSERT(registerArray != d->registerArray); d->registerArray = registerArray; diff --git a/Source/JavaScriptCore/runtime/JSWrapperObject.h b/Source/JavaScriptCore/runtime/JSWrapperObject.h index 0b0d3fd..6d586df 100644 --- a/Source/JavaScriptCore/runtime/JSWrapperObject.h +++ b/Source/JavaScriptCore/runtime/JSWrapperObject.h @@ -28,7 +28,7 @@ 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 JSObject { + class JSWrapperObject : public JSNonFinalObject { protected: explicit JSWrapperObject(JSGlobalData&, NonNullPassRefPtr); @@ -38,7 +38,7 @@ namespace JSC { static PassRefPtr createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: @@ -51,7 +51,7 @@ namespace JSC { }; inline JSWrapperObject::JSWrapperObject(JSGlobalData& globalData, NonNullPassRefPtr structure) - : JSObject(structure) + : JSNonFinalObject(structure) { putAnonymousValue(globalData, 0, jsNull()); } diff --git a/Source/JavaScriptCore/runtime/JSZombie.cpp b/Source/JavaScriptCore/runtime/JSZombie.cpp index 8a36bda..c0c5f11 100644 --- a/Source/JavaScriptCore/runtime/JSZombie.cpp +++ b/Source/JavaScriptCore/runtime/JSZombie.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "JSZombie.h" #include "ClassInfo.h" +#include "ScopeChain.h" #if ENABLE(JSC_ZOMBIES) @@ -37,7 +38,7 @@ Structure* JSZombie::leakedZombieStructure() { static Structure* structure = 0; if (!structure) { Structure::startIgnoringLeaks(); - structure = Structure::create(jsNull(), TypeInfo(UnspecifiedType), 0).leakRef(); + structure = Structure::create(jsNull(), TypeInfo(UnspecifiedType), 0, &info).leakRef(); Structure::stopIgnoringLeaks(); } return structure; diff --git a/Source/JavaScriptCore/runtime/JSZombie.h b/Source/JavaScriptCore/runtime/JSZombie.h index da45699..5fe6b6d 100644 --- a/Source/JavaScriptCore/runtime/JSZombie.h +++ b/Source/JavaScriptCore/runtime/JSZombie.h @@ -37,9 +37,10 @@ public: : JSCell(structure) , m_oldInfo(oldInfo) { + ASSERT(inherits(&s_info)); } + virtual bool isZombie() const { return true; } - virtual const ClassInfo* classInfo() const { return &s_info; } static Structure* leakedZombieStructure(); virtual bool isGetterSetter() const { ASSERT_NOT_REACHED(); return false; } @@ -65,7 +66,13 @@ public: virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&) { ASSERT_NOT_REACHED(); return false; } virtual bool getOwnPropertySlot(ExecState*, unsigned, PropertySlot&) { ASSERT_NOT_REACHED(); return false; } + static PassRefPtr createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); + } + static const ClassInfo s_info; + private: const ClassInfo* m_oldInfo; }; diff --git a/Source/JavaScriptCore/runtime/Lookup.cpp b/Source/JavaScriptCore/runtime/Lookup.cpp index 3c7d4be..307bceb 100644 --- a/Source/JavaScriptCore/runtime/Lookup.cpp +++ b/Source/JavaScriptCore/runtime/Lookup.cpp @@ -22,7 +22,6 @@ #include "Executable.h" #include "JSFunction.h" -#include "PrototypeFunction.h" namespace JSC { @@ -77,14 +76,14 @@ void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* WriteBarrierBase* location = thisObj->getDirectLocation(propertyName); if (!location) { - NativeFunctionWrapper* function; + JSFunction* function; JSGlobalObject* globalObject = asGlobalObject(thisObj->getAnonymousValue(0).asCell()); #if ENABLE(JIT) && ENABLE(JIT_OPTIMIZE_NATIVE_CALL) if (entry->generator()) - function = new (exec) NativeFunctionWrapper(exec, globalObject, globalObject->prototypeFunctionStructure(), entry->functionLength(), propertyName, exec->globalData().getHostFunction(entry->function(), entry->generator())); + function = new (exec) JSFunction(exec, globalObject, globalObject->functionStructure(), entry->functionLength(), propertyName, exec->globalData().getHostFunction(entry->function(), entry->generator())); else #endif - function = new (exec) NativeFunctionWrapper(exec, globalObject, globalObject->prototypeFunctionStructure(), entry->functionLength(), propertyName, entry->function()); + function = new (exec) JSFunction(exec, globalObject, globalObject->functionStructure(), entry->functionLength(), propertyName, entry->function()); thisObj->putDirectFunction(exec->globalData(), propertyName, function, entry->attributes()); location = thisObj->getDirectLocation(propertyName); diff --git a/Source/JavaScriptCore/runtime/MachineStackMarker.cpp b/Source/JavaScriptCore/runtime/MachineStackMarker.cpp index 4430947..4614a7c 100644 --- a/Source/JavaScriptCore/runtime/MachineStackMarker.cpp +++ b/Source/JavaScriptCore/runtime/MachineStackMarker.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2007 Eric Seidel + * Copyright (C) 2009 Acision BV. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -70,6 +71,13 @@ #include #endif +#if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN) +#include +#ifndef SA_RESTART +#error MachineStackMarker requires SA_RESTART +#endif +#endif + #endif namespace JSC { @@ -92,6 +100,17 @@ UNUSED_PARAM(end); typedef mach_port_t PlatformThread; #elif OS(WINDOWS) typedef HANDLE PlatformThread; +#elif USE(PTHREADS) +typedef pthread_t PlatformThread; +static const int SigThreadSuspendResume = SIGUSR2; + +static void pthreadSignalHandlerSuspendResume(int signo) +{ + sigset_t signalSet; + sigemptyset(&signalSet); + sigaddset(&signalSet, SigThreadSuspendResume); + sigsuspend(&signalSet); +} #endif class MachineStackMarker::Thread { @@ -101,6 +120,18 @@ public: , platformThread(platThread) , stackBase(base) { +#if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN) + struct sigaction action; + action.sa_handler = pthreadSignalHandlerSuspendResume; + sigemptyset(&action.sa_mask); + action.sa_flags = SA_RESTART; + sigaction(SigThreadSuspendResume, &action, 0); + + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, SigThreadSuspendResume); + pthread_sigmask(SIG_UNBLOCK, &mask, 0); +#endif } Thread* next; @@ -145,6 +176,8 @@ static inline PlatformThread getCurrentPlatformThread() return pthread_mach_thread_np(pthread_self()); #elif OS(WINDOWS) return pthread_getw32threadhandle_np(pthread_self()); +#elif USE(PTHREADS) + return pthread_self(); #endif } @@ -245,6 +278,8 @@ static inline void suspendThread(const PlatformThread& platformThread) thread_suspend(platformThread); #elif OS(WINDOWS) SuspendThread(platformThread); +#elif USE(PTHREADS) + pthread_kill(platformThread, SigThreadSuspendResume); #else #error Need a way to suspend threads on this platform #endif @@ -256,6 +291,8 @@ static inline void resumeThread(const PlatformThread& platformThread) thread_resume(platformThread); #elif OS(WINDOWS) ResumeThread(platformThread); +#elif USE(PTHREADS) + pthread_kill(platformThread, SigThreadSuspendResume); #else #error Need a way to resume threads on this platform #endif @@ -281,6 +318,8 @@ typedef arm_thread_state_t PlatformThreadRegisters; #elif OS(WINDOWS) && CPU(X86) typedef CONTEXT PlatformThreadRegisters; +#elif USE(PTHREADS) +typedef pthread_attr_t PlatformThreadRegisters; #else #error Need a thread register struct for this platform #endif @@ -321,6 +360,16 @@ static size_t getPlatformThreadRegisters(const PlatformThread& platformThread, P regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS; GetThreadContext(platformThread, ®s); return sizeof(CONTEXT); +#elif USE(PTHREADS) + pthread_attr_init(®s); +#if HAVE(PTHREAD_NP_H) || OS(NETBSD) + // e.g. on FreeBSD 5.4, neundorf@kde.org + pthread_attr_get_np(platformThread, ®s); +#else + // FIXME: this function is non-portable; other POSIX systems may have different np alternatives + pthread_getattr_np(platformThread, ®s); +#endif + return 0; #else #error Need a way to get thread registers on this platform #endif @@ -361,11 +410,27 @@ static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs) // end OS(DARWIN) #elif CPU(X86) && OS(WINDOWS) return reinterpret_cast((uintptr_t) regs.Esp); +#elif USE(PTHREADS) + void* stackBase = 0; + size_t stackSize = 0; + int rc = pthread_attr_getstack(®s, &stackBase, &stackSize); + (void)rc; // FIXME: Deal with error code somehow? Seems fatal. + ASSERT(stackBase); + return static_cast(stackBase) + stackSize; #else #error Need a way to get the stack pointer for another thread on this platform #endif } +static void freePlatformThreadRegisters(PlatformThreadRegisters& regs) +{ +#if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN) + pthread_attr_destroy(®s); +#else + UNUSED_PARAM(regs); +#endif +} + void MachineStackMarker::markOtherThreadConservatively(ConservativeSet& conservativeSet, Thread* thread) { suspendThread(thread->platformThread); @@ -382,6 +447,8 @@ void MachineStackMarker::markOtherThreadConservatively(ConservativeSet& conserva conservativeSet.add(stackPointer, stackBase); resumeThread(thread->platformThread); + + freePlatformThreadRegisters(regs); } #endif diff --git a/Source/JavaScriptCore/runtime/MarkedBlock.cpp b/Source/JavaScriptCore/runtime/MarkedBlock.cpp index 16053f2..48dda4c 100644 --- a/Source/JavaScriptCore/runtime/MarkedBlock.cpp +++ b/Source/JavaScriptCore/runtime/MarkedBlock.cpp @@ -27,33 +27,38 @@ #include "MarkedBlock.h" #include "JSCell.h" +#include "ScopeChain.h" namespace JSC { -MarkedBlock* MarkedBlock::create(JSGlobalData* globalData) +MarkedBlock* MarkedBlock::create(JSGlobalData* globalData, size_t cellSize) { - PageAllocationAligned allocation = PageAllocationAligned::allocate(BLOCK_SIZE, BLOCK_SIZE, OSAllocator::JSGCHeapPages); + PageAllocationAligned allocation = PageAllocationAligned::allocate(blockSize, blockSize, OSAllocator::JSGCHeapPages); if (!static_cast(allocation)) CRASH(); - return new (allocation.base()) MarkedBlock(allocation, globalData); + return new (allocation.base()) MarkedBlock(allocation, globalData, cellSize); } void MarkedBlock::destroy(MarkedBlock* block) { - for (size_t i = 0; i < CELLS_PER_BLOCK; ++i) - reinterpret_cast(&block->cells[i])->~JSCell(); + for (size_t i = block->firstAtom(); i < block->m_endAtom; i += block->m_atomsPerCell) + reinterpret_cast(&block->atoms()[i])->~JSCell(); block->m_allocation.deallocate(); } -MarkedBlock::MarkedBlock(const PageAllocationAligned& allocation, JSGlobalData* globalData) - : m_allocation(allocation) +MarkedBlock::MarkedBlock(const PageAllocationAligned& allocation, JSGlobalData* globalData, size_t cellSize) + : m_nextAtom(firstAtom()) + , m_allocation(allocation) , m_heap(&globalData->heap) + , m_prev(0) + , m_next(0) { - marked.set(CELLS_PER_BLOCK - 1); + m_atomsPerCell = (cellSize + atomSize - 1) / atomSize; + m_endAtom = atomsPerBlock - m_atomsPerCell + 1; Structure* dummyMarkableCellStructure = globalData->dummyMarkableCellStructure.get(); - for (size_t i = 0; i < CELLS_PER_BLOCK; ++i) - new (&cells[i]) JSCell(dummyMarkableCellStructure); + for (size_t i = firstAtom(); i < m_endAtom; i += m_atomsPerCell) + new (&atoms()[i]) JSCell(dummyMarkableCellStructure); } void MarkedBlock::sweep() @@ -62,17 +67,17 @@ void MarkedBlock::sweep() Structure* dummyMarkableCellStructure = m_heap->globalData()->dummyMarkableCellStructure.get(); #endif - for (size_t i = 0; i < CELLS_PER_BLOCK; ++i) { - if (marked.get(i)) + for (size_t i = firstAtom(); i < m_endAtom; i += m_atomsPerCell) { + if (m_marks.get(i)) continue; - JSCell* cell = reinterpret_cast(&cells[i]); + JSCell* cell = reinterpret_cast(&atoms()[i]); #if ENABLE(JSC_ZOMBIES) if (!cell->isZombie()) { const ClassInfo* info = cell->classInfo(); cell->~JSCell(); new (cell) JSZombie(info, JSZombie::leakedZombieStructure()); - marked.set(i); + m_marks.set(i); } #else cell->~JSCell(); diff --git a/Source/JavaScriptCore/runtime/MarkedBlock.h b/Source/JavaScriptCore/runtime/MarkedBlock.h index f726c25..e80fe82 100644 --- a/Source/JavaScriptCore/runtime/MarkedBlock.h +++ b/Source/JavaScriptCore/runtime/MarkedBlock.h @@ -23,89 +23,108 @@ #define MarkedBlock_h #include -#include #include -#define ASSERT_CLASS_FITS_IN_CELL(class) COMPILE_ASSERT(sizeof(class) <= MarkedBlock::CELL_SIZE, class_fits_in_cell) - namespace JSC { class Heap; class JSCell; class JSGlobalData; - class MarkedBlock { -#if OS(WINCE) || OS(SYMBIAN) || PLATFORM(BREWMP) - static const size_t BLOCK_SIZE = 64 * 1024; // 64k -#else - static const size_t BLOCK_SIZE = 256 * 1024; // 256k -#endif - - static const size_t BLOCK_OFFSET_MASK = BLOCK_SIZE - 1; - static const size_t BLOCK_MASK = ~BLOCK_OFFSET_MASK; - static const size_t MINIMUM_CELL_SIZE = 64; - static const size_t CELL_ARRAY_LENGTH = (MINIMUM_CELL_SIZE / sizeof(double)) + (MINIMUM_CELL_SIZE % sizeof(double) != 0 ? sizeof(double) : 0); - public: - // This is still public for now, for use in assertions. - static const size_t CELL_SIZE = CELL_ARRAY_LENGTH * sizeof(double); - private: - static const size_t SMALL_CELL_SIZE = CELL_SIZE / 2; - static const size_t CELL_MASK = CELL_SIZE - 1; - static const size_t CELL_ALIGN_MASK = ~CELL_MASK; - static const size_t BITS_PER_BLOCK = BLOCK_SIZE / CELL_SIZE; - static const size_t CELLS_PER_BLOCK = (BLOCK_SIZE - sizeof(Heap*) - sizeof(WTF::Bitmap)) / CELL_SIZE; // Division rounds down intentionally. - - struct CollectorCell { - FixedArray memory; - }; + typedef uintptr_t Bits; + + static const size_t KB = 1024; - // Cell size needs to be a power of two for CELL_MASK to be valid. - COMPILE_ASSERT(!(sizeof(CollectorCell) % 2), Collector_cell_size_is_power_of_two); + // Efficient implementation that takes advantage of powers of two. + template inline size_t roundUpToMultipleOf(size_t x) + { + COMPILE_ASSERT(divisor && !(divisor & (divisor - 1)), divisor_is_a_power_of_two); + + size_t remainderMask = divisor - 1; + return (x + remainderMask) & ~remainderMask; + } + class MarkedBlock { public: - static MarkedBlock* create(JSGlobalData*); + static const size_t atomSize = sizeof(double); // Ensures natural alignment for all built-in types. + + static MarkedBlock* create(JSGlobalData*, size_t cellSize); static void destroy(MarkedBlock*); - static bool isCellAligned(const void*); + static bool isAtomAligned(const void*); static MarkedBlock* blockFor(const void*); + static size_t firstAtom(); Heap* heap() const; + + void setPrev(MarkedBlock*); + void setNext(MarkedBlock*); + MarkedBlock* prev() const; + MarkedBlock* next() const; - void* allocate(size_t& nextCell); + void* allocate(); + void reset(); void sweep(); bool isEmpty(); void clearMarks(); size_t markCount(); + + size_t cellSize(); + size_t size(); size_t capacity(); - size_t cellNumber(const void*); + bool contains(const void*); + size_t atomNumber(const void*); bool isMarked(const void*); bool testAndSetMarked(const void*); void setMarked(const void*); template void forEach(Functor&); - FixedArray cells; - private: - MarkedBlock(const PageAllocationAligned&, JSGlobalData*); + static const size_t blockSize = 16 * KB; + static const size_t blockMask = ~(blockSize - 1); // blockSize must be a power of two. + + static const size_t atomMask = ~(atomSize - 1); // atomSize must be a power of two. + + static const size_t atomsPerBlock = blockSize / atomSize; + + typedef char Atom[atomSize]; - WTF::Bitmap marked; + MarkedBlock(const PageAllocationAligned&, JSGlobalData*, size_t cellSize); + Atom* atoms(); + + size_t m_nextAtom; + size_t m_endAtom; // This is a fuzzy end. Always test for < m_endAtom. + size_t m_atomsPerCell; + WTF::Bitmap m_marks; PageAllocationAligned m_allocation; Heap* m_heap; + MarkedBlock* m_prev; + MarkedBlock* m_next; }; - inline bool MarkedBlock::isCellAligned(const void* p) + inline size_t MarkedBlock::firstAtom() + { + return roundUpToMultipleOf(sizeof(MarkedBlock)) / atomSize; + } + + inline MarkedBlock::Atom* MarkedBlock::atoms() { - return !((intptr_t)(p) & CELL_MASK); + return reinterpret_cast(this); + } + + inline bool MarkedBlock::isAtomAligned(const void* p) + { + return !((intptr_t)(p) & ~atomMask); } inline MarkedBlock* MarkedBlock::blockFor(const void* p) { - return reinterpret_cast(reinterpret_cast(p) & BLOCK_MASK); + return reinterpret_cast(reinterpret_cast(p) & blockMask); } inline Heap* MarkedBlock::heap() const @@ -113,62 +132,98 @@ namespace JSC { return m_heap; } + inline void MarkedBlock::setPrev(MarkedBlock* prev) + { + m_prev = prev; + } + + inline void MarkedBlock::setNext(MarkedBlock* next) + { + m_next = next; + } + + inline MarkedBlock* MarkedBlock::prev() const + { + return m_prev; + } + + inline MarkedBlock* MarkedBlock::next() const + { + return m_next; + } + + inline void MarkedBlock::reset() + { + m_nextAtom = firstAtom(); + } + inline bool MarkedBlock::isEmpty() { - marked.clear(CELLS_PER_BLOCK - 1); // Clear the always-set last bit to avoid confusing isEmpty(). - bool result = marked.isEmpty(); - marked.set(CELLS_PER_BLOCK - 1); - return result; + return m_marks.isEmpty(); } inline void MarkedBlock::clearMarks() { - // allocate() assumes that the last mark bit is always set. - marked.clearAll(); - marked.set(CELLS_PER_BLOCK - 1); + m_marks.clearAll(); } inline size_t MarkedBlock::markCount() { - return marked.count() - 1; // The last mark bit is always set. + return m_marks.count(); + } + + inline size_t MarkedBlock::cellSize() + { + return m_atomsPerCell * atomSize; } inline size_t MarkedBlock::size() { - return markCount() * CELL_SIZE; + return markCount() * cellSize(); } inline size_t MarkedBlock::capacity() { - return BLOCK_SIZE; + return m_allocation.size(); + } + + inline bool MarkedBlock::contains(const void* p) + { + // Since we mark the first atom of every cell when allocating and/or + // marking, any pointer to a marked atom points to the head of a valid, + // live cell. Checking the mark bit guards against reviving an object + // in a zombie state. + + ASSERT(p && isAtomAligned(p)); + return isMarked(p); } - inline size_t MarkedBlock::cellNumber(const void* cell) + inline size_t MarkedBlock::atomNumber(const void* p) { - return (reinterpret_cast(cell) & BLOCK_OFFSET_MASK) / CELL_SIZE; + return (reinterpret_cast(p) - reinterpret_cast(this)) / atomSize; } - inline bool MarkedBlock::isMarked(const void* cell) + inline bool MarkedBlock::isMarked(const void* p) { - return marked.get(cellNumber(cell)); + return m_marks.get(atomNumber(p)); } - inline bool MarkedBlock::testAndSetMarked(const void* cell) + inline bool MarkedBlock::testAndSetMarked(const void* p) { - return marked.testAndSet(cellNumber(cell)); + return m_marks.testAndSet(atomNumber(p)); } - inline void MarkedBlock::setMarked(const void* cell) + inline void MarkedBlock::setMarked(const void* p) { - marked.set(cellNumber(cell)); + m_marks.set(atomNumber(p)); } template inline void MarkedBlock::forEach(Functor& functor) { - for (size_t i = 0; i < CELLS_PER_BLOCK - 1; ++i) { // The last cell is a dummy place-holder. - if (!marked.get(i)) + for (size_t i = firstAtom(); i < m_endAtom; i += m_atomsPerCell) { + if (!m_marks.get(i)) continue; - functor(reinterpret_cast(&cells[i])); + functor(reinterpret_cast(&atoms()[i])); } } diff --git a/Source/JavaScriptCore/runtime/MarkedSpace.cpp b/Source/JavaScriptCore/runtime/MarkedSpace.cpp index 2f8075d..15ab514 100644 --- a/Source/JavaScriptCore/runtime/MarkedSpace.cpp +++ b/Source/JavaScriptCore/runtime/MarkedSpace.cpp @@ -24,6 +24,7 @@ #include "JSCell.h" #include "JSGlobalData.h" #include "JSLock.h" +#include "ScopeChain.h" namespace JSC { @@ -34,105 +35,125 @@ MarkedSpace::MarkedSpace(JSGlobalData* globalData) , m_highWaterMark(0) , m_globalData(globalData) { - allocateBlock(); + for (size_t cellSize = preciseStep; cellSize <= preciseCutoff; cellSize += preciseStep) + sizeClassFor(cellSize).cellSize = cellSize; } void MarkedSpace::destroy() { - clearMarks(); // Make sure weak pointers appear dead during destruction. - - while (m_heap.blocks.size()) - freeBlock(0); - m_heap.blocks.clear(); + clearMarks(); + shrink(); + ASSERT(!size()); } -NEVER_INLINE MarkedBlock* MarkedSpace::allocateBlock() +MarkedBlock* MarkedSpace::allocateBlock(SizeClass& sizeClass) { - MarkedBlock* block = MarkedBlock::create(globalData()); - m_heap.blocks.append(block); + MarkedBlock* block = MarkedBlock::create(globalData(), sizeClass.cellSize); + sizeClass.blockList.append(block); + sizeClass.nextBlock = block; + m_blocks.add(block); + return block; } -NEVER_INLINE void MarkedSpace::freeBlock(size_t block) +void MarkedSpace::freeBlocks(DoublyLinkedList& blocks) { - MarkedBlock::destroy(m_heap.blocks[block]); + MarkedBlock* next; + for (MarkedBlock* block = blocks.head(); block; block = next) { + next = block->next(); - // swap with the last block so we compact as we go - m_heap.blocks[block] = m_heap.blocks.last(); - m_heap.blocks.removeLast(); + blocks.remove(block); + m_blocks.remove(block); + MarkedBlock::destroy(block); + } } -void* MarkedSpace::allocate(size_t) +void* MarkedSpace::allocateFromSizeClass(SizeClass& sizeClass) { - do { - ASSERT(m_heap.nextBlock < m_heap.blocks.size()); - MarkedBlock* block = m_heap.collectorBlock(m_heap.nextBlock); - if (void* result = block->allocate(m_heap.nextCell)) + for (MarkedBlock*& block = sizeClass.nextBlock ; block; block = block->next()) { + if (void* result = block->allocate()) return result; m_waterMark += block->capacity(); - } while (++m_heap.nextBlock != m_heap.blocks.size()); + } if (m_waterMark < m_highWaterMark) - return allocateBlock()->allocate(m_heap.nextCell); + return allocateBlock(sizeClass)->allocate(); return 0; } void MarkedSpace::shrink() { - for (size_t i = 0; i != m_heap.blocks.size() && m_heap.blocks.size() > 1; ) { // We assume at least one block exists at all times. - if (m_heap.collectorBlock(i)->isEmpty()) { - freeBlock(i); - } else - ++i; + // We record a temporary list of empties to avoid modifying m_blocks while iterating it. + DoublyLinkedList empties; + + BlockIterator end = m_blocks.end(); + for (BlockIterator it = m_blocks.begin(); it != end; ++it) { + MarkedBlock* block = *it; + if (block->isEmpty()) { + SizeClass& sizeClass = sizeClassFor(block->cellSize()); + sizeClass.blockList.remove(block); + sizeClass.nextBlock = sizeClass.blockList.head(); + empties.append(block); + } } + + freeBlocks(empties); + ASSERT(empties.isEmpty()); } void MarkedSpace::clearMarks() { - for (size_t i = 0; i < m_heap.blocks.size(); ++i) - m_heap.collectorBlock(i)->clearMarks(); + BlockIterator end = m_blocks.end(); + for (BlockIterator it = m_blocks.begin(); it != end; ++it) + (*it)->clearMarks(); } void MarkedSpace::sweep() { - for (size_t i = 0; i < m_heap.blocks.size(); ++i) - m_heap.collectorBlock(i)->sweep(); + BlockIterator end = m_blocks.end(); + for (BlockIterator it = m_blocks.begin(); it != end; ++it) + (*it)->sweep(); } size_t MarkedSpace::objectCount() const { size_t result = 0; - for (size_t i = 0; i < m_heap.blocks.size(); ++i) - result += m_heap.collectorBlock(i)->markCount(); + BlockIterator end = m_blocks.end(); + for (BlockIterator it = m_blocks.begin(); it != end; ++it) + result += (*it)->markCount(); return result; } size_t MarkedSpace::size() const { size_t result = 0; - for (size_t i = 0; i < m_heap.blocks.size(); ++i) - result += m_heap.collectorBlock(i)->size(); + BlockIterator end = m_blocks.end(); + for (BlockIterator it = m_blocks.begin(); it != end; ++it) + result += (*it)->size(); return result; } size_t MarkedSpace::capacity() const { size_t result = 0; - for (size_t i = 0; i < m_heap.blocks.size(); ++i) - result += m_heap.collectorBlock(i)->capacity(); + BlockIterator end = m_blocks.end(); + for (BlockIterator it = m_blocks.begin(); it != end; ++it) + result += (*it)->capacity(); return result; } void MarkedSpace::reset() { - m_heap.nextCell = 0; - m_heap.nextBlock = 0; m_waterMark = 0; -#if ENABLE(JSC_ZOMBIES) - sweep(); -#endif + + for (size_t cellSize = preciseStep; cellSize <= preciseCutoff; cellSize += preciseStep) + sizeClassFor(cellSize).reset(); + + BlockIterator end = m_blocks.end(); + for (BlockIterator it = m_blocks.begin(); it != end; ++it) + (*it)->reset(); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/MarkedSpace.h b/Source/JavaScriptCore/runtime/MarkedSpace.h index fcb93b7..2e88887 100644 --- a/Source/JavaScriptCore/runtime/MarkedSpace.h +++ b/Source/JavaScriptCore/runtime/MarkedSpace.h @@ -26,11 +26,15 @@ #include "MarkedBlock.h" #include "PageAllocationAligned.h" #include +#include #include -#include +#include #include #include +#define ASSERT_CLASS_FITS_IN_CELL(class) COMPILE_ASSERT(sizeof(class) <= MarkedSpace::maxCellSize, class_fits_in_cell) +#define ASSERT_CLASS_FILLS_CELL(class) COMPILE_ASSERT(sizeof(class) == MarkedSpace::maxCellSize, class_fills_cell) + namespace JSC { class Heap; @@ -40,26 +44,12 @@ namespace JSC { class MarkStack; class WeakGCHandle; - struct CollectorHeap { - CollectorHeap() - : nextBlock(0) - , nextCell(0) - { - } - - MarkedBlock* collectorBlock(size_t index) const - { - return blocks[index]; - } - - size_t nextBlock; - size_t nextCell; - Vector blocks; - }; - class MarkedSpace { WTF_MAKE_NONCOPYABLE(MarkedSpace); public: + // Currently public for use in assertions. + static const size_t maxCellSize = 64; + static Heap* heap(JSCell*); static bool isMarked(const JSCell*); @@ -91,12 +81,32 @@ namespace JSC { template void forEach(Functor&); private: - NEVER_INLINE MarkedBlock* allocateBlock(); - NEVER_INLINE void freeBlock(size_t); + // [ 8, 16... 64 ] + static const size_t preciseStep = MarkedBlock::atomSize; + static const size_t preciseCutoff = maxCellSize; + static const size_t preciseCount = preciseCutoff / preciseStep; + + typedef HashSet::iterator BlockIterator; + + struct SizeClass { + SizeClass(); + void reset(); + + MarkedBlock* nextBlock; + DoublyLinkedList blockList; + size_t cellSize; + }; + + MarkedBlock* allocateBlock(SizeClass&); + void freeBlocks(DoublyLinkedList&); + + SizeClass& sizeClassFor(size_t); + void* allocateFromSizeClass(SizeClass&); void clearMarks(MarkedBlock*); - CollectorHeap m_heap; + SizeClass m_preciseSizeClasses[preciseCount]; + HashSet m_blocks; size_t m_waterMark; size_t m_highWaterMark; JSGlobalData* m_globalData; @@ -124,31 +134,32 @@ namespace JSC { inline bool MarkedSpace::contains(const void* x) { - if (!MarkedBlock::isCellAligned(x)) + if (!MarkedBlock::isAtomAligned(x)) return false; MarkedBlock* block = MarkedBlock::blockFor(x); - if (!block) + if (!block || !m_blocks.contains(block)) return false; - size_t size = m_heap.blocks.size(); - for (size_t i = 0; i < size; i++) { - if (block != m_heap.collectorBlock(i)) - continue; - - // x is a pointer into the heap. Now, verify that the cell it - // points to is live. (If the cell is dead, we must not mark it, - // since that would revive it in a zombie state.) - return block->isMarked(x); - } - - return false; + return block->contains(x); } template inline void MarkedSpace::forEach(Functor& functor) { - for (size_t i = 0; i < m_heap.blocks.size(); ++i) - m_heap.collectorBlock(i)->forEach(functor); + BlockIterator end = m_blocks.end(); + for (BlockIterator it = m_blocks.begin(); it != end; ++it) + (*it)->forEach(functor); + } + + inline MarkedSpace::SizeClass::SizeClass() + : nextBlock(0) + , cellSize(0) + { + } + + inline void MarkedSpace::SizeClass::reset() + { + nextBlock = blockList.head(); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/MathObject.cpp b/Source/JavaScriptCore/runtime/MathObject.cpp index c79316b..7b856a1 100644 --- a/Source/JavaScriptCore/runtime/MathObject.cpp +++ b/Source/JavaScriptCore/runtime/MathObject.cpp @@ -61,7 +61,7 @@ namespace JSC { // ------------------------------ MathObject -------------------------------- -const ClassInfo MathObject::info = { "Math", 0, 0, ExecState::mathTable }; +const ClassInfo MathObject::s_info = { "Math", &JSObjectWithGlobalObject::s_info, 0, ExecState::mathTable }; /* Source for MathObject.lut.h @begin mathTable @@ -89,11 +89,13 @@ const ClassInfo MathObject::info = { "Math", 0, 0, ExecState::mathTable }; MathObject::MathObject(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure) : JSObjectWithGlobalObject(globalObject, structure) { + ASSERT(inherits(&s_info)); + putDirectWithoutTransition(exec->globalData(), Identifier(exec, "E"), jsNumber(exp(1.0)), DontDelete | DontEnum | ReadOnly); putDirectWithoutTransition(exec->globalData(), Identifier(exec, "LN2"), jsNumber(log(2.0)), DontDelete | DontEnum | ReadOnly); putDirectWithoutTransition(exec->globalData(), Identifier(exec, "LN10"), jsNumber(log(10.0)), DontDelete | DontEnum | ReadOnly); putDirectWithoutTransition(exec->globalData(), Identifier(exec, "LOG2E"), jsNumber(1.0 / log(2.0)), DontDelete | DontEnum | ReadOnly); - putDirectWithoutTransition(exec->globalData(), Identifier(exec, "LOG10E"), jsNumber(1.0 / log(10.0)), DontDelete | DontEnum | ReadOnly); + putDirectWithoutTransition(exec->globalData(), Identifier(exec, "LOG10E"), jsNumber(0.4342944819032518), DontDelete | DontEnum | ReadOnly); // See ECMA-262 15.8.1.5 putDirectWithoutTransition(exec->globalData(), Identifier(exec, "PI"), jsNumber(piDouble), DontDelete | DontEnum | ReadOnly); putDirectWithoutTransition(exec->globalData(), Identifier(exec, "SQRT1_2"), jsNumber(sqrt(0.5)), DontDelete | DontEnum | ReadOnly); putDirectWithoutTransition(exec->globalData(), Identifier(exec, "SQRT2"), jsNumber(sqrt(2.0)), DontDelete | DontEnum | ReadOnly); diff --git a/Source/JavaScriptCore/runtime/MathObject.h b/Source/JavaScriptCore/runtime/MathObject.h index 31fa2fe..86e7951 100644 --- a/Source/JavaScriptCore/runtime/MathObject.h +++ b/Source/JavaScriptCore/runtime/MathObject.h @@ -32,12 +32,11 @@ namespace JSC { virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); - virtual const ClassInfo* classInfo() const { return &info; } - static const ClassInfo info; + static const ClassInfo s_info; static PassRefPtr createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: diff --git a/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp b/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp index 421eecf..7949dd9 100644 --- a/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp +++ b/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp @@ -30,11 +30,13 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(NativeErrorConstructor); -const ClassInfo NativeErrorConstructor::info = { "Function", &InternalFunction::info, 0, 0 }; +const ClassInfo NativeErrorConstructor::s_info = { "Function", &InternalFunction::s_info, 0, 0 }; NativeErrorConstructor::NativeErrorConstructor(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure, NonNullPassRefPtr prototypeStructure, const UString& nameAndMessage) : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, nameAndMessage)) { + ASSERT(inherits(&s_info)); + NativeErrorPrototype* prototype = new (exec) NativeErrorPrototype(exec, globalObject, prototypeStructure, nameAndMessage, this); putDirect(exec->globalData(), exec->propertyNames().length, jsNumber(1), DontDelete | ReadOnly | DontEnum); // ECMA 15.11.7.5 diff --git a/Source/JavaScriptCore/runtime/NativeErrorConstructor.h b/Source/JavaScriptCore/runtime/NativeErrorConstructor.h index 1ff8207..e4978cc 100644 --- a/Source/JavaScriptCore/runtime/NativeErrorConstructor.h +++ b/Source/JavaScriptCore/runtime/NativeErrorConstructor.h @@ -33,7 +33,12 @@ namespace JSC { public: NativeErrorConstructor(ExecState*, JSGlobalObject*, NonNullPassRefPtr structure, NonNullPassRefPtr prototypeStructure, const UString&); - static const ClassInfo info; + static const ClassInfo s_info; + + static PassRefPtr createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); + } Structure* errorStructure() { return m_errorStructure.get(); } @@ -41,8 +46,6 @@ namespace JSC { virtual ConstructType getConstructData(ConstructData&); virtual CallType getCallData(CallData&); - virtual const ClassInfo* classInfo() const { return &info; } - RefPtr m_errorStructure; }; diff --git a/Source/JavaScriptCore/runtime/NativeFunctionWrapper.h b/Source/JavaScriptCore/runtime/NativeFunctionWrapper.h deleted file mode 100644 index d4eeb3b..0000000 --- a/Source/JavaScriptCore/runtime/NativeFunctionWrapper.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2009 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 NativeFunctionWrapper_h -#define NativeFunctionWrapper_h - -namespace JSC { -#if ENABLE(JIT) && ENABLE(JIT_OPTIMIZE_NATIVE_CALL) - class JSFunction; - typedef JSFunction NativeFunctionWrapper; -#else - class PrototypeFunction; - typedef PrototypeFunction NativeFunctionWrapper; -#endif -} - -#endif diff --git a/Source/JavaScriptCore/runtime/NumberConstructor.cpp b/Source/JavaScriptCore/runtime/NumberConstructor.cpp index 7cec875..3e4d6c7 100644 --- a/Source/JavaScriptCore/runtime/NumberConstructor.cpp +++ b/Source/JavaScriptCore/runtime/NumberConstructor.cpp @@ -42,7 +42,7 @@ static JSValue numberConstructorMinValue(ExecState*, JSValue, const Identifier&) namespace JSC { -const ClassInfo NumberConstructor::info = { "Function", &InternalFunction::info, 0, ExecState::numberTable }; +const ClassInfo NumberConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::numberTable }; /* Source for NumberConstructor.lut.h @begin numberTable @@ -55,8 +55,10 @@ const ClassInfo NumberConstructor::info = { "Function", &InternalFunction::info, */ NumberConstructor::NumberConstructor(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure, NumberPrototype* numberPrototype) - : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, numberPrototype->info.className)) + : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, numberPrototype->s_info.className)) { + ASSERT(inherits(&s_info)); + // Number.Prototype putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, numberPrototype, DontEnum | DontDelete | ReadOnly); diff --git a/Source/JavaScriptCore/runtime/NumberConstructor.h b/Source/JavaScriptCore/runtime/NumberConstructor.h index d8a2593..aaf7c32 100644 --- a/Source/JavaScriptCore/runtime/NumberConstructor.h +++ b/Source/JavaScriptCore/runtime/NumberConstructor.h @@ -35,11 +35,11 @@ namespace JSC { virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); JSValue getValueProperty(ExecState*, int token) const; - static const ClassInfo info; + static const ClassInfo s_info; static PassRefPtr createStructure(JSValue proto) { - return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } enum { NaNValue, NegInfinity, PosInfinity, MaxValue, MinValue }; @@ -50,8 +50,6 @@ namespace JSC { private: virtual ConstructType getConstructData(ConstructData&); virtual CallType getCallData(CallData&); - - virtual const ClassInfo* classInfo() const { return &info; } }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/NumberObject.cpp b/Source/JavaScriptCore/runtime/NumberObject.cpp index 603c2f0..4408673 100644 --- a/Source/JavaScriptCore/runtime/NumberObject.cpp +++ b/Source/JavaScriptCore/runtime/NumberObject.cpp @@ -29,11 +29,12 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(NumberObject); -const ClassInfo NumberObject::info = { "Number", 0, 0, 0 }; +const ClassInfo NumberObject::s_info = { "Number", &JSWrapperObject::s_info, 0, 0 }; NumberObject::NumberObject(JSGlobalData& globalData, NonNullPassRefPtr structure) : JSWrapperObject(globalData, structure) { + ASSERT(inherits(&s_info)); } JSValue NumberObject::getJSNumber() diff --git a/Source/JavaScriptCore/runtime/NumberObject.h b/Source/JavaScriptCore/runtime/NumberObject.h index 044f490..8a80382 100644 --- a/Source/JavaScriptCore/runtime/NumberObject.h +++ b/Source/JavaScriptCore/runtime/NumberObject.h @@ -29,19 +29,17 @@ namespace JSC { public: explicit NumberObject(JSGlobalData&, NonNullPassRefPtr); - static const ClassInfo info; + static const ClassInfo s_info; static PassRefPtr createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: static const unsigned StructureFlags = JSWrapperObject::StructureFlags; private: - virtual const ClassInfo* classInfo() const { return &info; } - virtual JSValue getJSNumber(); }; diff --git a/Source/JavaScriptCore/runtime/NumberPrototype.cpp b/Source/JavaScriptCore/runtime/NumberPrototype.cpp index fbe6992..6c027b3 100644 --- a/Source/JavaScriptCore/runtime/NumberPrototype.cpp +++ b/Source/JavaScriptCore/runtime/NumberPrototype.cpp @@ -26,7 +26,6 @@ #include "JSFunction.h" #include "JSString.h" #include "Operations.h" -#include "PrototypeFunction.h" #include "dtoa.h" #include #include @@ -46,19 +45,19 @@ static EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState*); // ECMA 15.7.4 -NumberPrototype::NumberPrototype(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure, Structure* prototypeFunctionStructure) +NumberPrototype::NumberPrototype(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure, Structure* functionStructure) : NumberObject(exec->globalData(), structure) { setInternalValue(exec->globalData(), jsNumber(0)); // The constructor will be added later, after NumberConstructor has been constructed - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 1, exec->propertyNames().toString, numberProtoFuncToString), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 0, exec->propertyNames().toLocaleString, numberProtoFuncToLocaleString), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 0, exec->propertyNames().valueOf, numberProtoFuncValueOf), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 1, exec->propertyNames().toFixed, numberProtoFuncToFixed), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 1, exec->propertyNames().toExponential, numberProtoFuncToExponential), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 1, exec->propertyNames().toPrecision, numberProtoFuncToPrecision), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().toString, numberProtoFuncToString), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().toLocaleString, numberProtoFuncToLocaleString), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().valueOf, numberProtoFuncValueOf), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().toFixed, numberProtoFuncToFixed), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().toExponential, numberProtoFuncToExponential), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().toPrecision, numberProtoFuncToPrecision), DontEnum); } // ------------------------------ Functions --------------------------- diff --git a/Source/JavaScriptCore/runtime/NumberPrototype.h b/Source/JavaScriptCore/runtime/NumberPrototype.h index 78b690e..191ab47 100644 --- a/Source/JavaScriptCore/runtime/NumberPrototype.h +++ b/Source/JavaScriptCore/runtime/NumberPrototype.h @@ -27,7 +27,7 @@ namespace JSC { class NumberPrototype : public NumberObject { public: - NumberPrototype(ExecState*, JSGlobalObject*, NonNullPassRefPtr, Structure* prototypeFunctionStructure); + NumberPrototype(ExecState*, JSGlobalObject*, NonNullPassRefPtr, Structure* functionStructure); }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp index f31da67..5080ef8 100644 --- a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp @@ -26,10 +26,10 @@ #include "JSFunction.h" #include "JSArray.h" #include "JSGlobalObject.h" +#include "Lookup.h" #include "ObjectPrototype.h" #include "PropertyDescriptor.h" #include "PropertyNameArray.h" -#include "PrototypeFunction.h" namespace JSC { @@ -42,23 +42,56 @@ static EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState*); static EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState*); static EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState*); static EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState*); +static EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState*); +static EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState*); +static EncodedJSValue JSC_HOST_CALL objectConstructorPreventExtensions(ExecState*); +static EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState*); +static EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState*); +static EncodedJSValue JSC_HOST_CALL objectConstructorIsExtensible(ExecState*); -ObjectConstructor::ObjectConstructor(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure, ObjectPrototype* objectPrototype, Structure* prototypeFunctionStructure) -: InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, "Object")) +} + +#include "ObjectConstructor.lut.h" + +namespace JSC { + +const ClassInfo ObjectConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::objectConstructorTable }; + +/* Source for ObjectConstructor.lut.h +@begin objectConstructorTable + getPrototypeOf objectConstructorGetPrototypeOf DontEnum|Function 1 + getOwnPropertyDescriptor objectConstructorGetOwnPropertyDescriptor DontEnum|Function 2 + getOwnPropertyNames objectConstructorGetOwnPropertyNames DontEnum|Function 1 + keys objectConstructorKeys DontEnum|Function 1 + defineProperty objectConstructorDefineProperty DontEnum|Function 3 + defineProperties objectConstructorDefineProperties DontEnum|Function 2 + create objectConstructorCreate DontEnum|Function 2 + seal objectConstructorSeal DontEnum|Function 1 + freeze objectConstructorFreeze DontEnum|Function 1 + preventExtensions objectConstructorPreventExtensions DontEnum|Function 1 + isSealed objectConstructorIsSealed DontEnum|Function 1 + isFrozen objectConstructorIsFrozen DontEnum|Function 1 + isExtensible objectConstructorIsExtensible DontEnum|Function 1 +@end +*/ + +ObjectConstructor::ObjectConstructor(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure, ObjectPrototype* objectPrototype) + : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, "Object")) { // ECMA 15.2.3.1 putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, objectPrototype, DontEnum | DontDelete | ReadOnly); - // no. of arguments for constructor putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontEnum | DontDelete); - - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 1, exec->propertyNames().getPrototypeOf, objectConstructorGetPrototypeOf), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 2, exec->propertyNames().getOwnPropertyDescriptor, objectConstructorGetOwnPropertyDescriptor), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 1, exec->propertyNames().getOwnPropertyNames, objectConstructorGetOwnPropertyNames), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 1, exec->propertyNames().keys, objectConstructorKeys), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 3, exec->propertyNames().defineProperty, objectConstructorDefineProperty), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 2, exec->propertyNames().defineProperties, objectConstructorDefineProperties), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 2, exec->propertyNames().create, objectConstructorCreate), DontEnum); +} + +bool ObjectConstructor::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot &slot) +{ + return getStaticFunctionSlot(exec, ExecState::objectConstructorTable(exec), this, propertyName, slot); +} + +bool ObjectConstructor::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + return getStaticFunctionDescriptor(exec, ExecState::objectConstructorTable(exec), this, propertyName, descriptor); } // ECMA 15.2.2 @@ -66,7 +99,7 @@ static ALWAYS_INLINE JSObject* constructObject(ExecState* exec, const ArgList& a { JSValue arg = args.at(0); if (arg.isUndefinedOrNull()) - return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure()); + return constructEmptyObject(exec); return arg.toObject(exec); } @@ -317,4 +350,55 @@ EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState* exec) return JSValue::encode(defineProperties(exec, newObject, asObject(exec->argument(1)))); } +EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState* exec) +{ + JSValue obj = exec->argument(0); + if (!obj.isObject()) + return throwVMError(exec, createTypeError(exec, "Object.seal can only be called on Objects.")); + asObject(obj)->seal(); + return JSValue::encode(obj); +} + +EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState* exec) +{ + JSValue obj = exec->argument(0); + if (!obj.isObject()) + return throwVMError(exec, createTypeError(exec, "Object.freeze can only be called on Objects.")); + asObject(obj)->freeze(); + return JSValue::encode(obj); +} + +EncodedJSValue JSC_HOST_CALL objectConstructorPreventExtensions(ExecState* exec) +{ + JSValue obj = exec->argument(0); + if (!obj.isObject()) + return throwVMError(exec, createTypeError(exec, "Object.preventExtensions can only be called on Objects.")); + asObject(obj)->preventExtensions(); + return JSValue::encode(obj); +} + +EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState* exec) +{ + JSValue obj = exec->argument(0); + if (!obj.isObject()) + return throwVMError(exec, createTypeError(exec, "Object.isSealed can only be called on Objects.")); + return JSValue::encode(jsBoolean(asObject(obj)->isSealed())); +} + +EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState* exec) +{ + JSValue obj = exec->argument(0); + if (!obj.isObject()) + return throwVMError(exec, createTypeError(exec, "Object.isFrozen can only be called on Objects.")); + return JSValue::encode(jsBoolean(asObject(obj)->isFrozen())); +} + +EncodedJSValue JSC_HOST_CALL objectConstructorIsExtensible(ExecState* exec) +{ + JSValue obj = exec->argument(0); + if (!obj.isObject()) + return throwVMError(exec, createTypeError(exec, "Object.isExtensible can only be called on Objects.")); + return JSValue::encode(jsBoolean(asObject(obj)->isExtensible())); +} + } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.h b/Source/JavaScriptCore/runtime/ObjectConstructor.h index 04a3c1a..895f988 100644 --- a/Source/JavaScriptCore/runtime/ObjectConstructor.h +++ b/Source/JavaScriptCore/runtime/ObjectConstructor.h @@ -29,7 +29,20 @@ namespace JSC { class ObjectConstructor : public InternalFunction { public: - ObjectConstructor(ExecState*, JSGlobalObject*, NonNullPassRefPtr, ObjectPrototype*, Structure* prototypeFunctionStructure); + ObjectConstructor(ExecState*, JSGlobalObject*, NonNullPassRefPtr, ObjectPrototype*); + + virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); + + static const ClassInfo s_info; + + static PassRefPtr createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); + } + + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags; private: virtual ConstructType getConstructData(ConstructData&); diff --git a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp index 57a8a31..187456f 100644 --- a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp @@ -25,7 +25,6 @@ #include "JSFunction.h" #include "JSString.h" #include "JSStringBuilder.h" -#include "PrototypeFunction.h" namespace JSC { @@ -41,22 +40,22 @@ static EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState*); static EncodedJSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState*); static EncodedJSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState*); -ObjectPrototype::ObjectPrototype(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr stucture, Structure* prototypeFunctionStructure) - : JSObject(stucture) +ObjectPrototype::ObjectPrototype(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr stucture, Structure* functionStructure) + : JSNonFinalObject(stucture) , m_hasNoPropertiesWithUInt32Names(true) { - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 0, exec->propertyNames().toString, objectProtoFuncToString), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 0, exec->propertyNames().toLocaleString, objectProtoFuncToLocaleString), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 0, exec->propertyNames().valueOf, objectProtoFuncValueOf), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 1, exec->propertyNames().hasOwnProperty, objectProtoFuncHasOwnProperty), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 1, exec->propertyNames().propertyIsEnumerable, objectProtoFuncPropertyIsEnumerable), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 1, exec->propertyNames().isPrototypeOf, objectProtoFuncIsPrototypeOf), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().toString, objectProtoFuncToString), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().toLocaleString, objectProtoFuncToLocaleString), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().valueOf, objectProtoFuncValueOf), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().hasOwnProperty, objectProtoFuncHasOwnProperty), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().propertyIsEnumerable, objectProtoFuncPropertyIsEnumerable), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().isPrototypeOf, objectProtoFuncIsPrototypeOf), DontEnum); // Mozilla extensions - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 2, exec->propertyNames().__defineGetter__, objectProtoFuncDefineGetter), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 2, exec->propertyNames().__defineSetter__, objectProtoFuncDefineSetter), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 1, exec->propertyNames().__lookupGetter__, objectProtoFuncLookupGetter), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 1, exec->propertyNames().__lookupSetter__, objectProtoFuncLookupSetter), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 2, exec->propertyNames().__defineGetter__, objectProtoFuncDefineGetter), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 2, exec->propertyNames().__defineSetter__, objectProtoFuncDefineSetter), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().__lookupGetter__, objectProtoFuncLookupGetter), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().__lookupSetter__, objectProtoFuncLookupSetter), DontEnum); } void ObjectPrototype::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) diff --git a/Source/JavaScriptCore/runtime/ObjectPrototype.h b/Source/JavaScriptCore/runtime/ObjectPrototype.h index 0382ae4..61c8f57 100644 --- a/Source/JavaScriptCore/runtime/ObjectPrototype.h +++ b/Source/JavaScriptCore/runtime/ObjectPrototype.h @@ -25,9 +25,9 @@ namespace JSC { - class ObjectPrototype : public JSObject { + class ObjectPrototype : public JSNonFinalObject { public: - ObjectPrototype(ExecState*, JSGlobalObject*, NonNullPassRefPtr, Structure* prototypeFunctionStructure); + ObjectPrototype(ExecState*, JSGlobalObject*, NonNullPassRefPtr, Structure* functionStructure); private: virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&); diff --git a/Source/JavaScriptCore/runtime/Operations.h b/Source/JavaScriptCore/runtime/Operations.h index 6e84123..181f912 100644 --- a/Source/JavaScriptCore/runtime/Operations.h +++ b/Source/JavaScriptCore/runtime/Operations.h @@ -472,8 +472,11 @@ namespace JSC { JSObject* base; while (true) { base = iter->get(); - if (next == end) - return isStrictPut ? JSValue() : base; + if (next == end) { + if (isStrictPut && !base->getPropertySlot(callFrame, property, slot)) + return JSValue(); + return base; + } if (base->getPropertySlot(callFrame, property, slot)) return base; diff --git a/Source/JavaScriptCore/runtime/PropertyMapHashTable.h b/Source/JavaScriptCore/runtime/PropertyMapHashTable.h index bd452b6..85a3818 100644 --- a/Source/JavaScriptCore/runtime/PropertyMapHashTable.h +++ b/Source/JavaScriptCore/runtime/PropertyMapHashTable.h @@ -22,69 +22,531 @@ #define PropertyMapHashTable_h #include "UString.h" +#include +#include #include + +#ifndef NDEBUG +#define DUMP_PROPERTYMAP_STATS 0 +#else +#define DUMP_PROPERTYMAP_STATS 0 +#endif + +#if DUMP_PROPERTYMAP_STATS + +extern int numProbes; +extern int numCollisions; +extern int numRehashes; +extern int numRemoves; + +#endif + +#define PROPERTY_MAP_DELETED_ENTRY_KEY ((StringImpl*)1) + namespace JSC { - struct PropertyMapEntry { - StringImpl* key; - unsigned offset; - unsigned attributes; - JSCell* specificValue; - unsigned index; - - PropertyMapEntry(StringImpl* key, unsigned attributes, JSCell* specificValue) - : key(key) - , offset(0) - , attributes(attributes) - , specificValue(specificValue) - , index(0) +inline bool isPowerOf2(unsigned v) +{ + // Taken from http://www.cs.utk.edu/~vose/c-stuff/bithacks.html + + return !(v & (v - 1)) && v; +} + +inline unsigned nextPowerOf2(unsigned v) +{ + // Taken from http://www.cs.utk.edu/~vose/c-stuff/bithacks.html + // Devised by Sean Anderson, Sepember 14, 2001 + + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + + return v; +} + +struct PropertyMapEntry { + StringImpl* key; + unsigned offset; + unsigned attributes; + JSCell* specificValue; + + PropertyMapEntry(StringImpl* key, unsigned offset, unsigned attributes, JSCell* specificValue) + : key(key) + , offset(offset) + , attributes(attributes) + , specificValue(specificValue) + { + } +}; + +class PropertyTable { + WTF_MAKE_FAST_ALLOCATED; + + // This is the implementation for 'iterator' and 'const_iterator', + // used for iterating over the table in insertion order. + template + class ordered_iterator { + public: + ordered_iterator& operator++() { + m_valuePtr = skipDeletedEntries(m_valuePtr + 1); + return *this; } - PropertyMapEntry(StringImpl* key, unsigned offset, unsigned attributes, JSCell* specificValue, unsigned index) - : key(key) - , offset(offset) - , attributes(attributes) - , specificValue(specificValue) - , index(index) + bool operator==(const ordered_iterator& other) { + return m_valuePtr == other.m_valuePtr; + } + + bool operator!=(const ordered_iterator& other) + { + return m_valuePtr != other.m_valuePtr; + } + + T& operator*() + { + return *m_valuePtr; } - }; - // lastIndexUsed is an ever-increasing index used to identify the order items - // were inserted into the property map. It's required that getEnumerablePropertyNames - // return the properties in the order they were added for compatibility with other - // browsers' JavaScript implementations. - struct PropertyMapHashTable { - unsigned sizeMask; - unsigned size; - unsigned keyCount; - unsigned deletedSentinelCount; - unsigned lastIndexUsed; - Vector* deletedOffsets; - unsigned entryIndices[1]; - - PropertyMapEntry* entries() + T* operator->() { - // The entries vector comes after the indices vector. - // The 0th item in the entries vector is not really used; it has to - // have a 0 in its key to allow the hash table lookup to handle deleted - // sentinels without any special-case code, but the other fields are unused. - return reinterpret_cast(&entryIndices[size]); + return m_valuePtr; } - static size_t allocationSize(unsigned size) + ordered_iterator(T* valuePtr) + : m_valuePtr(valuePtr) { - // We never let a hash table get more than half full, - // So the number of indices we need is the size of the hash table. - // But the number of entries is half that (plus one for the deleted sentinel). - return sizeof(PropertyMapHashTable) - + (size - 1) * sizeof(unsigned) - + (1 + size / 2) * sizeof(PropertyMapEntry); } + + private: + T* m_valuePtr; }; +public: + typedef StringImpl* KeyType; + typedef PropertyMapEntry ValueType; + + // The in order iterator provides overloaded * and -> to access the Value at the current position. + typedef ordered_iterator iterator; + typedef ordered_iterator const_iterator; + + // The find_iterator is a pair of a pointer to a Value* an the entry in the index. + // If 'find' does not find an entry then iter.first will be 0, and iter.second will + // give the point in m_index where an entry should be inserted. + typedef std::pair find_iterator; + + // Constructor is passed an initial capacity, a PropertyTable to copy, or both. + PropertyTable(unsigned initialCapacity); + PropertyTable(const PropertyTable&); + PropertyTable(unsigned initialCapacity, const PropertyTable&); + ~PropertyTable(); + + // Ordered iteration methods. + iterator begin(); + iterator end(); + const_iterator begin() const; + const_iterator end() const; + + // Find a value in the table. + find_iterator find(const KeyType& key); + // Add a value to the table + std::pair add(const ValueType& entry); + // Remove a value from the table. + void remove(const find_iterator& iter); + void remove(const KeyType& key); + + // Returns the number of values in the hashtable. + unsigned size() const; + + // Checks if there are any values in the hashtable. + bool isEmpty() const; + + // Number of slots in the property storage array in use, included deletedOffsets. + unsigned propertyStorageSize() const; + + // Used to maintain a list of unused entries in the property storage. + void clearDeletedOffsets(); + bool hasDeletedOffset(); + unsigned getDeletedOffset(); + void addDeletedOffset(unsigned offset); + + // Copy this PropertyTable, ensuring the copy has at least the capacity provided. + PassOwnPtr copy(unsigned newCapacity); + +#ifndef NDEBUG + size_t sizeInMemory(); + void checkConsistency(); +#endif + +private: + // Used to insert a value known not to be in the table, and where we know capacity to be available. + void reinsert(const ValueType& entry); + + // Rehash the table. Used to grow, or to recover deleted slots. + void rehash(unsigned newCapacity); + + // The capacity of the table of values is half of the size of the index. + unsigned tableCapacity() const; + + // We keep an extra deleted slot after the array to make iteration work, + // and to use for deleted values. Index values into the array are 1-based, + // so this is tableCapacity() + 1. + // For example, if m_tableSize is 16, then tableCapacity() is 8 - but the + // values array is actually 9 long (the 9th used for the deleted value/ + // iteration guard). The 8 valid entries are numbered 1..8, so the + // deleted index is 9 (0 being reserved for empty). + unsigned deletedEntryIndex() const; + + // Used in iterator creation/progression. + template + static T* skipDeletedEntries(T* valuePtr); + + // The table of values lies after the hash index. + ValueType* table(); + const ValueType* table() const; + + // total number of used entries in the values array - by either valid entries, or deleted ones. + unsigned usedCount() const; + + // The size in bytes of data needed for by the table. + size_t dataSize(); + + // Calculates the appropriate table size (rounds up to a power of two). + static unsigned sizeForCapacity(unsigned capacity); + + // Check if capacity is available. + bool canInsert(); + + unsigned m_indexSize; + unsigned m_indexMask; + unsigned* m_index; + unsigned m_keyCount; + unsigned m_deletedCount; + OwnPtr< Vector > m_deletedOffsets; + + static const unsigned MinimumTableSize = 16; + static const unsigned EmptyEntryIndex = 0; +}; + +inline PropertyTable::PropertyTable(unsigned initialCapacity) + : m_indexSize(sizeForCapacity(initialCapacity)) + , m_indexMask(m_indexSize - 1) + , m_index(static_cast(fastZeroedMalloc(dataSize()))) + , m_keyCount(0) + , m_deletedCount(0) +{ + ASSERT(isPowerOf2(m_indexSize)); +} + +inline PropertyTable::PropertyTable(const PropertyTable& other) + : m_indexSize(other.m_indexSize) + , m_indexMask(other.m_indexMask) + , m_index(static_cast(fastMalloc(dataSize()))) + , m_keyCount(other.m_keyCount) + , m_deletedCount(other.m_deletedCount) +{ + ASSERT(isPowerOf2(m_indexSize)); + + memcpy(m_index, other.m_index, dataSize()); + + iterator end = this->end(); + for (iterator iter = begin(); iter != end; ++iter) + iter->key->ref(); + + // Copy the m_deletedOffsets vector. + Vector* otherDeletedOffsets = other.m_deletedOffsets.get(); + if (otherDeletedOffsets) + m_deletedOffsets.set(new Vector(*otherDeletedOffsets)); +} + +inline PropertyTable::PropertyTable(unsigned initialCapacity, const PropertyTable& other) + : m_indexSize(sizeForCapacity(initialCapacity)) + , m_indexMask(m_indexSize - 1) + , m_index(static_cast(fastZeroedMalloc(dataSize()))) + , m_keyCount(0) + , m_deletedCount(0) +{ + ASSERT(isPowerOf2(m_indexSize)); + ASSERT(initialCapacity >= other.m_keyCount); + + const_iterator end = other.end(); + for (const_iterator iter = other.begin(); iter != end; ++iter) { + ASSERT(canInsert()); + reinsert(*iter); + iter->key->ref(); + } + + // Copy the m_deletedOffsets vector. + Vector* otherDeletedOffsets = other.m_deletedOffsets.get(); + if (otherDeletedOffsets) + m_deletedOffsets.set(new Vector(*otherDeletedOffsets)); +} + +inline PropertyTable::~PropertyTable() +{ + iterator end = this->end(); + for (iterator iter = begin(); iter != end; ++iter) + iter->key->ref(); + + fastFree(m_index); +} + +inline PropertyTable::iterator PropertyTable::begin() +{ + return iterator(skipDeletedEntries(table())); +} + +inline PropertyTable::iterator PropertyTable::end() +{ + return iterator(table() + usedCount()); +} + +inline PropertyTable::const_iterator PropertyTable::begin() const +{ + return const_iterator(skipDeletedEntries(table())); +} + +inline PropertyTable::const_iterator PropertyTable::end() const +{ + return const_iterator(table() + usedCount()); +} + +inline PropertyTable::find_iterator PropertyTable::find(const KeyType& key) +{ + ASSERT(key); + unsigned hash = key->existingHash(); + unsigned step = 0; + +#if DUMP_PROPERTYMAP_STATS + ++numProbes; +#endif + + while (true) { + unsigned entryIndex = m_index[hash & m_indexMask]; + if (entryIndex == EmptyEntryIndex) + return std::make_pair((ValueType*)0, hash & m_indexMask); + if (key == table()[entryIndex - 1].key) + return std::make_pair(&table()[entryIndex - 1], hash & m_indexMask); + +#if DUMP_PROPERTYMAP_STATS + ++numCollisions; +#endif + + if (!step) + step =WTF::doubleHash(key->existingHash()) | 1; + hash += step; + +#if DUMP_PROPERTYMAP_STATS + ++numRehashes; +#endif + } +} + +inline std::pair PropertyTable::add(const ValueType& entry) +{ + // Look for a value with a matching key already in the array. + find_iterator iter = find(entry.key); + if (iter.first) + return std::make_pair(iter, false); + + // Ref the key + entry.key->ref(); + + // ensure capacity is available. + if (!canInsert()) { + rehash(m_keyCount + 1); + iter = find(entry.key); + ASSERT(!iter.first); + } + + // Allocate a slot in the hashtable, and set the index to reference this. + unsigned entryIndex = usedCount() + 1; + m_index[iter.second] = entryIndex; + iter.first = &table()[entryIndex - 1]; + *iter.first = entry; + + ++m_keyCount; + return std::make_pair(iter, true); +} + +inline void PropertyTable::remove(const find_iterator& iter) +{ + // Removing a key that doesn't exist does nothing! + if (!iter.first) + return; + +#if DUMP_PROPERTYMAP_STATS + ++numRemoves; +#endif + + // Replace this one element with the deleted sentinel. Also clear out + // the entry so we can iterate all the entries as needed. + m_index[iter.second] = deletedEntryIndex(); + iter.first->key->deref(); + iter.first->key = PROPERTY_MAP_DELETED_ENTRY_KEY; + + ASSERT(m_keyCount >= 1); + --m_keyCount; + ++m_deletedCount; + + if (m_deletedCount * 4 >= m_indexSize) + rehash(m_keyCount); +} + +inline void PropertyTable::remove(const KeyType& key) +{ + remove(find(key)); +} + +// returns the number of values in the hashtable. +inline unsigned PropertyTable::size() const +{ + return m_keyCount; +} + +inline bool PropertyTable::isEmpty() const +{ + return !m_keyCount; +} + +inline unsigned PropertyTable::propertyStorageSize() const +{ + return size() + (m_deletedOffsets ? m_deletedOffsets->size() : 0); +} + +inline void PropertyTable::clearDeletedOffsets() +{ + m_deletedOffsets.clear(); +} + +inline bool PropertyTable::hasDeletedOffset() +{ + return m_deletedOffsets && !m_deletedOffsets->isEmpty(); +} + +inline unsigned PropertyTable::getDeletedOffset() +{ + unsigned offset = m_deletedOffsets->last(); + m_deletedOffsets->removeLast(); + return offset; +} + +inline void PropertyTable::addDeletedOffset(unsigned offset) +{ + if (!m_deletedOffsets) + m_deletedOffsets.set(new Vector); + m_deletedOffsets->append(offset); +} + +inline PassOwnPtr PropertyTable::copy(unsigned newCapacity) +{ + ASSERT(newCapacity >= m_keyCount); + + // Fast case; if the new table will be the same m_indexSize as this one, we can memcpy it, + // save rehashing all keys. + if (sizeForCapacity(newCapacity) == m_indexSize) + return new PropertyTable(*this); + return new PropertyTable(newCapacity, *this); +} + +#ifndef NDEBUG +inline size_t PropertyTable::sizeInMemory() +{ + size_t result = sizeof(PropertyTable) + dataSize(); + if (m_deletedOffsets) + result += (m_deletedOffsets->capacity() * sizeof(unsigned)); + return result; +} +#endif + +inline void PropertyTable::reinsert(const ValueType& entry) +{ + // Used to insert a value known not to be in the table, and where + // we know capacity to be available. + ASSERT(canInsert()); + find_iterator iter = find(entry.key); + ASSERT(!iter.first); + + unsigned entryIndex = usedCount() + 1; + m_index[iter.second] = entryIndex; + table()[entryIndex - 1] = entry; + + ++m_keyCount; +} + +inline void PropertyTable::rehash(unsigned newCapacity) +{ + unsigned* oldEntryIndices = m_index; + iterator iter = this->begin(); + iterator end = this->end(); + + m_indexSize = sizeForCapacity(newCapacity); + m_indexMask = m_indexSize - 1; + m_keyCount = 0; + m_deletedCount = 0; + m_index = static_cast(fastZeroedMalloc(dataSize())); + + for (; iter != end; ++iter) { + ASSERT(canInsert()); + reinsert(*iter); + } + + fastFree(oldEntryIndices); +} + +inline unsigned PropertyTable::tableCapacity() const { return m_indexSize >> 1; } + +inline unsigned PropertyTable::deletedEntryIndex() const { return tableCapacity() + 1; } + +template +inline T* PropertyTable::skipDeletedEntries(T* valuePtr) +{ + while (valuePtr->key == PROPERTY_MAP_DELETED_ENTRY_KEY) + ++valuePtr; + return valuePtr; +} + +inline PropertyTable::ValueType* PropertyTable::table() +{ + // The table of values lies after the hash index. + return reinterpret_cast(m_index + m_indexSize); +} + +inline const PropertyTable::ValueType* PropertyTable::table() const +{ + // The table of values lies after the hash index. + return reinterpret_cast(m_index + m_indexSize); +} + +inline unsigned PropertyTable::usedCount() const +{ + // Total number of used entries in the values array - by either valid entries, or deleted ones. + return m_keyCount + m_deletedCount; +} + +inline size_t PropertyTable::dataSize() +{ + // The size in bytes of data needed for by the table. + return m_indexSize * sizeof(unsigned) + ((tableCapacity()) + 1) * sizeof(ValueType); +} + +inline unsigned PropertyTable::sizeForCapacity(unsigned capacity) +{ + if (capacity < 8) + return MinimumTableSize; + return nextPowerOf2(capacity + 1) * 2; +} + +inline bool PropertyTable::canInsert() +{ + return usedCount() < tableCapacity(); +} + } // namespace JSC #endif // PropertyMapHashTable_h diff --git a/Source/JavaScriptCore/runtime/PropertyNameArray.cpp b/Source/JavaScriptCore/runtime/PropertyNameArray.cpp index afb41be..351ecc3 100644 --- a/Source/JavaScriptCore/runtime/PropertyNameArray.cpp +++ b/Source/JavaScriptCore/runtime/PropertyNameArray.cpp @@ -21,6 +21,7 @@ #include "config.h" #include "PropertyNameArray.h" +#include "ScopeChain.h" #include "Structure.h" #include "StructureChain.h" diff --git a/Source/JavaScriptCore/runtime/PropertySlot.h b/Source/JavaScriptCore/runtime/PropertySlot.h index cdda6ff..ce29ac4 100644 --- a/Source/JavaScriptCore/runtime/PropertySlot.h +++ b/Source/JavaScriptCore/runtime/PropertySlot.h @@ -123,15 +123,6 @@ namespace JSC { m_value = value; } - void setRegisterSlot(Register* registerSlot) - { - ASSERT(registerSlot); - clearBase(); - clearOffset(); - m_getValue = JSC_VALUE_MARKER; - m_value = registerSlot->jsValue(); - } - void setCustom(JSValue slotBase, GetValueFunc getValue) { ASSERT(slotBase); diff --git a/Source/JavaScriptCore/runtime/Protect.h b/Source/JavaScriptCore/runtime/Protect.h index 0c1b5e8..843c9e1 100644 --- a/Source/JavaScriptCore/runtime/Protect.h +++ b/Source/JavaScriptCore/runtime/Protect.h @@ -61,155 +61,6 @@ namespace JSC { gcUnprotect(value.asCell()); } - // FIXME: Share more code with RefPtr template? The only differences are the ref/deref operation - // and the implicit conversion to raw pointer - template class ProtectedPtr { - public: - ProtectedPtr() : m_ptr(0) {} - ProtectedPtr(T* ptr); - ProtectedPtr(const ProtectedPtr&); - ~ProtectedPtr(); - - template ProtectedPtr(const ProtectedPtr&); - - T* get() const { return m_ptr; } - operator T*() const { return m_ptr; } - operator JSValue() const { return JSValue(m_ptr); } - T* operator->() const { return m_ptr; } - - operator bool() const { return m_ptr; } - bool operator!() const { return !m_ptr; } - - ProtectedPtr& operator=(const ProtectedPtr&); - ProtectedPtr& operator=(T*); - - private: - T* m_ptr; - }; - - class ProtectedJSValue { - public: - ProtectedJSValue() {} - ProtectedJSValue(JSValue value); - ProtectedJSValue(const ProtectedJSValue&); - ~ProtectedJSValue(); - - template ProtectedJSValue(const ProtectedPtr&); - - JSValue get() const { return m_value; } - operator JSValue() const { return m_value; } - JSValue operator->() const { return m_value; } - - operator bool() const { return m_value; } - bool operator!() const { return !m_value; } - - ProtectedJSValue& operator=(const ProtectedJSValue&); - ProtectedJSValue& operator=(JSValue); - - private: - JSValue m_value; - }; - - template inline ProtectedPtr::ProtectedPtr(T* ptr) - : m_ptr(ptr) - { - gcProtectNullTolerant(m_ptr); - } - - template inline ProtectedPtr::ProtectedPtr(const ProtectedPtr& o) - : m_ptr(o.get()) - { - gcProtectNullTolerant(m_ptr); - } - - template inline ProtectedPtr::~ProtectedPtr() - { - gcUnprotectNullTolerant(m_ptr); - } - - template template inline ProtectedPtr::ProtectedPtr(const ProtectedPtr& o) - : m_ptr(o.get()) - { - gcProtectNullTolerant(m_ptr); - } - - template inline ProtectedPtr& ProtectedPtr::operator=(const ProtectedPtr& o) - { - T* optr = o.m_ptr; - gcProtectNullTolerant(optr); - gcUnprotectNullTolerant(m_ptr); - m_ptr = optr; - return *this; - } - - template inline ProtectedPtr& ProtectedPtr::operator=(T* optr) - { - gcProtectNullTolerant(optr); - gcUnprotectNullTolerant(m_ptr); - m_ptr = optr; - return *this; - } - - inline ProtectedJSValue::ProtectedJSValue(JSValue value) - : m_value(value) - { - gcProtect(m_value); - } - - inline ProtectedJSValue::ProtectedJSValue(const ProtectedJSValue& o) - : m_value(o.get()) - { - gcProtect(m_value); - } - - inline ProtectedJSValue::~ProtectedJSValue() - { - gcUnprotect(m_value); - } - - template ProtectedJSValue::ProtectedJSValue(const ProtectedPtr& o) - : m_value(o.get()) - { - gcProtect(m_value); - } - - inline ProtectedJSValue& ProtectedJSValue::operator=(const ProtectedJSValue& o) - { - JSValue ovalue = o.m_value; - gcProtect(ovalue); - gcUnprotect(m_value); - m_value = ovalue; - return *this; - } - - inline ProtectedJSValue& ProtectedJSValue::operator=(JSValue ovalue) - { - gcProtect(ovalue); - gcUnprotect(m_value); - m_value = ovalue; - return *this; - } - - template inline bool operator==(const ProtectedPtr& a, const ProtectedPtr& b) { return a.get() == b.get(); } - template inline bool operator==(const ProtectedPtr& a, const T* b) { return a.get() == b; } - template inline bool operator==(const T* a, const ProtectedPtr& b) { return a == b.get(); } - - template inline bool operator!=(const ProtectedPtr& a, const ProtectedPtr& b) { return a.get() != b.get(); } - template inline bool operator!=(const ProtectedPtr& a, const T* b) { return a.get() != b; } - template inline bool operator!=(const T* a, const ProtectedPtr& b) { return a != b.get(); } - - inline bool operator==(const ProtectedJSValue& a, const ProtectedJSValue& b) { return a.get() == b.get(); } - inline bool operator==(const ProtectedJSValue& a, const JSValue b) { return a.get() == b; } - template inline bool operator==(const ProtectedJSValue& a, const ProtectedPtr& b) { return a.get() == JSValue(b.get()); } - inline bool operator==(const JSValue a, const ProtectedJSValue& b) { return a == b.get(); } - template inline bool operator==(const ProtectedPtr& a, const ProtectedJSValue& b) { return JSValue(a.get()) == b.get(); } - - inline bool operator!=(const ProtectedJSValue& a, const ProtectedJSValue& b) { return a.get() != b.get(); } - inline bool operator!=(const ProtectedJSValue& a, const JSValue b) { return a.get() != b; } - template inline bool operator!=(const ProtectedJSValue& a, const ProtectedPtr& b) { return a.get() != JSValue(b.get()); } - inline bool operator!=(const JSValue a, const ProtectedJSValue& b) { return a != b.get(); } - template inline bool operator!=(const ProtectedPtr& a, const ProtectedJSValue& b) { return JSValue(a.get()) != b.get(); } - } // namespace JSC #endif // Protect_h diff --git a/Source/JavaScriptCore/runtime/PrototypeFunction.cpp b/Source/JavaScriptCore/runtime/PrototypeFunction.cpp deleted file mode 100644 index 95e1033..0000000 --- a/Source/JavaScriptCore/runtime/PrototypeFunction.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) - * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) - * Copyright (C) 2007 Maks Orlovich - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "PrototypeFunction.h" - -#include "JSGlobalObject.h" -#include - -namespace JSC { - -ASSERT_CLASS_FITS_IN_CELL(PrototypeFunction); - -PrototypeFunction::PrototypeFunction(ExecState* exec, JSGlobalObject* globalObject, int length, const Identifier& name, NativeFunction function) - : InternalFunction(&exec->globalData(), globalObject, exec->lexicalGlobalObject()->prototypeFunctionStructure(), name) - , m_function(function) -{ - ASSERT_ARG(function, function); - putDirect(exec->globalData(), exec->propertyNames().length, jsNumber(length), DontDelete | ReadOnly | DontEnum); -} - -PrototypeFunction::PrototypeFunction(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr prototypeFunctionStructure, int length, const Identifier& name, NativeFunction function) - : InternalFunction(&exec->globalData(), globalObject, prototypeFunctionStructure, name) - , m_function(function) -{ - ASSERT_ARG(function, function); - putDirect(exec->globalData(), exec->propertyNames().length, jsNumber(length), DontDelete | ReadOnly | DontEnum); -} - -CallType PrototypeFunction::getCallData(CallData& callData) -{ - callData.native.function = m_function; - return CallTypeHost; -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/PrototypeFunction.h b/Source/JavaScriptCore/runtime/PrototypeFunction.h deleted file mode 100644 index 6ca2342..0000000 --- a/Source/JavaScriptCore/runtime/PrototypeFunction.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) - * Copyright (C) 2007 Maks Orlovich - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#ifndef PrototypeFunction_h -#define PrototypeFunction_h - -#include "InternalFunction.h" -#include "CallData.h" - -namespace JSC { - - class PrototypeFunction : public InternalFunction { - public: - PrototypeFunction(ExecState*, JSGlobalObject*, int length, const Identifier&, NativeFunction); - PrototypeFunction(ExecState*, JSGlobalObject*, NonNullPassRefPtr, int length, const Identifier&, NativeFunction); - - private: - virtual CallType getCallData(CallData&); - - const NativeFunction m_function; - }; - -} // namespace JSC - -#endif // PrototypeFunction_h diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp index 1b30514..c06fdc4 100644 --- a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp +++ b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp @@ -67,7 +67,7 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(RegExpConstructor); -const ClassInfo RegExpConstructor::info = { "Function", &InternalFunction::info, 0, ExecState::regExpConstructorTable }; +const ClassInfo RegExpConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::regExpConstructorTable }; /* Source for RegExpConstructor.lut.h @begin regExpConstructorTable @@ -99,6 +99,8 @@ RegExpConstructor::RegExpConstructor(ExecState* exec, JSGlobalObject* globalObje : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, "RegExp")) , d(adoptPtr(new RegExpConstructorPrivate)) { + ASSERT(inherits(&s_info)); + // ECMA 15.10.5.1 RegExp.prototype putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, regExpPrototype, DontEnum | DontDelete | ReadOnly); @@ -296,7 +298,7 @@ JSObject* constructRegExp(ExecState* exec, const ArgList& args) JSValue arg0 = args.at(0); JSValue arg1 = args.at(1); - if (arg0.inherits(&RegExpObject::info)) { + if (arg0.inherits(&RegExpObject::s_info)) { if (!arg1.isUndefined()) return throwError(exec, createTypeError(exec, "Cannot supply flags when constructing one RegExp from another.")); return asObject(arg0); diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.h b/Source/JavaScriptCore/runtime/RegExpConstructor.h index 1714bd3..8a8a54a 100644 --- a/Source/JavaScriptCore/runtime/RegExpConstructor.h +++ b/Source/JavaScriptCore/runtime/RegExpConstructor.h @@ -61,14 +61,14 @@ namespace JSC { static PassRefPtr createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); - static const ClassInfo info; + static const ClassInfo s_info; void performMatch(RegExp*, const UString&, int startOffset, int& position, int& length, int** ovector = 0); JSObject* arrayOfMatches(ExecState*) const; @@ -91,8 +91,6 @@ namespace JSC { virtual ConstructType getConstructData(ConstructData&); virtual CallType getCallData(CallData&); - virtual const ClassInfo* classInfo() const { return &info; } - OwnPtr d; }; @@ -102,7 +100,7 @@ namespace JSC { inline RegExpConstructor* asRegExpConstructor(JSValue value) { - ASSERT(asObject(value)->inherits(&RegExpConstructor::info)); + ASSERT(asObject(value)->inherits(&RegExpConstructor::s_info)); return static_cast(asObject(value)); } diff --git a/Source/JavaScriptCore/runtime/RegExpObject.cpp b/Source/JavaScriptCore/runtime/RegExpObject.cpp index b969e38..5baf884 100644 --- a/Source/JavaScriptCore/runtime/RegExpObject.cpp +++ b/Source/JavaScriptCore/runtime/RegExpObject.cpp @@ -49,7 +49,7 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(RegExpObject); -const ClassInfo RegExpObject::info = { "RegExp", 0, 0, ExecState::regExpTable }; +const ClassInfo RegExpObject::s_info = { "RegExp", &JSObjectWithGlobalObject::s_info, 0, ExecState::regExpTable }; /* Source for RegExpObject.lut.h @begin regExpTable @@ -65,6 +65,7 @@ RegExpObject::RegExpObject(JSGlobalObject* globalObject, NonNullPassRefPtr createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: @@ -70,7 +69,7 @@ namespace JSC { RefPtr regExp; double lastIndex; }; -#if PLATFORM(WIN) +#if COMPILER(MSVC) friend void WTF::deleteOwnedPtr(RegExpObjectData*); #endif OwnPtr d; @@ -80,7 +79,7 @@ namespace JSC { inline RegExpObject* asRegExpObject(JSValue value) { - ASSERT(asObject(value)->inherits(&RegExpObject::info)); + ASSERT(asObject(value)->inherits(&RegExpObject::s_info)); return static_cast(asObject(value)); } diff --git a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp index a7c447d..106006c 100644 --- a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp +++ b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp @@ -30,7 +30,6 @@ #include "JSStringBuilder.h" #include "JSValue.h" #include "ObjectPrototype.h" -#include "PrototypeFunction.h" #include "RegExpObject.h" #include "RegExp.h" #include "RegExpCache.h" @@ -48,13 +47,13 @@ static EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState*); // ECMA 15.10.5 -RegExpPrototype::RegExpPrototype(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure, Structure* prototypeFunctionStructure) +RegExpPrototype::RegExpPrototype(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure, Structure* functionStructure) : RegExpObject(globalObject, structure, RegExp::create(&exec->globalData(), "", "")) { - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 0, exec->propertyNames().compile, regExpProtoFuncCompile), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 0, exec->propertyNames().exec, regExpProtoFuncExec), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 0, exec->propertyNames().test, regExpProtoFuncTest), DontEnum); - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 0, exec->propertyNames().toString, regExpProtoFuncToString), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().compile, regExpProtoFuncCompile), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().exec, regExpProtoFuncExec), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().test, regExpProtoFuncTest), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().toString, regExpProtoFuncToString), DontEnum); } // ------------------------------ Functions --------------------------- @@ -62,7 +61,7 @@ RegExpPrototype::RegExpPrototype(ExecState* exec, JSGlobalObject* globalObject, EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&RegExpObject::info)) + if (!thisValue.inherits(&RegExpObject::s_info)) return throwVMTypeError(exec); return JSValue::encode(asRegExpObject(thisValue)->test(exec)); } @@ -70,7 +69,7 @@ EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState* exec) EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&RegExpObject::info)) + if (!thisValue.inherits(&RegExpObject::s_info)) return throwVMTypeError(exec); return JSValue::encode(asRegExpObject(thisValue)->exec(exec)); } @@ -78,14 +77,14 @@ EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec) EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&RegExpObject::info)) + if (!thisValue.inherits(&RegExpObject::s_info)) return throwVMTypeError(exec); RefPtr regExp; JSValue arg0 = exec->argument(0); JSValue arg1 = exec->argument(1); - if (arg0.inherits(&RegExpObject::info)) { + if (arg0.inherits(&RegExpObject::s_info)) { if (!arg1.isUndefined()) return throwVMError(exec, createTypeError(exec, "Cannot supply flags when constructing one RegExp from another.")); regExp = asRegExpObject(arg0)->regExp(); @@ -106,8 +105,8 @@ EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec) EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); - if (!thisValue.inherits(&RegExpObject::info)) { - if (thisValue.inherits(&RegExpPrototype::info)) + if (!thisValue.inherits(&RegExpObject::s_info)) { + if (thisValue.inherits(&RegExpPrototype::s_info)) return JSValue::encode(jsNontrivialString(exec, "//")); return throwVMTypeError(exec); } diff --git a/Source/JavaScriptCore/runtime/RegExpPrototype.h b/Source/JavaScriptCore/runtime/RegExpPrototype.h index eb4ae00..70d77d9 100644 --- a/Source/JavaScriptCore/runtime/RegExpPrototype.h +++ b/Source/JavaScriptCore/runtime/RegExpPrototype.h @@ -28,7 +28,7 @@ namespace JSC { class RegExpPrototype : public RegExpObject { public: - RegExpPrototype(ExecState*, JSGlobalObject*, NonNullPassRefPtr, Structure* prototypeFunctionStructure); + RegExpPrototype(ExecState*, JSGlobalObject*, NonNullPassRefPtr, Structure* functionStructure); }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ScopeChain.cpp b/Source/JavaScriptCore/runtime/ScopeChain.cpp index 976cff6..4615f9a 100644 --- a/Source/JavaScriptCore/runtime/ScopeChain.cpp +++ b/Source/JavaScriptCore/runtime/ScopeChain.cpp @@ -31,16 +31,16 @@ namespace JSC { #ifndef NDEBUG -void ScopeChainNode::print() const +void ScopeChainNode::print() { ScopeChainIterator scopeEnd = end(); for (ScopeChainIterator scopeIter = begin(); scopeIter != scopeEnd; ++scopeIter) { - DeprecatedPtr o = *scopeIter; + JSObject* o = scopeIter->get(); PropertyNameArray propertyNames(globalObject->globalExec()); o->getPropertyNames(globalObject->globalExec(), propertyNames); PropertyNameArray::const_iterator propEnd = propertyNames.end(); - fprintf(stderr, "----- [scope %p] -----\n", o.get()); + fprintf(stderr, "----- [scope %p] -----\n", o); for (PropertyNameArray::const_iterator propIter = propertyNames.begin(); propIter != propEnd; propIter++) { Identifier name = *propIter; fprintf(stderr, "%s, ", name.ustring().utf8().data()); @@ -51,12 +51,12 @@ void ScopeChainNode::print() const #endif -int ScopeChain::localDepth() const +int ScopeChainNode::localDepth() { int scopeDepth = 0; ScopeChainIterator iter = this->begin(); ScopeChainIterator end = this->end(); - while (!(*iter)->inherits(&JSActivation::info)) { + while (!(*iter)->inherits(&JSActivation::s_info)) { ++iter; if (iter == end) break; @@ -65,4 +65,13 @@ int ScopeChain::localDepth() const return scopeDepth; } +void ScopeChainNode::markChildren(MarkStack& markStack) +{ + if (next) + markStack.append(&next); + markStack.append(&object); + markStack.append(&globalObject); + markStack.append(&globalThis); +} + } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ScopeChain.h b/Source/JavaScriptCore/runtime/ScopeChain.h index 11f3692..fbecd11 100644 --- a/Source/JavaScriptCore/runtime/ScopeChain.h +++ b/Source/JavaScriptCore/runtime/ScopeChain.h @@ -21,7 +21,7 @@ #ifndef ScopeChain_h #define ScopeChain_h -#include "WriteBarrier.h" +#include "JSCell.h" #include namespace JSC { @@ -32,109 +32,67 @@ namespace JSC { class MarkStack; class ScopeChainIterator; - class ScopeChainNode { - WTF_MAKE_FAST_ALLOCATED; + class ScopeChainNode : public JSCell { public: ScopeChainNode(ScopeChainNode* next, JSObject* object, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis) - : next(next) - , object(object) + : JSCell(globalData->scopeChainNodeStructure.get()) , globalData(globalData) - , globalObject(globalObject) - , globalThis(globalThis) - , refCount(1) + , next(*globalData, this, next) + , object(*globalData, this, object) + , globalObject(*globalData, this, globalObject) + , globalThis(*globalData, this, globalThis) { ASSERT(globalData); ASSERT(globalObject); } -#ifndef NDEBUG - // Due to the number of subtle and timing dependent bugs that have occurred due - // to deleted but still "valid" ScopeChainNodes we now deliberately clobber the - // contents in debug builds. - ~ScopeChainNode() - { - next = 0; - globalData = 0; - globalObject = 0; - globalThis = 0; - } -#endif - ScopeChainNode* next; - DeprecatedPtr object; JSGlobalData* globalData; - JSGlobalObject* globalObject; - JSObject* globalThis; - int refCount; - - void deref() { ASSERT(refCount); if (--refCount == 0) { release();} } - void ref() { ASSERT(refCount); ++refCount; } - void release(); - - // Before calling "push" on a bare ScopeChainNode, a client should - // logically "copy" the node. Later, the client can "deref" the head - // of its chain of ScopeChainNodes to reclaim all the nodes it added - // after the logical copy, leaving nodes added before the logical copy - // (nodes shared with other clients) untouched. - ScopeChainNode* copy() - { - ref(); - return this; - } + WriteBarrier next; + WriteBarrier object; + WriteBarrier globalObject; + WriteBarrier globalThis; ScopeChainNode* push(JSObject*); ScopeChainNode* pop(); - ScopeChainIterator begin() const; - ScopeChainIterator end() const; + ScopeChainIterator begin(); + ScopeChainIterator end(); + + int localDepth(); #ifndef NDEBUG - void print() const; + void print(); #endif + + static PassRefPtr createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, 0); } + virtual void markChildren(MarkStack&); + private: + static const unsigned StructureFlags = OverridesMarkChildren; }; inline ScopeChainNode* ScopeChainNode::push(JSObject* o) { ASSERT(o); - return new ScopeChainNode(this, o, globalData, globalObject, globalThis); + return new (globalData) ScopeChainNode(this, o, globalData, globalObject.get(), globalThis.get()); } inline ScopeChainNode* ScopeChainNode::pop() { ASSERT(next); - ScopeChainNode* result = next; - - if (--refCount != 0) - ++result->refCount; - else - delete this; - - return result; - } - - inline void ScopeChainNode::release() - { - // This function is only called by deref(), - // Deref ensures these conditions are true. - ASSERT(refCount == 0); - ScopeChainNode* n = this; - do { - ScopeChainNode* next = n->next; - delete n; - n = next; - } while (n && --n->refCount == 0); + return next.get(); } class ScopeChainIterator { public: - ScopeChainIterator(const ScopeChainNode* node) + ScopeChainIterator(ScopeChainNode* node) : m_node(node) { } - DeprecatedPtr const & operator*() const { return m_node->object; } - DeprecatedPtr const * operator->() const { return &(operator*()); } + WriteBarrier const & operator*() const { return m_node->object; } + WriteBarrier const * operator->() const { return &(operator*()); } - ScopeChainIterator& operator++() { m_node = m_node->next; return *this; } + ScopeChainIterator& operator++() { m_node = m_node->next.get(); return *this; } // postfix ++ intentionally omitted @@ -142,100 +100,33 @@ namespace JSC { bool operator!=(const ScopeChainIterator& other) const { return m_node != other.m_node; } private: - const ScopeChainNode* m_node; + DeprecatedPtr m_node; }; - inline ScopeChainIterator ScopeChainNode::begin() const + inline ScopeChainIterator ScopeChainNode::begin() { return ScopeChainIterator(this); } - inline ScopeChainIterator ScopeChainNode::end() const + inline ScopeChainIterator ScopeChainNode::end() { return ScopeChainIterator(0); } - class NoScopeChain {}; - - class ScopeChain { - friend class JIT; - public: - ScopeChain(NoScopeChain) - : m_node(0) - { - } - - ScopeChain(JSObject* o, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis) - : m_node(new ScopeChainNode(0, o, globalData, globalObject, globalThis)) - { - } - - ScopeChain(const ScopeChain& c) - : m_node(c.m_node->copy()) - { - } - - ScopeChain& operator=(const ScopeChain& c); - - explicit ScopeChain(ScopeChainNode* node) - : m_node(node->copy()) - { - } - - ~ScopeChain() - { - if (m_node) - m_node->deref(); -#ifndef NDEBUG - m_node = 0; -#endif - } - - void swap(ScopeChain&); - - ScopeChainNode* node() const { return m_node; } - - JSObject* top() const { return m_node->object.get(); } - - ScopeChainIterator begin() const { return m_node->begin(); } - ScopeChainIterator end() const { return m_node->end(); } - - void push(JSObject* o) { m_node = m_node->push(o); } - - void pop() { m_node = m_node->pop(); } - void clear() { m_node->deref(); m_node = 0; } - - JSGlobalObject* globalObject() const { return m_node->globalObject; } - - void markAggregate(MarkStack&) const; - - // Caution: this should only be used if the codeblock this is being used - // with needs a full scope chain, otherwise this returns the depth of - // the preceeding call frame - // - // Returns the depth of the current call frame's scope chain - int localDepth() const; - -#ifndef NDEBUG - void print() const { m_node->print(); } -#endif - - private: - ScopeChainNode* m_node; - }; - - inline void ScopeChain::swap(ScopeChain& o) + ALWAYS_INLINE JSGlobalData& ExecState::globalData() const { - ScopeChainNode* tmp = m_node; - m_node = o.m_node; - o.m_node = tmp; + ASSERT(scopeChain()->globalData); + return *scopeChain()->globalData; } - inline ScopeChain& ScopeChain::operator=(const ScopeChain& c) + ALWAYS_INLINE JSGlobalObject* ExecState::lexicalGlobalObject() const + { + return scopeChain()->globalObject.get(); + } + + ALWAYS_INLINE JSObject* ExecState::globalThisValue() const { - ScopeChain tmp(c); - swap(tmp); - return *this; + return scopeChain()->globalThis.get(); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ScopeChainMark.h b/Source/JavaScriptCore/runtime/ScopeChainMark.h index faa4824..35701f1 100644 --- a/Source/JavaScriptCore/runtime/ScopeChainMark.h +++ b/Source/JavaScriptCore/runtime/ScopeChainMark.h @@ -25,12 +25,6 @@ namespace JSC { - inline void ScopeChain::markAggregate(MarkStack& markStack) const - { - for (ScopeChainNode* n = m_node; n; n = n->next) - markStack.append(&n->object); - } - } // namespace JSC #endif // ScopeChainMark_h diff --git a/Source/JavaScriptCore/runtime/SmallStrings.h b/Source/JavaScriptCore/runtime/SmallStrings.h index ee795b6..cd9c325 100644 --- a/Source/JavaScriptCore/runtime/SmallStrings.h +++ b/Source/JavaScriptCore/runtime/SmallStrings.h @@ -63,9 +63,9 @@ namespace JSC { void clear(); unsigned count() const; -#if ENABLE(JIT) + JSCell** singleCharacterStrings() { return m_singleCharacterStrings[0].slot(); } -#endif + private: void createEmptyString(JSGlobalData*); void createSingleCharacterString(JSGlobalData*, unsigned char); diff --git a/Source/JavaScriptCore/runtime/StrictEvalActivation.cpp b/Source/JavaScriptCore/runtime/StrictEvalActivation.cpp index 5bb013b..24c501e 100644 --- a/Source/JavaScriptCore/runtime/StrictEvalActivation.cpp +++ b/Source/JavaScriptCore/runtime/StrictEvalActivation.cpp @@ -29,7 +29,7 @@ namespace JSC { StrictEvalActivation::StrictEvalActivation(ExecState* exec) - : JSObject(exec->globalData().strictEvalActivationStructure) + : JSNonFinalObject(exec->globalData().strictEvalActivationStructure) { } diff --git a/Source/JavaScriptCore/runtime/StrictEvalActivation.h b/Source/JavaScriptCore/runtime/StrictEvalActivation.h index 1385eec..e2885cc 100644 --- a/Source/JavaScriptCore/runtime/StrictEvalActivation.h +++ b/Source/JavaScriptCore/runtime/StrictEvalActivation.h @@ -30,7 +30,7 @@ namespace JSC { -class StrictEvalActivation : public JSObject { +class StrictEvalActivation : public JSNonFinalObject { public: StrictEvalActivation(ExecState*); virtual bool deleteProperty(ExecState*, const Identifier&); diff --git a/Source/JavaScriptCore/runtime/StringConstructor.cpp b/Source/JavaScriptCore/runtime/StringConstructor.cpp index 604473b..5398f31 100644 --- a/Source/JavaScriptCore/runtime/StringConstructor.cpp +++ b/Source/JavaScriptCore/runtime/StringConstructor.cpp @@ -25,7 +25,6 @@ #include "JITCode.h" #include "JSFunction.h" #include "JSGlobalObject.h" -#include "PrototypeFunction.h" #include "StringPrototype.h" namespace JSC { @@ -49,7 +48,7 @@ static EncodedJSValue JSC_HOST_CALL stringFromCharCode(ExecState* exec) ASSERT_CLASS_FITS_IN_CELL(StringConstructor); -StringConstructor::StringConstructor(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure, Structure* prototypeFunctionStructure, StringPrototype* stringPrototype) +StringConstructor::StringConstructor(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure, Structure* functionStructure, StringPrototype* stringPrototype) : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, stringPrototype->classInfo()->className)) { // ECMA 15.5.3.1 String.prototype @@ -57,9 +56,9 @@ StringConstructor::StringConstructor(ExecState* exec, JSGlobalObject* globalObje // ECMA 15.5.3.2 fromCharCode() #if ENABLE(JIT) && ENABLE(JIT_OPTIMIZE_NATIVE_CALL) - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 1, exec->propertyNames().fromCharCode, exec->globalData().getHostFunction(stringFromCharCode, fromCharCodeThunkGenerator)), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().fromCharCode, exec->globalData().getHostFunction(stringFromCharCode, fromCharCodeThunkGenerator)), DontEnum); #else - putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 1, exec->propertyNames().fromCharCode, stringFromCharCode), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().fromCharCode, stringFromCharCode), DontEnum); #endif // no. of arguments for constructor putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontEnum | DontDelete); diff --git a/Source/JavaScriptCore/runtime/StringConstructor.h b/Source/JavaScriptCore/runtime/StringConstructor.h index 20f3a52..3a42c7e 100644 --- a/Source/JavaScriptCore/runtime/StringConstructor.h +++ b/Source/JavaScriptCore/runtime/StringConstructor.h @@ -29,7 +29,7 @@ namespace JSC { class StringConstructor : public InternalFunction { public: - StringConstructor(ExecState*, JSGlobalObject*, NonNullPassRefPtr, Structure* prototypeFunctionStructure, StringPrototype*); + StringConstructor(ExecState*, JSGlobalObject*, NonNullPassRefPtr, Structure* functionStructure, StringPrototype*); virtual ConstructType getConstructData(ConstructData&); virtual CallType getCallData(CallData&); diff --git a/Source/JavaScriptCore/runtime/StringObject.cpp b/Source/JavaScriptCore/runtime/StringObject.cpp index eb9cfa3..5fe7544 100644 --- a/Source/JavaScriptCore/runtime/StringObject.cpp +++ b/Source/JavaScriptCore/runtime/StringObject.cpp @@ -27,23 +27,26 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(StringObject); -const ClassInfo StringObject::info = { "String", 0, 0, 0 }; +const ClassInfo StringObject::s_info = { "String", &JSWrapperObject::s_info, 0, 0 }; StringObject::StringObject(ExecState* exec, NonNullPassRefPtr structure) : JSWrapperObject(exec->globalData(), structure) { + ASSERT(inherits(&s_info)); setInternalValue(exec->globalData(), jsEmptyString(exec)); } StringObject::StringObject(JSGlobalData& globalData, NonNullPassRefPtr structure, JSString* string) : JSWrapperObject(globalData, structure) { + ASSERT(inherits(&s_info)); setInternalValue(globalData, string); } StringObject::StringObject(ExecState* exec, NonNullPassRefPtr structure, const UString& string) : JSWrapperObject(exec->globalData(), structure) { + ASSERT(inherits(&s_info)); setInternalValue(exec->globalData(), jsString(exec, string)); } diff --git a/Source/JavaScriptCore/runtime/StringObject.h b/Source/JavaScriptCore/runtime/StringObject.h index 03488f5..99f9add 100644 --- a/Source/JavaScriptCore/runtime/StringObject.h +++ b/Source/JavaScriptCore/runtime/StringObject.h @@ -41,14 +41,13 @@ namespace JSC { virtual bool deleteProperty(ExecState*, const Identifier& propertyName); virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties); - virtual const ClassInfo* classInfo() const { return &info; } - static const JS_EXPORTDATA ClassInfo info; + static const JS_EXPORTDATA ClassInfo s_info; JSString* internalValue() const { return asString(JSWrapperObject::internalValue());} static PassRefPtr createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: @@ -60,7 +59,7 @@ namespace JSC { inline StringObject* asStringObject(JSValue value) { - ASSERT(asObject(value)->inherits(&StringObject::info)); + ASSERT(asObject(value)->inherits(&StringObject::s_info)); return static_cast(asObject(value)); } diff --git a/Source/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h b/Source/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h index 43c3e38..0a44ed3 100644 --- a/Source/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h +++ b/Source/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h @@ -44,7 +44,7 @@ namespace JSC { static PassRefPtr createStructure(JSValue proto) { - return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } static const unsigned StructureFlags = OverridesGetOwnPropertySlot | MasqueradesAsUndefined | OverridesGetPropertyNames | StringObject::StructureFlags; diff --git a/Source/JavaScriptCore/runtime/StringPrototype.cpp b/Source/JavaScriptCore/runtime/StringPrototype.cpp index 545c93e..aa37122 100644 --- a/Source/JavaScriptCore/runtime/StringPrototype.cpp +++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp @@ -85,7 +85,7 @@ static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState*); namespace JSC { -const ClassInfo StringPrototype::info = { "String", &StringObject::info, 0, ExecState::stringTable }; +const ClassInfo StringPrototype::s_info = { "String", &StringObject::s_info, 0, ExecState::stringTable }; /* Source for StringPrototype.lut.h @begin stringTable 26 @@ -134,6 +134,8 @@ const ClassInfo StringPrototype::info = { "String", &StringObject::info, 0, Exec StringPrototype::StringPrototype(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr structure) : StringObject(exec, structure) { + ASSERT(inherits(&s_info)); + putAnonymousValue(exec->globalData(), 0, globalObject); // The constructor will be added later, after StringConstructor has been built putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum); @@ -305,7 +307,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec) if (callType == CallTypeNone) replacementString = replacement.toString(exec); - if (pattern.inherits(&RegExpObject::info)) { + if (pattern.inherits(&RegExpObject::s_info)) { const UString& source = sourceVal->value(exec); unsigned sourceLen = source.length(); if (exec->hadException()) @@ -473,7 +475,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState* exec) if (thisValue.isString()) return JSValue::encode(thisValue); - if (thisValue.inherits(&StringObject::info)) + if (thisValue.inherits(&StringObject::s_info)) return JSValue::encode(asStringObject(thisValue)->internalValue()); return throwVMTypeError(exec); @@ -605,7 +607,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec) UString u = s; RefPtr reg; RegExpObject* imp = 0; - if (a0.inherits(&RegExpObject::info)) + if (a0.inherits(&RegExpObject::s_info)) reg = asRegExpObject(a0)->regExp(); else { /* @@ -658,7 +660,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec) UString u = s; RefPtr reg; - if (a0.inherits(&RegExpObject::info)) + if (a0.inherits(&RegExpObject::s_info)) reg = asRegExpObject(a0)->regExp(); else { /* @@ -716,7 +718,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec) unsigned i = 0; unsigned p0 = 0; unsigned limit = a1.isUndefined() ? 0xFFFFFFFFU : a1.toUInt32(exec); - if (a0.inherits(&RegExpObject::info)) { + if (a0.inherits(&RegExpObject::s_info)) { RegExp* reg = asRegExpObject(a0)->regExp(); if (s.isEmpty() && reg->match(s, 0) >= 0) { // empty string matched by regexp -> empty array diff --git a/Source/JavaScriptCore/runtime/StringPrototype.h b/Source/JavaScriptCore/runtime/StringPrototype.h index 4b0f88f..feea2e2 100644 --- a/Source/JavaScriptCore/runtime/StringPrototype.h +++ b/Source/JavaScriptCore/runtime/StringPrototype.h @@ -34,8 +34,12 @@ namespace JSC { virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); - virtual const ClassInfo* classInfo() const { return &info; } - static const ClassInfo info; + static PassRefPtr createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); + } + + static const ClassInfo s_info; }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp index e8f5d7a..829e3db 100644 --- a/Source/JavaScriptCore/runtime/Structure.cpp +++ b/Source/JavaScriptCore/runtime/Structure.cpp @@ -50,23 +50,26 @@ using namespace std; using namespace WTF; -namespace JSC { +#if DUMP_PROPERTYMAP_STATS -// Choose a number for the following so that most property maps are smaller, -// but it's not going to blow out the stack to allocate this number of pointers. -static const int smallMapThreshold = 1024; +int numProbes; +int numCollisions; +int numRehashes; +int numRemoves; -// The point at which the function call overhead of the qsort implementation -// becomes small compared to the inefficiency of insertion sort. -static const unsigned tinyMapThreshold = 20; +#endif -static const unsigned newTableSize = 16; +namespace JSC { #ifndef NDEBUG static WTF::RefCountedLeakCounter structureCounter("Structure"); #if ENABLE(JSC_MULTIPLE_THREADS) -static Mutex& ignoreSetMutex = *(new Mutex); +static Mutex& ignoreSetMutex() +{ + DEFINE_STATIC_LOCAL(Mutex, mutex, ()); + return mutex; +} #endif static bool shouldIgnoreLeaks; @@ -77,105 +80,67 @@ static HashSet& ignoreSet = *(new HashSet); static HashSet& liveStructureSet = *(new HashSet); #endif -static int comparePropertyMapEntryIndices(const void* a, const void* b); - -inline void Structure::setTransitionTable(TransitionTable* table) -{ - ASSERT(m_isUsingSingleSlot); -#ifndef NDEBUG - setSingleTransition(0); -#endif - m_isUsingSingleSlot = false; - m_transitions.m_table = table; - // This implicitly clears the flag that indicates we're using a single transition - ASSERT(!m_isUsingSingleSlot); -} - -// The contains and get methods accept imprecise matches, so if an unspecialised transition exists -// for the given key they will consider that transition to be a match. If a specialised transition -// exists and it matches the provided specificValue, get will return the specific transition. -inline bool Structure::transitionTableContains(const StructureTransitionTableHash::Key& key, JSCell* specificValue) +bool StructureTransitionTable::contains(StringImpl* rep, unsigned attributes) const { - if (m_isUsingSingleSlot) { - Structure* existingTransition = singleTransition(); - return existingTransition && existingTransition->m_nameInPrevious.get() == key.first - && existingTransition->m_attributesInPrevious == key.second - && (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0); - } - TransitionTable::iterator find = transitionTable()->find(key); - if (find == transitionTable()->end()) - return false; - - return find->second.first || find->second.second->transitionedFor(specificValue); -} - -inline Structure* Structure::transitionTableGet(const StructureTransitionTableHash::Key& key, JSCell* specificValue) const -{ - if (m_isUsingSingleSlot) { - Structure* existingTransition = singleTransition(); - if (existingTransition && existingTransition->m_nameInPrevious.get() == key.first - && existingTransition->m_attributesInPrevious == key.second - && (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0)) - return existingTransition; - return 0; + if (isUsingSingleSlot()) { + Structure* transition = singleTransition(); + return transition && transition->m_nameInPrevious == rep && transition->m_attributesInPrevious == attributes; } - - Transition transition = transitionTable()->get(key); - if (transition.second && transition.second->transitionedFor(specificValue)) - return transition.second; - return transition.first; + return map()->contains(make_pair(rep, attributes)); } -inline bool Structure::transitionTableHasTransition(const StructureTransitionTableHash::Key& key) const +inline Structure* StructureTransitionTable::get(StringImpl* rep, unsigned attributes) const { - if (m_isUsingSingleSlot) { + if (isUsingSingleSlot()) { Structure* transition = singleTransition(); - return transition && transition->m_nameInPrevious == key.first - && transition->m_attributesInPrevious == key.second; + return (transition && transition->m_nameInPrevious == rep && transition->m_attributesInPrevious == attributes) ? transition : 0; } - return transitionTable()->contains(key); + return map()->get(make_pair(rep, attributes)); } -inline void Structure::transitionTableRemove(const StructureTransitionTableHash::Key& key, JSCell* specificValue) +inline void StructureTransitionTable::remove(Structure* structure) { - if (m_isUsingSingleSlot) { - ASSERT(transitionTableContains(key, specificValue)); + if (isUsingSingleSlot()) { + // If more than one transition had been added, then we wouldn't be in + // single slot mode (even despecifying a from a specific value triggers + // map mode). + // As such, the passed structure *must* be the existing transition. + ASSERT(singleTransition() == structure); setSingleTransition(0); - return; + } else { + // Check whether a mapping exists for structure's key, and whether the + // entry is structure (the latter check may fail if we initially had a + // transition with a specific value, and this has been despecified). + TransitionMap::iterator entry = map()->find(make_pair(structure->m_nameInPrevious, structure->m_attributesInPrevious)); + if (entry != map()->end() && structure == entry->second) + map()->remove(entry); } - TransitionTable::iterator find = transitionTable()->find(key); - if (!specificValue) - find->second.first = 0; - else - find->second.second = 0; - if (!find->second.first && !find->second.second) - transitionTable()->remove(find); } -inline void Structure::transitionTableAdd(const StructureTransitionTableHash::Key& key, Structure* structure, JSCell* specificValue) +inline void StructureTransitionTable::add(Structure* structure) { - if (m_isUsingSingleSlot) { - if (!singleTransition()) { + if (isUsingSingleSlot()) { + Structure* existingTransition = singleTransition(); + + // This handles the first transition being added. + if (!existingTransition) { setSingleTransition(structure); return; } - Structure* existingTransition = singleTransition(); - TransitionTable* transitionTable = new TransitionTable; - setTransitionTable(transitionTable); - if (existingTransition) - transitionTableAdd(std::make_pair(existingTransition->m_nameInPrevious.get(), existingTransition->m_attributesInPrevious), existingTransition, existingTransition->m_specificValueInPrevious); + + // This handles the second transition being added + // (or the first transition being despecified!) + setMap(new TransitionMap()); + add(existingTransition); } - if (!specificValue) { - TransitionTable::iterator find = transitionTable()->find(key); - if (find == transitionTable()->end()) - transitionTable()->add(key, Transition(structure, static_cast(0))); - else - find->second.first = structure; - } else { - // If we're adding a transition to a specific value, then there cannot be - // an existing transition - ASSERT(!transitionTable()->contains(key)); - transitionTable()->add(key, Transition(static_cast(0), structure)); + + // Add the structure to the map. + std::pair result = map()->add(make_pair(structure->m_nameInPrevious, structure->m_attributesInPrevious), structure); + if (!result.second) { + // There already is an entry! - we should only hit this when despecifying. + ASSERT(result.first->second->m_specificValueInPrevious); + ASSERT(!structure->m_specificValueInPrevious); + result.first->second = structure; } } @@ -191,21 +156,22 @@ void Structure::dumpStatistics() HashSet::const_iterator end = liveStructureSet.end(); for (HashSet::const_iterator it = liveStructureSet.begin(); it != end; ++it) { Structure* structure = *it; - if (structure->m_usingSingleTransitionSlot) { - if (!structure->m_transitions.singleTransition) + + switch (structure->m_transitionTable.size()) { + case 0: ++numberLeaf; - else - ++numberUsingSingleSlot; + if (!structure->m_previous) + ++numberSingletons; + break; - if (!structure->m_previous && !structure->m_transitions.singleTransition) - ++numberSingletons; + case 1: + ++numberUsingSingleSlot; + break; } if (structure->m_propertyTable) { ++numberWithPropertyMaps; - totalPropertyMapsSize += PropertyMapHashTable::allocationSize(structure->m_propertyTable->size); - if (structure->m_propertyTable->deletedOffsets) - totalPropertyMapsSize += (structure->m_propertyTable->deletedOffsets->capacity() * sizeof(unsigned)); + totalPropertyMapsSize += structure->m_propertyTable->sizeInMemory(); } } @@ -223,12 +189,12 @@ void Structure::dumpStatistics() #endif } -Structure::Structure(JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount) +Structure::Structure(JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount, const ClassInfo* classInfo) : m_typeInfo(typeInfo) , m_prototype(prototype) , m_specificValueInPrevious(0) - , m_propertyTable(0) - , m_propertyStorageCapacity(JSObject::inlineStorageCapacity) + , m_classInfo(classInfo) + , m_propertyStorageCapacity(typeInfo.isFinal() ? JSFinalObject_inlineStorageCapacity : JSNonFinalObject_inlineStorageCapacity) , m_offset(noOffset) , m_dictionaryKind(NoneDictionaryKind) , m_isPinnedPropertyTable(false) @@ -237,16 +203,48 @@ Structure::Structure(JSValue prototype, const TypeInfo& typeInfo, unsigned anony , m_attributesInPrevious(0) , m_specificFunctionThrashCount(0) , m_anonymousSlotCount(anonymousSlotCount) - , m_isUsingSingleSlot(true) + , m_preventExtensions(false) { - m_transitions.m_singleTransition = 0; + ASSERT(m_prototype); + ASSERT(m_prototype->isObject() || m_prototype->isNull()); + +#ifndef NDEBUG +#if ENABLE(JSC_MULTIPLE_THREADS) + MutexLocker protect(ignoreSetMutex()); +#endif + if (shouldIgnoreLeaks) + ignoreSet.add(this); + else + structureCounter.increment(); +#endif + +#if DUMP_STRUCTURE_ID_STATISTICS + liveStructureSet.add(this); +#endif +} +Structure::Structure(const Structure* previous) + : m_typeInfo(previous->typeInfo()) + , m_prototype(previous->storedPrototype()) + , m_specificValueInPrevious(0) + , m_classInfo(previous->m_classInfo) + , m_propertyStorageCapacity(previous->m_propertyStorageCapacity) + , m_offset(noOffset) + , m_dictionaryKind(NoneDictionaryKind) + , m_isPinnedPropertyTable(false) + , m_hasGetterSetterProperties(previous->m_hasGetterSetterProperties) + , m_hasNonEnumerableProperties(previous->m_hasNonEnumerableProperties) + , m_attributesInPrevious(0) + , m_specificFunctionThrashCount(previous->m_specificFunctionThrashCount) + , m_anonymousSlotCount(previous->anonymousSlotCount()) + , m_preventExtensions(previous->m_preventExtensions) +{ ASSERT(m_prototype); ASSERT(m_prototype->isObject() || m_prototype->isNull()); #ifndef NDEBUG #if ENABLE(JSC_MULTIPLE_THREADS) - MutexLocker protect(ignoreSetMutex); + MutexLocker protect(ignoreSetMutex()); #endif if (shouldIgnoreLeaks) ignoreSet.add(this); @@ -263,28 +261,12 @@ Structure::~Structure() { if (m_previous) { ASSERT(m_nameInPrevious); - m_previous->transitionTableRemove(make_pair(m_nameInPrevious.get(), m_attributesInPrevious), m_specificValueInPrevious); - - } - ASSERT(!m_enumerationCache.hasDeadObject()); - - if (m_propertyTable) { - unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; - for (unsigned i = 1; i <= entryCount; i++) { - if (StringImpl* key = m_propertyTable->entries()[i].key) - key->deref(); - } - - delete m_propertyTable->deletedOffsets; - fastFree(m_propertyTable); + m_previous->m_transitionTable.remove(this); } - if (!m_isUsingSingleSlot) - delete transitionTable(); - #ifndef NDEBUG #if ENABLE(JSC_MULTIPLE_THREADS) - MutexLocker protect(ignoreSetMutex); + MutexLocker protect(ignoreSetMutex()); #endif HashSet::iterator it = ignoreSet.find(this); if (it != ignoreSet.end()) @@ -312,43 +294,6 @@ void Structure::stopIgnoringLeaks() #endif } -static bool isPowerOf2(unsigned v) -{ - // Taken from http://www.cs.utk.edu/~vose/c-stuff/bithacks.html - - return !(v & (v - 1)) && v; -} - -static unsigned nextPowerOf2(unsigned v) -{ - // Taken from http://www.cs.utk.edu/~vose/c-stuff/bithacks.html - // Devised by Sean Anderson, Sepember 14, 2001 - - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - - return v; -} - -static unsigned sizeForKeyCount(size_t keyCount) -{ - if (keyCount == notFound) - return newTableSize; - - if (keyCount < 8) - return newTableSize; - - if (isPowerOf2(keyCount)) - return keyCount * 4; - - return nextPowerOf2(keyCount) * 2; -} - void Structure::materializePropertyMap() { ASSERT(!m_propertyTable); @@ -358,13 +303,13 @@ void Structure::materializePropertyMap() Structure* structure = this; - // Search for the last Structure with a property table. + // Search for the last Structure with a property table. while ((structure = structure->previousID())) { if (structure->m_isPinnedPropertyTable) { ASSERT(structure->m_propertyTable); ASSERT(!structure->m_previous); - m_propertyTable = structure->copyPropertyTable(); + m_propertyTable = structure->m_propertyTable->copy(m_offset + 1); break; } @@ -372,72 +317,35 @@ void Structure::materializePropertyMap() } if (!m_propertyTable) - createPropertyMapHashTable(sizeForKeyCount(m_offset + 1)); - else { - if (sizeForKeyCount(m_offset + 1) > m_propertyTable->size) - rehashPropertyMapHashTable(sizeForKeyCount(m_offset + 1)); // This could be made more efficient by combining with the copy above. - } + createPropertyMap(m_offset + 1); for (ptrdiff_t i = structures.size() - 2; i >= 0; --i) { structure = structures[i]; - structure->m_nameInPrevious->ref(); - PropertyMapEntry entry(structure->m_nameInPrevious.get(), m_anonymousSlotCount + structure->m_offset, structure->m_attributesInPrevious, structure->m_specificValueInPrevious, ++m_propertyTable->lastIndexUsed); - insertIntoPropertyMapHashTable(entry); + PropertyMapEntry entry(structure->m_nameInPrevious.get(), m_anonymousSlotCount + structure->m_offset, structure->m_attributesInPrevious, structure->m_specificValueInPrevious); + m_propertyTable->add(entry); } } void Structure::growPropertyStorageCapacity() { - if (m_propertyStorageCapacity == JSObject::inlineStorageCapacity) - m_propertyStorageCapacity = JSObject::nonInlineBaseStorageCapacity; + if (isUsingInlineStorage()) + m_propertyStorageCapacity = JSObject::baseExternalStorageCapacity; else m_propertyStorageCapacity *= 2; } void Structure::despecifyDictionaryFunction(const Identifier& propertyName) { - const StringImpl* rep = propertyName.impl(); + StringImpl* rep = propertyName.impl(); materializePropertyMapIfNecessary(); ASSERT(isDictionary()); ASSERT(m_propertyTable); - unsigned i = rep->existingHash(); - -#if DUMP_PROPERTYMAP_STATS - ++numProbes; -#endif - - unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; - ASSERT(entryIndex != emptyEntryIndex); - - if (rep == m_propertyTable->entries()[entryIndex - 1].key) { - m_propertyTable->entries()[entryIndex - 1].specificValue = 0; - return; - } - -#if DUMP_PROPERTYMAP_STATS - ++numCollisions; -#endif - - unsigned k = 1 | doubleHash(rep->existingHash()); - - while (1) { - i += k; - -#if DUMP_PROPERTYMAP_STATS - ++numRehashes; -#endif - - entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; - ASSERT(entryIndex != emptyEntryIndex); - - if (rep == m_propertyTable->entries()[entryIndex - 1].key) { - m_propertyTable->entries()[entryIndex - 1].specificValue = 0; - return; - } - } + PropertyMapEntry* entry = m_propertyTable->find(rep).first; + ASSERT(entry); + entry->specificValue = 0; } PassRefPtr Structure::addPropertyTransitionToExistingStructure(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset) @@ -445,7 +353,10 @@ PassRefPtr Structure::addPropertyTransitionToExistingStructure(Struct ASSERT(!structure->isDictionary()); ASSERT(structure->typeInfo().type() == ObjectType); - if (Structure* existingTransition = structure->transitionTableGet(make_pair(propertyName.impl(), attributes), specificValue)) { + if (Structure* existingTransition = structure->m_transitionTable.get(propertyName.impl(), attributes)) { + JSCell* specificValueInPrevious = existingTransition->m_specificValueInPrevious; + if (specificValueInPrevious && specificValueInPrevious != specificValue) + return 0; ASSERT(existingTransition->m_offset != noOffset); offset = existingTransition->m_offset + existingTransition->m_anonymousSlotCount; ASSERT(offset >= structure->m_anonymousSlotCount); @@ -458,6 +369,16 @@ PassRefPtr Structure::addPropertyTransitionToExistingStructure(Struct PassRefPtr Structure::addPropertyTransition(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset) { + // If we have a specific function, we may have got to this point if there is + // already a transition with the correct property name and attributes, but + // specialized to a different function. In this case we just want to give up + // and despecialize the transition. + // In this case we clear the value of specificFunction which will result + // in us adding a non-specific transition, and any subsequent lookup in + // Structure::addPropertyTransitionToExistingStructure will just use that. + if (specificValue && structure->m_transitionTable.contains(propertyName.impl(), attributes)) + specificValue = 0; + ASSERT(!structure->isDictionary()); ASSERT(structure->typeInfo().type() == ObjectType); ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, specificValue, offset)); @@ -476,30 +397,24 @@ PassRefPtr Structure::addPropertyTransition(Structure* structure, con return transition.release(); } - RefPtr transition = create(structure->m_prototype.get(), structure->typeInfo(), structure->anonymousSlotCount()); + RefPtr transition = create(structure); transition->m_cachedPrototypeChain = structure->m_cachedPrototypeChain; transition->m_previous = structure; transition->m_nameInPrevious = propertyName.impl(); transition->m_attributesInPrevious = attributes; transition->m_specificValueInPrevious = specificValue; - transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; - transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties; - transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties; - transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount; if (structure->m_propertyTable) { if (structure->m_isPinnedPropertyTable) - transition->m_propertyTable = structure->copyPropertyTable(); - else { - transition->m_propertyTable = structure->m_propertyTable; - structure->m_propertyTable = 0; - } + transition->m_propertyTable = structure->m_propertyTable->copy(structure->m_propertyTable->size() + 1); + else + transition->m_propertyTable = structure->m_propertyTable.release(); } else { if (structure->m_previous) transition->materializePropertyMap(); else - transition->createPropertyMapHashTable(); + transition->createPropertyMap(); } offset = transition->put(propertyName, attributes, specificValue); @@ -510,7 +425,7 @@ PassRefPtr Structure::addPropertyTransition(Structure* structure, con transition->m_offset = offset - structure->m_anonymousSlotCount; ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount()); - structure->transitionTableAdd(make_pair(propertyName.impl(), attributes), transition.get(), specificValue); + structure->m_transitionTable.add(transition.get()); return transition.release(); } @@ -529,12 +444,9 @@ PassRefPtr Structure::removePropertyTransition(Structure* structure, PassRefPtr Structure::changePrototypeTransition(Structure* structure, JSValue prototype) { - RefPtr transition = create(prototype, structure->typeInfo(), structure->anonymousSlotCount()); + RefPtr transition = create(structure); - transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; - transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties; - transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties; - transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount; + transition->m_prototype = prototype; // Don't set m_offset, as one can not transition to this. @@ -549,12 +461,9 @@ PassRefPtr Structure::changePrototypeTransition(Structure* structure, PassRefPtr Structure::despecifyFunctionTransition(Structure* structure, const Identifier& replaceFunction) { ASSERT(structure->m_specificFunctionThrashCount < maxSpecificFunctionThrashCount); - RefPtr transition = create(structure->storedPrototype(), structure->typeInfo(), structure->anonymousSlotCount()); + RefPtr transition = create(structure); - transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; - transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties; - transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties; - transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount + 1; + ++transition->m_specificFunctionThrashCount; // Don't set m_offset, as one can not transition to this. @@ -575,11 +484,7 @@ PassRefPtr Structure::despecifyFunctionTransition(Structure* structur PassRefPtr Structure::getterSetterTransition(Structure* structure) { - RefPtr transition = create(structure->storedPrototype(), structure->typeInfo(), structure->anonymousSlotCount()); - transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; - transition->m_hasGetterSetterProperties = transition->m_hasGetterSetterProperties; - transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties; - transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount; + RefPtr transition = create(structure); // Don't set m_offset, as one can not transition to this. @@ -595,16 +500,12 @@ PassRefPtr Structure::toDictionaryTransition(Structure* structure, Di { ASSERT(!structure->isUncacheableDictionary()); - RefPtr transition = create(structure->m_prototype.get(), structure->typeInfo(), structure->anonymousSlotCount()); - transition->m_dictionaryKind = kind; - transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; - transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties; - transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties; - transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount; - + RefPtr transition = create(structure); + structure->materializePropertyMapIfNecessary(); transition->m_propertyTable = structure->copyPropertyTable(); transition->m_isPinnedPropertyTable = true; + transition->m_dictionaryKind = kind; ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount()); return transition.release(); @@ -620,43 +521,109 @@ PassRefPtr Structure::toUncacheableDictionaryTransition(Structure* st return toDictionaryTransition(structure, UncachedDictionaryKind); } +// In future we may want to cache this transition. +PassRefPtr Structure::sealTransition(Structure* structure) +{ + RefPtr transition = preventExtensionsTransition(structure); + + if (transition->m_propertyTable) { + PropertyTable::iterator end = transition->m_propertyTable->end(); + for (PropertyTable::iterator iter = transition->m_propertyTable->begin(); iter != end; ++iter) + iter->attributes |= DontDelete; + } + + return transition.release(); +} + +// In future we may want to cache this transition. +PassRefPtr Structure::freezeTransition(Structure* structure) +{ + RefPtr transition = preventExtensionsTransition(structure); + + if (transition->m_propertyTable) { + PropertyTable::iterator end = transition->m_propertyTable->end(); + for (PropertyTable::iterator iter = transition->m_propertyTable->begin(); iter != end; ++iter) + iter->attributes |= (DontDelete | ReadOnly); + } + + return transition.release(); +} + +// In future we may want to cache this transition. +PassRefPtr Structure::preventExtensionsTransition(Structure* structure) +{ + RefPtr transition = create(structure); + + // Don't set m_offset, as one can not transition to this. + + structure->materializePropertyMapIfNecessary(); + transition->m_propertyTable = structure->copyPropertyTable(); + transition->m_isPinnedPropertyTable = true; + transition->m_preventExtensions = true; + + ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount()); + return transition.release(); +} + +// In future we may want to cache this property. +bool Structure::isSealed() +{ + if (isExtensible()) + return false; + + materializePropertyMapIfNecessary(); + if (!m_propertyTable) + return true; + + PropertyTable::iterator end = m_propertyTable->end(); + for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) { + if ((iter->attributes & DontDelete) != DontDelete) + return false; + } + return true; +} + +// In future we may want to cache this property. +bool Structure::isFrozen() +{ + if (isExtensible()) + return false; + + materializePropertyMapIfNecessary(); + if (!m_propertyTable) + return true; + + PropertyTable::iterator end = m_propertyTable->end(); + for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) { + if ((iter->attributes & (DontDelete | ReadOnly)) != (DontDelete | ReadOnly)) + return false; + } + return true; +} + PassRefPtr Structure::flattenDictionaryStructure(JSGlobalData& globalData, JSObject* object) { ASSERT(isDictionary()); if (isUncacheableDictionary()) { ASSERT(m_propertyTable); - Vector sortedPropertyEntries(m_propertyTable->keyCount); - PropertyMapEntry** p = sortedPropertyEntries.data(); - unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; - for (unsigned i = 1; i <= entryCount; i++) { - if (m_propertyTable->entries()[i].key) - *p++ = &m_propertyTable->entries()[i]; - } - size_t propertyCount = p - sortedPropertyEntries.data(); - qsort(sortedPropertyEntries.data(), propertyCount, sizeof(PropertyMapEntry*), comparePropertyMapEntryIndices); - sortedPropertyEntries.resize(propertyCount); - // We now have the properties currently defined on this object - // in the order that they are expected to be in, but we need to - // reorder the storage, so we have to copy the current values out - Vector values(propertyCount); unsigned anonymousSlotCount = m_anonymousSlotCount; - for (unsigned i = 0; i < propertyCount; i++) { - PropertyMapEntry* entry = sortedPropertyEntries[i]; - values[i] = object->getDirectOffset(entry->offset); + size_t propertyCount = m_propertyTable->size(); + Vector values(propertyCount); + + unsigned i = 0; + 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 - entry->offset = anonymousSlotCount + i; - entry->index = i; + iter->offset = anonymousSlotCount + i; } // Copy the original property values into their final locations for (unsigned i = 0; i < propertyCount; i++) object->putDirectOffset(globalData, anonymousSlotCount + i, values[i]); - if (m_propertyTable->deletedOffsets) { - delete m_propertyTable->deletedOffsets; - m_propertyTable->deletedOffsets = 0; - } + m_propertyTable->clearDeletedOffsets(); } m_dictionaryKind = NoneDictionaryKind; @@ -696,11 +663,6 @@ size_t Structure::removePropertyWithoutTransition(const Identifier& propertyName #if DUMP_PROPERTYMAP_STATS -static int numProbes; -static int numCollisions; -static int numRehashes; -static int numRemoves; - struct PropertyMapStatisticsExitLogger { ~PropertyMapStatisticsExitLogger(); }; @@ -718,8 +680,6 @@ PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger() #endif -static const unsigned deletedSentinelIndex = 1; - #if !DO_PROPERTYMAP_CONSTENCY_CHECK inline void Structure::checkConsistency() @@ -728,126 +688,41 @@ inline void Structure::checkConsistency() #endif -PropertyMapHashTable* Structure::copyPropertyTable() +PropertyTable* Structure::copyPropertyTable() { - if (!m_propertyTable) - return 0; - - size_t tableSize = PropertyMapHashTable::allocationSize(m_propertyTable->size); - PropertyMapHashTable* newTable = static_cast(fastMalloc(tableSize)); - memcpy(newTable, m_propertyTable, tableSize); - - unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; - for (unsigned i = 1; i <= entryCount; ++i) { - if (StringImpl* key = newTable->entries()[i].key) - key->ref(); - } - - // Copy the deletedOffsets vector. - if (m_propertyTable->deletedOffsets) - newTable->deletedOffsets = new Vector(*m_propertyTable->deletedOffsets); - - return newTable; + return m_propertyTable ? new PropertyTable(*m_propertyTable) : 0; } -size_t Structure::get(const StringImpl* rep, unsigned& attributes, JSCell*& specificValue) +size_t Structure::get(StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue) { materializePropertyMapIfNecessary(); if (!m_propertyTable) - return notFound; + return WTF::notFound; - unsigned i = rep->existingHash(); + PropertyMapEntry* entry = m_propertyTable->find(propertyName).first; + if (!entry) + return WTF::notFound; -#if DUMP_PROPERTYMAP_STATS - ++numProbes; -#endif - - unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; - if (entryIndex == emptyEntryIndex) - return notFound; - - if (rep == m_propertyTable->entries()[entryIndex - 1].key) { - attributes = m_propertyTable->entries()[entryIndex - 1].attributes; - specificValue = m_propertyTable->entries()[entryIndex - 1].specificValue; - ASSERT(m_propertyTable->entries()[entryIndex - 1].offset >= m_anonymousSlotCount); - return m_propertyTable->entries()[entryIndex - 1].offset; - } - -#if DUMP_PROPERTYMAP_STATS - ++numCollisions; -#endif - - unsigned k = 1 | doubleHash(rep->existingHash()); - - while (1) { - i += k; - -#if DUMP_PROPERTYMAP_STATS - ++numRehashes; -#endif - - entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; - if (entryIndex == emptyEntryIndex) - return notFound; - - if (rep == m_propertyTable->entries()[entryIndex - 1].key) { - attributes = m_propertyTable->entries()[entryIndex - 1].attributes; - specificValue = m_propertyTable->entries()[entryIndex - 1].specificValue; - ASSERT(m_propertyTable->entries()[entryIndex - 1].offset >= m_anonymousSlotCount); - return m_propertyTable->entries()[entryIndex - 1].offset; - } - } + attributes = entry->attributes; + specificValue = entry->specificValue; + ASSERT(entry->offset >= m_anonymousSlotCount); + return entry->offset; } bool Structure::despecifyFunction(const Identifier& propertyName) { - ASSERT(!propertyName.isNull()); - materializePropertyMapIfNecessary(); if (!m_propertyTable) return false; - StringImpl* rep = propertyName.impl(); - - unsigned i = rep->existingHash(); - -#if DUMP_PROPERTYMAP_STATS - ++numProbes; -#endif - - unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; - if (entryIndex == emptyEntryIndex) + ASSERT(!propertyName.isNull()); + PropertyMapEntry* entry = m_propertyTable->find(propertyName.impl()).first; + if (!entry) return false; - if (rep == m_propertyTable->entries()[entryIndex - 1].key) { - ASSERT(m_propertyTable->entries()[entryIndex - 1].specificValue); - m_propertyTable->entries()[entryIndex - 1].specificValue = 0; - return true; - } - -#if DUMP_PROPERTYMAP_STATS - ++numCollisions; -#endif - - unsigned k = 1 | doubleHash(rep->existingHash()); - - while (1) { - i += k; - -#if DUMP_PROPERTYMAP_STATS - ++numRehashes; -#endif - - entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; - if (entryIndex == emptyEntryIndex) - return false; - - if (rep == m_propertyTable->entries()[entryIndex - 1].key) { - ASSERT(m_propertyTable->entries()[entryIndex - 1].specificValue); - m_propertyTable->entries()[entryIndex - 1].specificValue = 0; - return true; - } - } + ASSERT(entry->specificValue); + entry->specificValue = 0; + return true; } void Structure::despecifyAllFunctions() @@ -855,10 +730,10 @@ void Structure::despecifyAllFunctions() materializePropertyMapIfNecessary(); if (!m_propertyTable) return; - - unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; - for (unsigned i = 1; i <= entryCount; ++i) - m_propertyTable->entries()[i].specificValue = 0; + + PropertyTable::iterator end = m_propertyTable->end(); + for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) + iter->specificValue = 0; } size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue) @@ -867,99 +742,28 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCel ASSERT(get(propertyName) == notFound); checkConsistency(); - if (attributes & DontEnum) m_hasNonEnumerableProperties = true; StringImpl* rep = propertyName.impl(); if (!m_propertyTable) - createPropertyMapHashTable(); - - // FIXME: Consider a fast case for tables with no deleted sentinels. - - unsigned i = rep->existingHash(); - unsigned k = 0; - bool foundDeletedElement = false; - unsigned deletedElementIndex = 0; // initialize to make the compiler happy - -#if DUMP_PROPERTYMAP_STATS - ++numProbes; -#endif - - while (1) { - unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; - if (entryIndex == emptyEntryIndex) - break; - - if (entryIndex == deletedSentinelIndex) { - // If we find a deleted-element sentinel, remember it for use later. - if (!foundDeletedElement) { - foundDeletedElement = true; - deletedElementIndex = i; - } - } - - if (k == 0) { - k = 1 | doubleHash(rep->existingHash()); -#if DUMP_PROPERTYMAP_STATS - ++numCollisions; -#endif - } - - i += k; - -#if DUMP_PROPERTYMAP_STATS - ++numRehashes; -#endif - } - - // Figure out which entry to use. - unsigned entryIndex = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount + 2; - if (foundDeletedElement) { - i = deletedElementIndex; - --m_propertyTable->deletedSentinelCount; - - // Since we're not making the table bigger, we can't use the entry one past - // the end that we were planning on using, so search backwards for the empty - // slot that we can use. We know it will be there because we did at least one - // deletion in the past that left an entry empty. - while (m_propertyTable->entries()[--entryIndex - 1].key) { } - } - - // Create a new hash table entry. - m_propertyTable->entryIndices[i & m_propertyTable->sizeMask] = entryIndex; - - // Create a new hash table entry. - rep->ref(); - m_propertyTable->entries()[entryIndex - 1].key = rep; - m_propertyTable->entries()[entryIndex - 1].attributes = attributes; - m_propertyTable->entries()[entryIndex - 1].specificValue = specificValue; - m_propertyTable->entries()[entryIndex - 1].index = ++m_propertyTable->lastIndexUsed; + createPropertyMap(); unsigned newOffset; - if (m_propertyTable->deletedOffsets && !m_propertyTable->deletedOffsets->isEmpty()) { - newOffset = m_propertyTable->deletedOffsets->last(); - m_propertyTable->deletedOffsets->removeLast(); - } else - newOffset = m_propertyTable->keyCount + m_anonymousSlotCount; - m_propertyTable->entries()[entryIndex - 1].offset = newOffset; - + + if (m_propertyTable->hasDeletedOffset()) + newOffset = m_propertyTable->getDeletedOffset(); + else + newOffset = m_propertyTable->size() + m_anonymousSlotCount; ASSERT(newOffset >= m_anonymousSlotCount); - ++m_propertyTable->keyCount; - if ((m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount) * 2 >= m_propertyTable->size) - expandPropertyMapHashTable(); + m_propertyTable->add(PropertyMapEntry(rep, newOffset, attributes, specificValue)); checkConsistency(); return newOffset; } -bool Structure::hasTransition(StringImpl* rep, unsigned attributes) -{ - return transitionTableHasTransition(make_pair(rep, attributes)); -} - size_t Structure::remove(const Identifier& propertyName) { ASSERT(!propertyName.isNull()); @@ -971,289 +775,104 @@ size_t Structure::remove(const Identifier& propertyName) if (!m_propertyTable) return notFound; -#if DUMP_PROPERTYMAP_STATS - ++numProbes; - ++numRemoves; -#endif - - // Find the thing to remove. - unsigned i = rep->existingHash(); - unsigned k = 0; - unsigned entryIndex; - StringImpl* key = 0; - while (1) { - entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; - if (entryIndex == emptyEntryIndex) - return notFound; - - key = m_propertyTable->entries()[entryIndex - 1].key; - if (rep == key) - break; - - if (k == 0) { - k = 1 | doubleHash(rep->existingHash()); -#if DUMP_PROPERTYMAP_STATS - ++numCollisions; -#endif - } - - i += k; - -#if DUMP_PROPERTYMAP_STATS - ++numRehashes; -#endif - } - - // Replace this one element with the deleted sentinel. Also clear out - // the entry so we can iterate all the entries as needed. - m_propertyTable->entryIndices[i & m_propertyTable->sizeMask] = deletedSentinelIndex; + PropertyTable::find_iterator position = m_propertyTable->find(rep); + if (!position.first) + return notFound; - size_t offset = m_propertyTable->entries()[entryIndex - 1].offset; + size_t offset = position.first->offset; ASSERT(offset >= m_anonymousSlotCount); - key->deref(); - m_propertyTable->entries()[entryIndex - 1].key = 0; - m_propertyTable->entries()[entryIndex - 1].attributes = 0; - m_propertyTable->entries()[entryIndex - 1].specificValue = 0; - m_propertyTable->entries()[entryIndex - 1].offset = 0; - - if (!m_propertyTable->deletedOffsets) - m_propertyTable->deletedOffsets = new Vector; - m_propertyTable->deletedOffsets->append(offset); - - ASSERT(m_propertyTable->keyCount >= 1); - --m_propertyTable->keyCount; - ++m_propertyTable->deletedSentinelCount; - - if (m_propertyTable->deletedSentinelCount * 4 >= m_propertyTable->size) - rehashPropertyMapHashTable(); + m_propertyTable->remove(position); + m_propertyTable->addDeletedOffset(offset); checkConsistency(); return offset; } -void Structure::insertIntoPropertyMapHashTable(const PropertyMapEntry& entry) -{ - ASSERT(m_propertyTable); - ASSERT(entry.offset >= m_anonymousSlotCount); - unsigned i = entry.key->existingHash(); - unsigned k = 0; - -#if DUMP_PROPERTYMAP_STATS - ++numProbes; -#endif - - while (1) { - unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; - if (entryIndex == emptyEntryIndex) - break; - - if (k == 0) { - k = 1 | doubleHash(entry.key->existingHash()); -#if DUMP_PROPERTYMAP_STATS - ++numCollisions; -#endif - } - - i += k; - -#if DUMP_PROPERTYMAP_STATS - ++numRehashes; -#endif - } - - unsigned entryIndex = m_propertyTable->keyCount + 2; - m_propertyTable->entryIndices[i & m_propertyTable->sizeMask] = entryIndex; - m_propertyTable->entries()[entryIndex - 1] = entry; - - ++m_propertyTable->keyCount; -} - -void Structure::createPropertyMapHashTable() -{ - ASSERT(sizeForKeyCount(7) == newTableSize); - createPropertyMapHashTable(newTableSize); -} - -void Structure::createPropertyMapHashTable(unsigned newTableSize) +void Structure::createPropertyMap(unsigned capacity) { ASSERT(!m_propertyTable); - ASSERT(isPowerOf2(newTableSize)); checkConsistency(); - - m_propertyTable = static_cast(fastZeroedMalloc(PropertyMapHashTable::allocationSize(newTableSize))); - m_propertyTable->size = newTableSize; - m_propertyTable->sizeMask = newTableSize - 1; - + m_propertyTable = new PropertyTable(capacity); checkConsistency(); } -void Structure::expandPropertyMapHashTable() -{ - ASSERT(m_propertyTable); - rehashPropertyMapHashTable(m_propertyTable->size * 2); -} - -void Structure::rehashPropertyMapHashTable() -{ - ASSERT(m_propertyTable); - ASSERT(m_propertyTable->size); - rehashPropertyMapHashTable(m_propertyTable->size); -} - -void Structure::rehashPropertyMapHashTable(unsigned newTableSize) -{ - ASSERT(m_propertyTable); - ASSERT(isPowerOf2(newTableSize)); - - checkConsistency(); - - PropertyMapHashTable* oldTable = m_propertyTable; - - m_propertyTable = static_cast(fastZeroedMalloc(PropertyMapHashTable::allocationSize(newTableSize))); - m_propertyTable->size = newTableSize; - m_propertyTable->sizeMask = newTableSize - 1; - - unsigned lastIndexUsed = 0; - unsigned entryCount = oldTable->keyCount + oldTable->deletedSentinelCount; - for (unsigned i = 1; i <= entryCount; ++i) { - if (oldTable->entries()[i].key) { - lastIndexUsed = max(oldTable->entries()[i].index, lastIndexUsed); - insertIntoPropertyMapHashTable(oldTable->entries()[i]); - } - } - m_propertyTable->lastIndexUsed = lastIndexUsed; - m_propertyTable->deletedOffsets = oldTable->deletedOffsets; - - fastFree(oldTable); - - checkConsistency(); -} - -int comparePropertyMapEntryIndices(const void* a, const void* b) -{ - unsigned ia = static_cast(a)[0]->index; - unsigned ib = static_cast(b)[0]->index; - if (ia < ib) - return -1; - if (ia > ib) - return +1; - return 0; -} - void Structure::getPropertyNames(PropertyNameArray& propertyNames, EnumerationMode mode) { materializePropertyMapIfNecessary(); if (!m_propertyTable) return; - if (m_propertyTable->keyCount < tinyMapThreshold) { - PropertyMapEntry* a[tinyMapThreshold]; - int i = 0; - unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; - for (unsigned k = 1; k <= entryCount; k++) { - ASSERT(m_hasNonEnumerableProperties || !(m_propertyTable->entries()[k].attributes & DontEnum)); - if (m_propertyTable->entries()[k].key && (!(m_propertyTable->entries()[k].attributes & DontEnum) || (mode == IncludeDontEnumProperties))) { - PropertyMapEntry* value = &m_propertyTable->entries()[k]; - int j; - for (j = i - 1; j >= 0 && a[j]->index > value->index; --j) - a[j + 1] = a[j]; - a[j + 1] = value; - ++i; - } - } - if (!propertyNames.size()) { - for (int k = 0; k < i; ++k) - propertyNames.addKnownUnique(a[k]->key); - } else { - for (int k = 0; k < i; ++k) - propertyNames.add(a[k]->key); - } - - return; - } - - // Allocate a buffer to use to sort the keys. - Vector sortedEnumerables(m_propertyTable->keyCount); + bool knownUnique = !propertyNames.size(); - // Get pointers to the enumerable entries in the buffer. - PropertyMapEntry** p = sortedEnumerables.data(); - unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; - for (unsigned i = 1; i <= entryCount; i++) { - if (m_propertyTable->entries()[i].key && (!(m_propertyTable->entries()[i].attributes & DontEnum) || (mode == IncludeDontEnumProperties))) - *p++ = &m_propertyTable->entries()[i]; + PropertyTable::iterator end = m_propertyTable->end(); + for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) { + ASSERT(m_hasNonEnumerableProperties || !(iter->attributes & DontEnum)); + if (!(iter->attributes & DontEnum) || (mode == IncludeDontEnumProperties)) { + if (knownUnique) + propertyNames.addKnownUnique(iter->key); + else + propertyNames.add(iter->key); + } } +} - size_t enumerableCount = p - sortedEnumerables.data(); - // Sort the entries by index. - qsort(sortedEnumerables.data(), enumerableCount, sizeof(PropertyMapEntry*), comparePropertyMapEntryIndices); - sortedEnumerables.resize(enumerableCount); - - // Put the keys of the sorted entries into the list. - if (!propertyNames.size()) { - for (size_t i = 0; i < sortedEnumerables.size(); ++i) - propertyNames.addKnownUnique(sortedEnumerables[i]->key); - } else { - for (size_t i = 0; i < sortedEnumerables.size(); ++i) - propertyNames.add(sortedEnumerables[i]->key); - } +void Structure::initializeThreading() +{ +#if !defined(NDEBUG) && ENABLE(JSC_MULTIPLE_THREADS) + ignoreSetMutex(); +#endif } #if DO_PROPERTYMAP_CONSTENCY_CHECK -void Structure::checkConsistency() +void PropertyTable::checkConsistency() { - if (!m_propertyTable) - return; - - ASSERT(m_propertyTable->size >= newTableSize); - ASSERT(m_propertyTable->sizeMask); - ASSERT(m_propertyTable->size == m_propertyTable->sizeMask + 1); - ASSERT(!(m_propertyTable->size & m_propertyTable->sizeMask)); - - ASSERT(m_propertyTable->keyCount <= m_propertyTable->size / 2); - ASSERT(m_propertyTable->deletedSentinelCount <= m_propertyTable->size / 4); + ASSERT(m_indexSize >= PropertyTable::MinimumTableSize); + ASSERT(m_indexMask); + ASSERT(m_indexSize == m_indexMask + 1); + ASSERT(!(m_indexSize & m_indexMask)); - ASSERT(m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount <= m_propertyTable->size / 2); + ASSERT(m_keyCount <= m_indexSize / 2); + ASSERT(m_keyCount + m_deletedCount <= m_indexSize / 2); + ASSERT(m_deletedCount <= m_indexSize / 4); unsigned indexCount = 0; unsigned deletedIndexCount = 0; - for (unsigned a = 0; a != m_propertyTable->size; ++a) { - unsigned entryIndex = m_propertyTable->entryIndices[a]; - if (entryIndex == emptyEntryIndex) + for (unsigned a = 0; a != m_indexSize; ++a) { + unsigned entryIndex = m_index[a]; + if (entryIndex == PropertyTable::EmptyEntryIndex) continue; - if (entryIndex == deletedSentinelIndex) { + if (entryIndex == deletedEntryIndex()) { ++deletedIndexCount; continue; } - ASSERT(entryIndex > deletedSentinelIndex); - ASSERT(entryIndex - 1 <= m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount); + ASSERT(entryIndex < deletedEntryIndex()); + ASSERT(entryIndex - 1 <= usedCount()); ++indexCount; - for (unsigned b = a + 1; b != m_propertyTable->size; ++b) - ASSERT(m_propertyTable->entryIndices[b] != entryIndex); + for (unsigned b = a + 1; b != m_indexSize; ++b) + ASSERT(m_index[b] != entryIndex); } - ASSERT(indexCount == m_propertyTable->keyCount); - ASSERT(deletedIndexCount == m_propertyTable->deletedSentinelCount); + ASSERT(indexCount == m_keyCount); + ASSERT(deletedIndexCount == m_deletedCount); - ASSERT(m_propertyTable->entries()[0].key == 0); + ASSERT(!table()[deletedEntryIndex() - 1].key); unsigned nonEmptyEntryCount = 0; - for (unsigned c = 1; c <= m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; ++c) { - ASSERT(m_hasNonEnumerableProperties || !(m_propertyTable->entries()[c].attributes & DontEnum)); - StringImpl* rep = m_propertyTable->entries()[c].key; - ASSERT(m_propertyTable->entries()[c].offset >= m_anonymousSlotCount); - if (!rep) + for (unsigned c = 0; c < usedCount(); ++c) { + StringImpl* rep = table()[c].key; + if (rep == PROPERTY_MAP_DELETED_ENTRY_KEY) continue; ++nonEmptyEntryCount; unsigned i = rep->existingHash(); unsigned k = 0; unsigned entryIndex; while (1) { - entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; - ASSERT(entryIndex != emptyEntryIndex); - if (rep == m_propertyTable->entries()[entryIndex - 1].key) + entryIndex = m_index[i & m_indexMask]; + ASSERT(entryIndex != PropertyTable::EmptyEntryIndex); + if (rep == table()[entryIndex - 1].key) break; if (k == 0) k = 1 | doubleHash(rep->existingHash()); @@ -1262,7 +881,23 @@ void Structure::checkConsistency() ASSERT(entryIndex == c + 1); } - ASSERT(nonEmptyEntryCount == m_propertyTable->keyCount); + ASSERT(nonEmptyEntryCount == m_keyCount); +} + +void Structure::checkConsistency() +{ + if (!m_propertyTable) + return; + + if (!m_hasNonEnumerableProperties) { + PropertyTable::iterator end = m_propertyTable->end(); + for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) { + ASSERT(!(iter->attributes & DontEnum)); + ASSERT(iter->offset >= m_anonymousSlotCount); + } + } + + m_propertyTable->checkConsistency(); } #endif // DO_PROPERTYMAP_CONSTENCY_CHECK diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h index 77724ac..bf27334 100644 --- a/Source/JavaScriptCore/runtime/Structure.h +++ b/Source/JavaScriptCore/runtime/Structure.h @@ -40,11 +40,6 @@ #include #include -#ifndef NDEBUG -#define DUMP_PROPERTYMAP_STATS 0 -#else -#define DUMP_PROPERTYMAP_STATS 0 -#endif namespace JSC { @@ -52,6 +47,8 @@ namespace JSC { class PropertyNameArray; class PropertyNameArrayData; + struct ClassInfo; + enum EnumerationMode { ExcludeDontEnumProperties, IncludeDontEnumProperties @@ -61,9 +58,9 @@ namespace JSC { public: friend class JIT; friend class StructureTransitionTable; - static PassRefPtr create(JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount) + static PassRefPtr create(JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount, const ClassInfo* classInfo) { - return adoptRef(new Structure(prototype, typeInfo, anonymousSlotCount)); + return adoptRef(new Structure(prototype, typeInfo, anonymousSlotCount, classInfo)); } static void startIgnoringLeaks(); @@ -79,6 +76,13 @@ namespace JSC { static PassRefPtr getterSetterTransition(Structure*); static PassRefPtr toCacheableDictionaryTransition(Structure*); static PassRefPtr toUncacheableDictionaryTransition(Structure*); + static PassRefPtr sealTransition(Structure*); + static PassRefPtr freezeTransition(Structure*); + static PassRefPtr preventExtensionsTransition(Structure*); + + bool isSealed(); + bool isFrozen(); + bool isExtensible() const { return !m_preventExtensions; } PassRefPtr flattenDictionaryStructure(JSGlobalData&, JSObject*); @@ -103,25 +107,16 @@ namespace JSC { void growPropertyStorageCapacity(); unsigned propertyStorageCapacity() const { return m_propertyStorageCapacity; } - unsigned propertyStorageSize() const { return m_anonymousSlotCount + (m_propertyTable ? m_propertyTable->keyCount + (m_propertyTable->deletedOffsets ? m_propertyTable->deletedOffsets->size() : 0) : static_cast(m_offset + 1)); } + unsigned propertyStorageSize() const { return m_anonymousSlotCount + (m_propertyTable ? m_propertyTable->propertyStorageSize() : static_cast(m_offset + 1)); } bool isUsingInlineStorage() const; size_t get(const Identifier& propertyName); - size_t get(const StringImpl* rep, unsigned& attributes, JSCell*& specificValue); + size_t get(StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue); size_t get(const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue) { ASSERT(!propertyName.isNull()); return get(propertyName.impl(), attributes, specificValue); } - bool transitionedFor(const JSCell* specificValue) - { - return m_specificValueInPrevious == specificValue; - } - bool hasTransition(StringImpl*, unsigned attributes); - bool hasTransition(const Identifier& propertyName, unsigned attributes) - { - return hasTransition(propertyName.impl(), attributes); - } bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; } void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; } @@ -131,19 +126,28 @@ namespace JSC { bool hasAnonymousSlots() const { return !!m_anonymousSlotCount; } unsigned anonymousSlotCount() const { return m_anonymousSlotCount; } - bool isEmpty() const { return m_propertyTable ? !m_propertyTable->keyCount : m_offset == noOffset; } + bool isEmpty() const { return m_propertyTable ? m_propertyTable->isEmpty() : m_offset == noOffset; } void despecifyDictionaryFunction(const Identifier& propertyName); void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; } - void setEnumerationCache(JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h. - void clearEnumerationCache(JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h. + void setEnumerationCache(JSGlobalData&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h. + void clearEnumerationCache(); // Defined in JSPropertyNameIterator.h. JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h. void getPropertyNames(PropertyNameArray&, EnumerationMode mode); - + + const ClassInfo* classInfo() const { return m_classInfo; } + + static void initializeThreading(); + private: + Structure(JSValue prototype, const TypeInfo&, unsigned anonymousSlotCount, const ClassInfo*); + Structure(const Structure*); - Structure(JSValue prototype, const TypeInfo&, unsigned anonymousSlotCount); + static PassRefPtr create(const Structure* structure) + { + return adoptRef(new Structure(structure)); + } typedef enum { NoneDictionaryKind = 0, @@ -155,24 +159,18 @@ namespace JSC { size_t put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue); size_t remove(const Identifier& propertyName); - void expandPropertyMapHashTable(); - void rehashPropertyMapHashTable(); - void rehashPropertyMapHashTable(unsigned newTableSize); - void createPropertyMapHashTable(); - void createPropertyMapHashTable(unsigned newTableSize); - void insertIntoPropertyMapHashTable(const PropertyMapEntry&); + void createPropertyMap(unsigned keyCount = 0); void checkConsistency(); bool despecifyFunction(const Identifier&); void despecifyAllFunctions(); - PropertyMapHashTable* copyPropertyTable(); + PropertyTable* copyPropertyTable(); void materializePropertyMap(); void materializePropertyMapIfNecessary() { - if (m_propertyTable || !m_previous) - return; - materializePropertyMap(); + if (!m_propertyTable && m_previous) + materializePropertyMap(); } signed char transitionCount() const @@ -181,24 +179,8 @@ namespace JSC { return m_offset == noOffset ? 0 : m_offset + 1; } - typedef std::pair Transition; - typedef HashMap TransitionTable; - - inline bool transitionTableContains(const StructureTransitionTableHash::Key& key, JSCell* specificValue); - inline void transitionTableRemove(const StructureTransitionTableHash::Key& key, JSCell* specificValue); - inline void transitionTableAdd(const StructureTransitionTableHash::Key& key, Structure* structure, JSCell* specificValue); - inline bool transitionTableHasTransition(const StructureTransitionTableHash::Key& key) const; - inline Structure* transitionTableGet(const StructureTransitionTableHash::Key& key, JSCell* specificValue) const; - - TransitionTable* transitionTable() const { ASSERT(!m_isUsingSingleSlot); return m_transitions.m_table; } - inline void setTransitionTable(TransitionTable* table); - Structure* singleTransition() const { ASSERT(m_isUsingSingleSlot); return m_transitions.m_singleTransition; } - void setSingleTransition(Structure* structure) { ASSERT(m_isUsingSingleSlot); m_transitions.m_singleTransition = structure; } - bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const; - static const unsigned emptyEntryIndex = 0; - static const signed char s_maxTransitionLength = 64; static const signed char noOffset = -1; @@ -214,15 +196,13 @@ namespace JSC { RefPtr m_nameInPrevious; JSCell* m_specificValueInPrevious; - // 'm_isUsingSingleSlot' indicates whether we are using the single transition optimisation. - union { - TransitionTable* m_table; - Structure* m_singleTransition; - } m_transitions; + const ClassInfo* m_classInfo; + + StructureTransitionTable m_transitionTable; WeakGCPtr m_enumerationCache; - PropertyMapHashTable* m_propertyTable; + OwnPtr m_propertyTable; uint32_t m_propertyStorageCapacity; @@ -243,53 +223,19 @@ namespace JSC { #endif unsigned m_specificFunctionThrashCount : 2; unsigned m_anonymousSlotCount : 5; - unsigned m_isUsingSingleSlot : 1; + unsigned m_preventExtensions : 1; // 4 free bits }; inline size_t Structure::get(const Identifier& propertyName) { - ASSERT(!propertyName.isNull()); - materializePropertyMapIfNecessary(); if (!m_propertyTable) - return WTF::notFound; - - StringImpl* rep = propertyName.impl(); - - unsigned i = rep->existingHash(); - -#if DUMP_PROPERTYMAP_STATS - ++numProbes; -#endif - - unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; - if (entryIndex == emptyEntryIndex) - return WTF::notFound; - - if (rep == m_propertyTable->entries()[entryIndex - 1].key) - return m_propertyTable->entries()[entryIndex - 1].offset; + return notFound; -#if DUMP_PROPERTYMAP_STATS - ++numCollisions; -#endif - - unsigned k = 1 | WTF::doubleHash(rep->existingHash()); - - while (1) { - i += k; - -#if DUMP_PROPERTYMAP_STATS - ++numRehashes; -#endif - - entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; - if (entryIndex == emptyEntryIndex) - return WTF::notFound; - - if (rep == m_propertyTable->entries()[entryIndex - 1].key) - return m_propertyTable->entries()[entryIndex - 1].offset; - } + PropertyMapEntry* entry = m_propertyTable->find(propertyName.impl()).first; + ASSERT(!entry || entry->offset >= m_anonymousSlotCount); + return entry ? entry->offset : notFound; } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/StructureTransitionTable.h b/Source/JavaScriptCore/runtime/StructureTransitionTable.h index 7e9d7ff..da78e1b 100644 --- a/Source/JavaScriptCore/runtime/StructureTransitionTable.h +++ b/Source/JavaScriptCore/runtime/StructureTransitionTable.h @@ -35,9 +35,12 @@ namespace JSC { - class Structure; +class Structure; - struct StructureTransitionTableHash { +class StructureTransitionTable { + static const intptr_t UsingSingleSlotFlag = 1; + + struct Hash { typedef std::pair, unsigned> Key; static unsigned hash(const Key& p) { @@ -52,7 +55,7 @@ namespace JSC { static const bool safeToCompareToEmptyOrDeleted = true; }; - struct StructureTransitionTableHashTraits { + struct HashTraits { typedef WTF::HashTraits > FirstTraits; typedef WTF::GenericHashTraits SecondTraits; typedef std::pair TraitType; @@ -66,6 +69,62 @@ namespace JSC { static bool isDeletedValue(const TraitType& value) { return FirstTraits::isDeletedValue(value.first); } }; + typedef HashMap TransitionMap; + +public: + StructureTransitionTable() + : m_data(UsingSingleSlotFlag) + { + } + + ~StructureTransitionTable() + { + if (!isUsingSingleSlot()) + delete map(); + } + + inline void add(Structure*); + inline void remove(Structure*); + inline bool contains(StringImpl* rep, unsigned attributes) const; + inline Structure* get(StringImpl* rep, unsigned attributes) const; + +private: + bool isUsingSingleSlot() const + { + return m_data & UsingSingleSlotFlag; + } + + TransitionMap* map() const + { + ASSERT(!isUsingSingleSlot()); + return reinterpret_cast(m_data); + } + + void setMap(TransitionMap* map) + { + ASSERT(isUsingSingleSlot()); + + // This implicitly clears the flag that indicates we're using a single transition + m_data = reinterpret_cast(map); + + ASSERT(!isUsingSingleSlot()); + } + + Structure* singleTransition() const + { + ASSERT(isUsingSingleSlot()); + return reinterpret_cast(m_data & ~UsingSingleSlotFlag); + } + + void setSingleTransition(Structure* structure) + { + ASSERT(isUsingSingleSlot()); + m_data = reinterpret_cast(structure) | UsingSingleSlotFlag; + } + + intptr_t m_data; +}; + } // namespace JSC #endif // StructureTransitionTable_h diff --git a/Source/JavaScriptCore/runtime/WeakGCMap.h b/Source/JavaScriptCore/runtime/WeakGCMap.h index 7bf4503..a40e684 100644 --- a/Source/JavaScriptCore/runtime/WeakGCMap.h +++ b/Source/JavaScriptCore/runtime/WeakGCMap.h @@ -26,110 +26,127 @@ #ifndef WeakGCMap_h #define WeakGCMap_h -#include "Heap.h" +#include "Handle.h" +#include "JSGlobalData.h" #include namespace JSC { -class JSCell; - -// A HashMap whose get() function returns emptyValue() for cells awaiting destruction. -template -class WeakGCMap { +// A HashMap for GC'd values that removes entries when the associated value +// dies. +template class WeakGCMap : private Finalizer { WTF_MAKE_FAST_ALLOCATED; - /* - Invariants: - * A value enters the WeakGCMap marked. (Guaranteed by set().) - * A value that becomes unmarked leaves the WeakGCMap before being recycled. (Guaranteed by the value's destructor removing it from the WeakGCMap.) - * A value that becomes unmarked leaves the WeakGCMap before becoming marked again. (Guaranteed by all destructors running before the mark phase begins.) - * During the mark phase, all values in the WeakGCMap are valid. (Guaranteed by all destructors running before the mark phase begins.) - */ + WTF_MAKE_NONCOPYABLE(WeakGCMap); + + typedef HashMap MapType; + typedef typename HandleTypes::ExternalType ExternalType; + typedef typename MapType::iterator map_iterator; public: - typedef typename HashMap >::iterator iterator; - typedef typename HashMap >::const_iterator const_iterator; - + + struct iterator { + iterator(map_iterator iter) + : m_iterator(iter) + { + } + + std::pair get() const { return std::make_pair(m_iterator->first, HandleTypes::getFromSlot(m_iterator->second)); } + std::pair getSlot() const { return *m_iterator; } + + iterator& operator++() { ++m_iterator; return *this; } + + // postfix ++ intentionally omitted + + // Comparison. + bool operator==(const iterator& other) const { return m_iterator == other.m_iterator; } + bool operator!=(const iterator& other) const { return m_iterator != other.m_iterator; } + + private: + map_iterator m_iterator; + }; + + WeakGCMap() + { + } + bool isEmpty() { return m_map.isEmpty(); } - void clear() { m_map.clear(); } + void clear() + { + map_iterator end = m_map.end(); + for (map_iterator ptr = m_map.begin(); ptr != end; ++ptr) + HandleHeap::heapFor(ptr->second)->deallocate(ptr->second); + m_map.clear(); + } - MappedType* get(const KeyType&) const; - pair set(const KeyType&, MappedType*); - MappedType* take(const KeyType&); + ExternalType get(const KeyType& key) const + { + return HandleTypes::getFromSlot(m_map.get(key)); + } - // These unchecked functions provide access to a value even if the value's - // mark bit is not set. This is used, among other things, to retrieve values - // during the GC mark phase, which begins by clearing all mark bits. - - size_t uncheckedSize() { return m_map.size(); } + HandleSlot getSlot(const KeyType& key) const + { + return m_map.get(key); + } - MappedType* uncheckedGet(const KeyType& key) const { return m_map.get(key).get(); } - DeprecatedPtr* uncheckedGetSlot(const KeyType& key) + void set(JSGlobalData& globalData, const KeyType& key, ExternalType value) { - iterator iter = m_map.find(key); - if (iter == m_map.end()) - return 0; - return &iter->second; + pair iter = m_map.add(key, 0); + HandleSlot slot = iter.first->second; + if (iter.second) { + slot = globalData.allocateGlobalHandle(); + iter.first->second = slot; + HandleHeap::heapFor(slot)->makeWeak(slot, this, key); + } + HandleHeap::heapFor(slot)->writeBarrier(slot, value); + *slot = value; } - bool uncheckedRemove(const KeyType&, MappedType*); - iterator uncheckedBegin() { return m_map.begin(); } - iterator uncheckedEnd() { return m_map.end(); } + ExternalType take(const KeyType& key) + { + HandleSlot slot = m_map.take(key); + if (!slot) + return HashTraits::emptyValue(); + ExternalType result = HandleTypes::getFromSlot(slot); + HandleHeap::heapFor(slot)->deallocate(slot); + return result; + } - const_iterator uncheckedBegin() const { return m_map.begin(); } - const_iterator uncheckedEnd() const { return m_map.end(); } + size_t size() { return m_map.size(); } - bool isValid(iterator it) const { return Heap::isMarked(it->second.get()); } - bool isValid(const_iterator it) const { return Heap::isMarked(it->second.get()); } + bool deprecatedRemove(const KeyType& key, ExternalType value) + { + // This only exists in order to allow some semblance of correctness to + // the JSWeakObjectMapClear API + typename MapType::iterator iter = m_map.find(key); + if (iter == m_map.end()) + return false; + HandleSlot slot = iter->second; + ExternalType inmap = HandleTypes::getFromSlot(slot); + if (inmap && inmap != value) + return false; + m_map.remove(iter); + HandleHeap::heapFor(slot)->deallocate(slot); + return true; + } + iterator begin() { return iterator(m_map.begin()); } + iterator end() { return iterator(m_map.end()); } + + ~WeakGCMap() + { + clear(); + } + private: - HashMap > m_map; -}; - -template -inline MappedType* WeakGCMap::get(const KeyType& key) const -{ - MappedType* result = m_map.get(key).get(); - if (result == HashTraits::emptyValue()) - return result; - if (!Heap::isMarked(result)) - return HashTraits::emptyValue(); - return result; -} - -template -MappedType* WeakGCMap::take(const KeyType& key) -{ - MappedType* result = m_map.take(key).get(); - if (result == HashTraits::emptyValue()) - return result; - if (!Heap::isMarked(result)) - return HashTraits::emptyValue(); - return result; -} - -template -pair::iterator, bool> WeakGCMap::set(const KeyType& key, MappedType* value) -{ - Heap::setMarked(value); // If value is newly allocated, it's not marked, so mark it now. - pair result = m_map.add(key, value); - if (!result.second) { // pre-existing entry - result.second = !Heap::isMarked(result.first->second.get()); - result.first->second = value; + virtual void finalize(Handle, void* key) + { + HandleSlot slot = m_map.take(static_cast(key)); + ASSERT(slot); + HandleHeap::heapFor(slot)->deallocate(slot); } - return result; -} - -template -bool WeakGCMap::uncheckedRemove(const KeyType& key, MappedType* value) -{ - iterator it = m_map.find(key); - if (it == m_map.end()) - return false; - if (it->second.get() != value) - return false; - m_map.remove(it); - return true; -} + + MapType m_map; +}; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/WeakGCPtr.h b/Source/JavaScriptCore/runtime/WeakGCPtr.h index 4946ee7..3f87b83 100644 --- a/Source/JavaScriptCore/runtime/WeakGCPtr.h +++ b/Source/JavaScriptCore/runtime/WeakGCPtr.h @@ -26,128 +26,79 @@ #ifndef WeakGCPtr_h #define WeakGCPtr_h +#include "Global.h" #include "Heap.h" -#include "GCHandle.h" namespace JSC { +// A smart pointer whose get() function returns 0 for cells that have died -// A smart pointer whose get() function returns 0 for cells awaiting destruction. -template class WeakGCPtr { +template class WeakGCPtr : public HandleConverter, T> { WTF_MAKE_NONCOPYABLE(WeakGCPtr); + public: + typedef typename HandleTypes::ExternalType ExternalType; + WeakGCPtr() - : m_ptr(0) + : m_slot(0) { } - - WeakGCPtr(T* ptr) { assign(ptr); } - - ~WeakGCPtr() + + WeakGCPtr(JSGlobalData& globalData, Finalizer* finalizer = 0, void* context = 0) + : m_slot(globalData.allocateGlobalHandle()) { - if (m_ptr) - m_ptr->pool()->free(m_ptr); + HandleHeap::heapFor(m_slot)->makeWeak(m_slot, finalizer, context); } - - T* get() const + + WeakGCPtr(JSGlobalData& globalData, ExternalType value, Finalizer* finalizer = 0, void* context = 0) + : m_slot(globalData.allocateGlobalHandle()) { - if (m_ptr && m_ptr->isValidPtr()) - return static_cast(m_ptr->get()); - return 0; + HandleHeap::heapFor(m_slot)->makeWeak(m_slot, finalizer, context); + internalSet(value); } + + ExternalType get() const { return HandleTypes::getFromSlot(m_slot); } - bool clear(JSCell* p) + void clear() { - if (!m_ptr || m_ptr->get() != p) - return false; - - m_ptr->pool()->free(m_ptr); - m_ptr = 0; - return true; + if (m_slot) + internalSet(ExternalType()); } - - T& operator*() const { return *get(); } - T* operator->() const { return get(); } - bool operator!() const { return !get(); } + bool operator!() const { return !m_slot || !*m_slot; } // This conversion operator allows implicit conversion to bool but not to other integer types. -#if COMPILER(WINSCW) - operator bool() const { return m_ptr; } -#else - typedef WeakGCHandle* WeakGCPtr::*UnspecifiedBoolType; - operator UnspecifiedBoolType() const { return get() ? &WeakGCPtr::m_ptr : 0; } -#endif + typedef ExternalType (WeakGCPtr::*UnspecifiedBoolType); + operator UnspecifiedBoolType*() const { return !*this ? 0 : reinterpret_cast(1); } - WeakGCPtr& operator=(T*); + ~WeakGCPtr() + { + if (!m_slot) + return; + HandleHeap::heapFor(m_slot)->deallocate(m_slot); + } -#if !ASSERT_DISABLED - bool hasDeadObject() const { return !!m_ptr; } -#endif + void set(JSGlobalData& globalData, ExternalType value, Finalizer* finalizer) + { + if (!this->m_slot) { + this->m_slot = globalData.allocateGlobalHandle(); + HandleHeap::heapFor(this->m_slot)->makeWeak(this->m_slot, finalizer, 0); + } else + ASSERT(HandleHeap::heapFor(this->m_slot)->getFinalizer(this->m_slot) == finalizer); + this->internalSet(value); + } private: - void assign(JSCell* ptr) + void internalSet(ExternalType value) { - ASSERT(ptr); - if (m_ptr) - m_ptr->set(ptr); - else - m_ptr = Heap::heap(ptr)->addWeakGCHandle(ptr); + ASSERT(m_slot); + JSValue newValue(HandleTypes::toJSValue(value)); + HandleHeap::heapFor(m_slot)->writeBarrier(m_slot, newValue); + *m_slot = newValue; } - WeakGCHandle* m_ptr; + HandleSlot m_slot; }; -template inline WeakGCPtr& WeakGCPtr::operator=(T* optr) -{ - assign(optr); - return *this; -} - -template inline bool operator==(const WeakGCPtr& a, const WeakGCPtr& b) -{ - return a.get() == b.get(); -} - -template inline bool operator==(const WeakGCPtr& a, U* b) -{ - return a.get() == b; -} - -template inline bool operator==(T* a, const WeakGCPtr& b) -{ - return a == b.get(); -} - -template inline bool operator!=(const WeakGCPtr& a, const WeakGCPtr& b) -{ - return a.get() != b.get(); -} - -template inline bool operator!=(const WeakGCPtr& a, U* b) -{ - return a.get() != b; -} - -template inline bool operator!=(T* a, const WeakGCPtr& b) -{ - return a != b.get(); -} - -template inline WeakGCPtr static_pointer_cast(const WeakGCPtr& p) -{ - return WeakGCPtr(static_cast(p.get())); -} - -template inline WeakGCPtr const_pointer_cast(const WeakGCPtr& p) -{ - return WeakGCPtr(const_cast(p.get())); -} - -template inline T* get(const WeakGCPtr& p) -{ - return p.get(); -} - } // namespace JSC #endif // WeakGCPtr_h diff --git a/Source/JavaScriptCore/runtime/WriteBarrier.h b/Source/JavaScriptCore/runtime/WriteBarrier.h index 64150ed..44840ad 100644 --- a/Source/JavaScriptCore/runtime/WriteBarrier.h +++ b/Source/JavaScriptCore/runtime/WriteBarrier.h @@ -33,6 +33,7 @@ class JSCell; class JSGlobalData; typedef enum { } Unknown; +typedef JSValue* HandleSlot; template class DeprecatedPtr { public: -- cgit v1.1