diff options
Diffstat (limited to 'Source/JavaScriptCore/runtime')
173 files changed, 4491 insertions, 7351 deletions
diff --git a/Source/JavaScriptCore/runtime/ArgList.cpp b/Source/JavaScriptCore/runtime/ArgList.cpp index a862ea0..f46d108 100644 --- a/Source/JavaScriptCore/runtime/ArgList.cpp +++ b/Source/JavaScriptCore/runtime/ArgList.cpp @@ -23,6 +23,8 @@ #include "JSValue.h" #include "JSCell.h" +#include "JSObject.h" +#include "ScopeChain.h" using std::min; @@ -37,12 +39,12 @@ void ArgList::getSlice(int startIndex, ArgList& result) const result = ArgList(m_args + startIndex, m_argCount - startIndex); } -void MarkedArgumentBuffer::markLists(MarkStack& markStack, ListSet& markSet) +void MarkedArgumentBuffer::markLists(HeapRootMarker& heapRootMarker, ListSet& markSet) { ListSet::iterator end = markSet.end(); for (ListSet::iterator it = markSet.begin(); it != end; ++it) { MarkedArgumentBuffer* list = *it; - markStack.deprecatedAppendValues(list->m_buffer, list->m_size); + heapRootMarker.mark(reinterpret_cast<JSValue*>(list->m_buffer), list->m_size); } } @@ -54,8 +56,8 @@ void MarkedArgumentBuffer::slowAppend(JSValue v) // our Vector's inline capacity, though, our values move to the // heap, where they do need explicit marking. if (!m_markSet) { - // We can only register for explicit marking once we know which heap - // is the current one, i.e., when a non-immediate value is appended. + // FIXME: Even if v is not a JSCell*, if previous values in the buffer + // are, then they won't be marked! if (Heap* heap = Heap::heap(v)) { ListSet& markSet = heap->markListSet(); markSet.add(this); diff --git a/Source/JavaScriptCore/runtime/ArgList.h b/Source/JavaScriptCore/runtime/ArgList.h index 57e3c20..a794a04 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<Unknown>* buffer, size_t size) { ASSERT(!m_markSet); ASSERT(isEmpty()); - m_buffer = buffer; + m_buffer = reinterpret_cast<Register*>(buffer); m_size = size; #ifndef NDEBUG m_isReadOnly = true; @@ -141,7 +141,7 @@ namespace JSC { const_iterator begin() const { return m_buffer; } const_iterator end() const { return m_buffer + m_size; } - static void markLists(MarkStack&, ListSet&); + static void markLists(HeapRootMarker&, ListSet&); private: void slowAppend(JSValue); 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<JSCell*>(d->activation.get()) : static_cast<JSCell*>(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<JSCell*>(d->activation.get()) : static_cast<JSCell*>(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..b5aa46b 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<Register> registerArray; + WriteBarrier<Unknown>* registers; + OwnArrayPtr<WriteBarrier<Unknown> > registerArray; - Register* extraArguments; + WriteBarrier<Unknown>* extraArguments; OwnArrayPtr<bool> deletedArguments; - Register extraArgumentsFixedBuffer[4]; + WriteBarrier<Unknown> extraArgumentsFixedBuffer[4]; WriteBarrier<JSFunction> 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<Structure> createStructure(JSValue prototype) + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, 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<ArgumentsData> 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<Arguments*>(asObject(value)); } @@ -145,9 +143,11 @@ namespace JSC { } inline Arguments::Arguments(CallFrame* callFrame) - : JSObject(callFrame->lexicalGlobalObject()->argumentsStructure()) + : JSNonFinalObject(callFrame->globalData(), 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<WriteBarrier<Unknown>*>(callFrame->registers()); - Register* extraArguments; + WriteBarrier<Unknown>* 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<Unknown>)) + extraArguments = new WriteBarrier<Unknown>[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->globalData(), 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<Unknown>* extraArguments; if (numArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(Register)) - extraArguments = new Register[numArguments]; + extraArguments = new WriteBarrier<Unknown>[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,29 +227,28 @@ namespace JSC { int registerOffset = d->numParameters + RegisterFile::CallFrameHeaderSize; size_t registerArraySize = d->numParameters; - OwnArrayPtr<Register> registerArray = adoptArrayPtr(new Register[registerArraySize]); - memcpy(registerArray.get(), d->registers - registerOffset, registerArraySize * sizeof(Register)); + OwnArrayPtr<WriteBarrier<Unknown> > registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[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); + ASSERT(!m_registerArray); - size_t numParametersMinusThis = d()->functionExecutable->parameterCount(); - size_t numVars = d()->functionExecutable->capturedVariableCount(); - size_t numLocals = numVars + numParametersMinusThis; + size_t numLocals = m_numCapturedVars + m_numParametersMinusThis; if (!numLocals) return; - int registerOffset = numParametersMinusThis + RegisterFile::CallFrameHeaderSize; + int registerOffset = m_numParametersMinusThis + RegisterFile::CallFrameHeaderSize; size_t registerArraySize = numLocals + RegisterFile::CallFrameHeaderSize; - OwnArrayPtr<Register> registerArray = copyRegisterArray(d()->registers - registerOffset, registerArraySize); - Register* registers = registerArray.get() + registerOffset; + OwnArrayPtr<WriteBarrier<Unknown> > registerArray = copyRegisterArray(globalData, m_registers - registerOffset, registerArraySize, m_numParametersMinusThis + 1); + WriteBarrier<Unknown>* registers = registerArray.get() + registerOffset; setRegisters(registers, registerArray.release()); } diff --git a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp index 5d0adbd..050e989 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> structure, ArrayPrototype* arrayPrototype, Structure* prototypeFunctionStructure) +ArrayConstructor::ArrayConstructor(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, ArrayPrototype* arrayPrototype, Structure* functionStructure) : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, arrayPrototype->classInfo()->className)) { // ECMA 15.4.3.1 Array.prototype @@ -48,21 +47,23 @@ 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) { + JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject(); + // a single numeric argument denotes the array size (!) if (args.size() == 1 && args.at(0).isNumber()) { uint32_t n = args.at(0).toUInt32(exec); if (n != args.at(0).toNumber(exec)) return throwError(exec, createRangeError(exec, "Array size is not a small enough positive integer.")); - return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), n, CreateInitialized); + return new (exec) JSArray(exec->globalData(), globalObject->arrayStructure(), n, CreateInitialized); } // otherwise the array is constructed with the arguments in it - return new (exec) JSArray(exec->globalData(), exec->lexicalGlobalObject()->arrayStructure(), args); + return new (exec) JSArray(exec->globalData(), globalObject->arrayStructure(), args); } static EncodedJSValue JSC_HOST_CALL constructWithArrayConstructor(ExecState* exec) @@ -94,7 +95,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/ArrayConstructor.h b/Source/JavaScriptCore/runtime/ArrayConstructor.h index 5e1408f..97b26c5 100644 --- a/Source/JavaScriptCore/runtime/ArrayConstructor.h +++ b/Source/JavaScriptCore/runtime/ArrayConstructor.h @@ -29,7 +29,7 @@ namespace JSC { class ArrayConstructor : public InternalFunction { public: - ArrayConstructor(ExecState*, JSGlobalObject*, NonNullPassRefPtr<Structure>, ArrayPrototype*, Structure*); + ArrayConstructor(ExecState*, JSGlobalObject*, Structure*, ArrayPrototype*, Structure*); virtual ConstructType getConstructData(ConstructData&); virtual CallType getCallData(CallData&); diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp index 70c0d06..29caece 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 @@ -114,9 +114,10 @@ const ClassInfo ArrayPrototype::info = {"Array", &JSArray::info, 0, ExecState::a */ // ECMA 15.4.4 -ArrayPrototype::ArrayPrototype(JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure) - : JSArray(structure) +ArrayPrototype::ArrayPrototype(JSGlobalObject* globalObject, Structure* structure) + : JSArray(globalObject->globalData(), structure) { + ASSERT(inherits(&s_info)); putAnonymousValue(globalObject->globalData(), 0, globalObject); } @@ -164,16 +165,20 @@ static unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument 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); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + StringRecursionChecker checker(exec, thisObj); if (EncodedJSValue earlyReturnValue = checker.earlyReturnValue()) return earlyReturnValue; - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); unsigned totalSize = length ? length - 1 : 0; #if OS(SYMBIAN) // Symbian has very limited stack size available. @@ -224,16 +229,20 @@ 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); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + StringRecursionChecker checker(exec, thisObj); if (EncodedJSValue earlyReturnValue = checker.earlyReturnValue()) return earlyReturnValue; JSStringBuilder strBuffer; - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); for (unsigned k = 0; k < length; k++) { if (k >= 1) strBuffer.append(','); @@ -259,6 +268,9 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec) { JSObject* thisObj = exec->hostThisValue().toThisObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); StringRecursionChecker checker(exec, thisObj); if (EncodedJSValue earlyReturnValue = checker.earlyReturnValue()) @@ -270,7 +282,6 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec) if (!exec->argument(0).isUndefined()) separator = exec->argument(0).toString(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); unsigned k = 0; if (isJSArray(&exec->globalData(), thisObj)) { JSArray* array = asArray(thisObj); @@ -330,7 +341,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) { @@ -354,12 +365,16 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); + if (isJSArray(&exec->globalData(), thisValue)) return JSValue::encode(asArray(thisValue)->pop()); JSObject* thisObj = thisValue.toThisObject(exec); - JSValue result; unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + JSValue result; if (length == 0) { putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length)); result = jsUndefined(); @@ -374,6 +389,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); + if (isJSArray(&exec->globalData(), thisValue) && exec->argumentCount() == 1) { JSArray* array = asArray(thisValue); array->push(exec, exec->argument(0)); @@ -382,6 +398,9 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec) JSObject* thisObj = thisValue.toThisObject(exec); unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + for (unsigned n = 0; n < exec->argumentCount(); n++) thisObj->put(exec, length + n, exec->argument(n)); length += exec->argumentCount(); @@ -393,8 +412,10 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState* exec) { JSObject* thisObj = exec->hostThisValue().toThisObject(exec); unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - unsigned middle = length / 2; + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + unsigned middle = length / 2; for (unsigned k = 0; k < middle; k++) { unsigned lk1 = length - k - 1; JSValue obj2 = getProperty(exec, thisObj, lk1); @@ -419,6 +440,9 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState* exec) JSValue result; unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + if (length == 0) { putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length)); result = jsUndefined(); @@ -450,6 +474,9 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec) JSValue result = resObj; unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length); unsigned end = argumentClampedIndexFromStartOrEnd(exec, 1, length, length); @@ -465,12 +492,15 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec) { JSObject* thisObj = exec->hostThisValue().toThisObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (!length || exec->hadException()) + return JSValue::encode(thisObj); JSValue function = exec->argument(0); 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) @@ -480,19 +510,18 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec) return JSValue::encode(thisObj); } - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - - if (!length) - return JSValue::encode(thisObj); - // "Min" sort. Not the fastest, but definitely less code than heapsort // or quicksort, and much less swapping than bubblesort/insertionsort. for (unsigned i = 0; i < length - 1; ++i) { JSValue iObj = thisObj->get(exec, i); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); unsigned themin = i; JSValue minObj = iObj; for (unsigned j = i + 1; j < length; ++j) { JSValue jObj = thisObj->get(exec, j); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); double compareResult; if (jObj.isUndefined()) compareResult = 1; // don't check minObj because there's no need to differentiate == (0) from > (1) @@ -522,14 +551,16 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec) { - JSObject* thisObj = exec->hostThisValue().toThisObject(exec); - // 15.4.4.12 + JSObject* thisObj = exec->hostThisValue().toThisObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + if (!exec->argumentCount()) return JSValue::encode(constructEmptyArray(exec)); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length); unsigned deleteCount = length - begin; @@ -543,7 +574,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec) deleteCount = static_cast<unsigned>(deleteDouble); } - JSArray* resObj = new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), deleteCount, CreateCompact); + JSArray* resObj = new (exec) JSArray(exec->globalData(), exec->lexicalGlobalObject()->arrayStructure(), deleteCount, CreateCompact); JSValue result = resObj; JSGlobalData& globalData = exec->globalData(); for (unsigned k = 0; k < deleteCount; k++) @@ -588,10 +619,13 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState* exec) { - JSObject* thisObj = exec->hostThisValue().toThisObject(exec); - // 15.4.4.13 + + JSObject* thisObj = exec->hostThisValue().toThisObject(exec); unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + unsigned nrArgs = exec->argumentCount(); if ((nrArgs) && (length)) { if (isJSArray(&exec->globalData(), thisObj)) @@ -615,6 +649,9 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec) { JSObject* thisObj = exec->hostThisValue().toThisObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); JSValue function = exec->argument(0); CallData callData; @@ -626,7 +663,6 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec) JSArray* resultArray = constructEmptyArray(exec); unsigned filterIndex = 0; - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); unsigned k = 0; if (callType == CallTypeJS && isJSArray(&exec->globalData(), thisObj)) { JSFunction* f = asFunction(function); @@ -650,20 +686,19 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec) } for (; k < length && !exec->hadException(); ++k) { PropertySlot slot(thisObj); - if (!thisObj->getPropertySlot(exec, k, slot)) continue; - JSValue v = slot.getValue(exec, k); - MarkedArgumentBuffer eachArguments; + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + MarkedArgumentBuffer eachArguments; eachArguments.append(v); eachArguments.append(jsNumber(k)); eachArguments.append(thisObj); JSValue result = call(exec, function, callType, callData, applyThis, eachArguments); - if (result.toBoolean(exec)) resultArray->put(exec, filterIndex++, v); } @@ -673,6 +708,9 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec) { JSObject* thisObj = exec->hostThisValue().toThisObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); JSValue function = exec->argument(0); CallData callData; @@ -682,8 +720,6 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec) JSObject* applyThis = exec->argument(1).isUndefinedOrNull() ? exec->globalThisValue() : exec->argument(1).toObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - JSArray* resultArray = constructEmptyArray(exec, length); unsigned k = 0; if (callType == CallTypeJS && isJSArray(&exec->globalData(), thisObj)) { @@ -706,15 +742,19 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec) PropertySlot slot(thisObj); if (!thisObj->getPropertySlot(exec, k, slot)) continue; - JSValue v = slot.getValue(exec, k); - MarkedArgumentBuffer eachArguments; + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + MarkedArgumentBuffer eachArguments; eachArguments.append(v); eachArguments.append(jsNumber(k)); eachArguments.append(thisObj); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + JSValue result = call(exec, function, callType, callData, applyThis, eachArguments); resultArray->put(exec, k, result); } @@ -730,6 +770,9 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState* exec) { JSObject* thisObj = exec->hostThisValue().toThisObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); JSValue function = exec->argument(0); CallData callData; @@ -741,7 +784,6 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState* exec) JSValue result = jsBoolean(true); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); unsigned k = 0; if (callType == CallTypeJS && isJSArray(&exec->globalData(), thisObj)) { JSFunction* f = asFunction(function); @@ -762,18 +804,18 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState* exec) } for (; k < length && !exec->hadException(); ++k) { PropertySlot slot(thisObj); - if (!thisObj->getPropertySlot(exec, k, slot)) continue; MarkedArgumentBuffer eachArguments; - eachArguments.append(slot.getValue(exec, k)); eachArguments.append(jsNumber(k)); eachArguments.append(thisObj); - bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments).toBoolean(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments).toBoolean(exec); if (!predicateResult) { result = jsBoolean(false); break; @@ -786,6 +828,9 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState* exec) { JSObject* thisObj = exec->hostThisValue().toThisObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); JSValue function = exec->argument(0); CallData callData; @@ -795,7 +840,6 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState* exec) JSObject* applyThis = exec->argument(1).isUndefinedOrNull() ? exec->globalThisValue() : exec->argument(1).toObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); unsigned k = 0; if (callType == CallTypeJS && isJSArray(&exec->globalData(), thisObj)) { JSFunction* f = asFunction(function); @@ -823,6 +867,9 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState* exec) eachArguments.append(jsNumber(k)); eachArguments.append(thisObj); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + call(exec, function, callType, callData, applyThis, eachArguments); } return JSValue::encode(jsUndefined()); @@ -831,6 +878,9 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState* exec) { JSObject* thisObj = exec->hostThisValue().toThisObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); JSValue function = exec->argument(0); CallData callData; @@ -842,7 +892,6 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState* exec) JSValue result = jsBoolean(false); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); unsigned k = 0; if (callType == CallTypeJS && isJSArray(&exec->globalData(), thisObj)) { JSFunction* f = asFunction(function); @@ -871,8 +920,10 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState* exec) eachArguments.append(jsNumber(k)); eachArguments.append(thisObj); - bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments).toBoolean(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments).toBoolean(exec); if (predicateResult) { result = jsBoolean(true); break; @@ -884,7 +935,10 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState* exec) { JSObject* thisObj = exec->hostThisValue().toThisObject(exec); - + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + JSValue function = exec->argument(0); CallData callData; CallType callType = getCallData(function, callData); @@ -893,9 +947,9 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState* exec) unsigned i = 0; JSValue rv; - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); if (!length && exec->argumentCount() == 1) return throwVMTypeError(exec); + JSArray* array = 0; if (isJSArray(&exec->globalData(), thisObj)) array = asArray(thisObj); @@ -937,6 +991,8 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState* exec) for (; i < length && !exec->hadException(); ++i) { JSValue prop = getProperty(exec, thisObj, i); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); if (!prop) continue; @@ -954,7 +1010,10 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState* exec) { JSObject* thisObj = exec->hostThisValue().toThisObject(exec); - + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + JSValue function = exec->argument(0); CallData callData; CallType callType = getCallData(function, callData); @@ -963,9 +1022,9 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState* exec) unsigned i = 0; JSValue rv; - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); if (!length && exec->argumentCount() == 1) return throwVMTypeError(exec); + JSArray* array = 0; if (isJSArray(&exec->globalData(), thisObj)) array = asArray(thisObj); @@ -1006,6 +1065,8 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState* exec) for (; i < length && !exec->hadException(); ++i) { unsigned idx = length - i - 1; JSValue prop = getProperty(exec, thisObj, idx); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); if (!prop) continue; @@ -1022,13 +1083,13 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState* exec) { - // JavaScript 1.5 Extension by Mozilla - // Documentation: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf + // 15.4.4.14 JSObject* thisObj = exec->hostThisValue().toThisObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - unsigned index = argumentClampedIndexFromStartOrEnd(exec, 1, length); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + unsigned index = argumentClampedIndexFromStartOrEnd(exec, 1, length); JSValue searchElement = exec->argument(0); for (; index < length; ++index) { JSValue e = getProperty(exec, thisObj, index); @@ -1043,10 +1104,8 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState* exec) { - // JavaScript 1.6 Extension by Mozilla - // Documentation: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf + // 15.4.4.15 JSObject* thisObj = exec->hostThisValue().toThisObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); if (!length) return JSValue::encode(jsNumber(-1)); diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.h b/Source/JavaScriptCore/runtime/ArrayPrototype.h index 42665e3..6dadf51 100644 --- a/Source/JavaScriptCore/runtime/ArrayPrototype.h +++ b/Source/JavaScriptCore/runtime/ArrayPrototype.h @@ -28,17 +28,16 @@ namespace JSC { class ArrayPrototype : public JSArray { public: - explicit ArrayPrototype(JSGlobalObject*, NonNullPassRefPtr<Structure>); + explicit ArrayPrototype(JSGlobalObject*, Structure*); 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<Structure> createStructure(JSValue prototype) + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: diff --git a/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h b/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h index 0f6a646..df7b7f6 100644 --- a/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h +++ b/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h @@ -39,7 +39,7 @@ namespace JSC { , m_object(object) { if (!m_object->structure()->isDictionary()) - m_object->setStructure(Structure::toCacheableDictionaryTransition(m_object->structure())); + m_object->setStructure(globalData, Structure::toCacheableDictionaryTransition(globalData, m_object->structure())); } ~BatchedTransitionOptimizer() diff --git a/Source/JavaScriptCore/runtime/BooleanConstructor.cpp b/Source/JavaScriptCore/runtime/BooleanConstructor.cpp index 21ef5bb..a1a4ed4 100644 --- a/Source/JavaScriptCore/runtime/BooleanConstructor.cpp +++ b/Source/JavaScriptCore/runtime/BooleanConstructor.cpp @@ -28,7 +28,7 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(BooleanConstructor); -BooleanConstructor::BooleanConstructor(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, BooleanPrototype* booleanPrototype) +BooleanConstructor::BooleanConstructor(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, BooleanPrototype* booleanPrototype) : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, booleanPrototype->classInfo()->className)) { putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, booleanPrototype, DontEnum | DontDelete | ReadOnly); @@ -40,7 +40,7 @@ BooleanConstructor::BooleanConstructor(ExecState* exec, JSGlobalObject* globalOb // ECMA 15.6.2 JSObject* constructBoolean(ExecState* exec, const ArgList& args) { - BooleanObject* obj = new (exec) BooleanObject(exec->globalData(), exec->lexicalGlobalObject()->booleanObjectStructure()); + BooleanObject* obj = new (exec) BooleanObject(exec->globalData(), asInternalFunction(exec->callee())->globalObject()->booleanObjectStructure()); obj->setInternalValue(exec->globalData(), jsBoolean(args.at(0).toBoolean(exec))); return obj; } @@ -69,9 +69,9 @@ CallType BooleanConstructor::getCallData(CallData& callData) return CallTypeHost; } -JSObject* constructBooleanFromImmediateBoolean(ExecState* exec, JSValue immediateBooleanValue) +JSObject* constructBooleanFromImmediateBoolean(ExecState* exec, JSGlobalObject* globalObject, JSValue immediateBooleanValue) { - BooleanObject* obj = new (exec) BooleanObject(exec->globalData(), exec->lexicalGlobalObject()->booleanObjectStructure()); + BooleanObject* obj = new (exec) BooleanObject(exec->globalData(), globalObject->booleanObjectStructure()); obj->setInternalValue(exec->globalData(), immediateBooleanValue); return obj; } diff --git a/Source/JavaScriptCore/runtime/BooleanConstructor.h b/Source/JavaScriptCore/runtime/BooleanConstructor.h index 0f3efa7..fa0d05e 100644 --- a/Source/JavaScriptCore/runtime/BooleanConstructor.h +++ b/Source/JavaScriptCore/runtime/BooleanConstructor.h @@ -29,14 +29,14 @@ namespace JSC { class BooleanConstructor : public InternalFunction { public: - BooleanConstructor(ExecState*, JSGlobalObject*, NonNullPassRefPtr<Structure>, BooleanPrototype*); + BooleanConstructor(ExecState*, JSGlobalObject*, Structure*, BooleanPrototype*); private: virtual ConstructType getConstructData(ConstructData&); virtual CallType getCallData(CallData&); }; - JSObject* constructBooleanFromImmediateBoolean(ExecState*, JSValue); + JSObject* constructBooleanFromImmediateBoolean(ExecState*, JSGlobalObject*, JSValue); JSObject* constructBoolean(ExecState*, const ArgList&); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/BooleanObject.cpp b/Source/JavaScriptCore/runtime/BooleanObject.cpp index 71ff2d2..e24a30a 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> structure) +BooleanObject::BooleanObject(JSGlobalData& globalData, Structure* 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..def44b4 100644 --- a/Source/JavaScriptCore/runtime/BooleanObject.h +++ b/Source/JavaScriptCore/runtime/BooleanObject.h @@ -27,14 +27,13 @@ namespace JSC { class BooleanObject : public JSWrapperObject { public: - explicit BooleanObject(JSGlobalData& globalData, NonNullPassRefPtr<Structure>); + explicit BooleanObject(JSGlobalData&, Structure*); - virtual const ClassInfo* classInfo() const { return &info; } - static const ClassInfo info; + static const ClassInfo s_info; - static PassRefPtr<Structure> createStructure(JSValue prototype) + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, 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<BooleanObject*>(asObject(value)); } diff --git a/Source/JavaScriptCore/runtime/BooleanPrototype.cpp b/Source/JavaScriptCore/runtime/BooleanPrototype.cpp index 54d621c..20990e1 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, Structure* prototypeFunctionStructure) +BooleanPrototype::BooleanPrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* 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..5ccbd2b 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>, Structure* prototypeFunctionStructure); + BooleanPrototype(ExecState*, JSGlobalObject*, Structure*, 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..ac19705 100644 --- a/Source/JavaScriptCore/runtime/Completion.cpp +++ b/Source/JavaScriptCore/runtime/Completion.cpp @@ -39,7 +39,7 @@ Completion checkSyntax(ExecState* exec, const SourceCode& source) JSLock lock(exec); ASSERT(exec->globalData().identifierTable == wtfThreadData().currentIdentifierTable()); - RefPtr<ProgramExecutable> program = ProgramExecutable::create(exec, source); + ProgramExecutable* program = ProgramExecutable::create(exec, source); JSObject* error = program->checkSyntax(exec); if (error) return Completion(Throw, error); @@ -47,19 +47,21 @@ 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<ProgramExecutable> program = ProgramExecutable::create(exec, source); - JSObject* error = program->compile(exec, scopeChain.node()); - if (error) - return Completion(Throw, error); + ProgramExecutable* program = ProgramExecutable::create(exec, source); + if (!program) { + JSValue exception = exec->globalData().exception; + exec->globalData().exception = JSValue(); + return Completion(Throw, exception); + } 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, 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/ConservativeSet.h b/Source/JavaScriptCore/runtime/ConservativeSet.h deleted file mode 100644 index e7c2c4a..0000000 --- a/Source/JavaScriptCore/runtime/ConservativeSet.h +++ /dev/null @@ -1,80 +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 ConservativeSet_h -#define ConservativeSet_h - -#include "Heap.h" -#include "MarkStack.h" -#include <wtf/Vector.h> - -namespace JSC { - -class JSCell; - -class ConservativeSet { -public: - ConservativeSet(Heap*); - ~ConservativeSet(); - - void add(void* begin, void* end); - void mark(MarkStack&); - -private: - static const size_t inlineCapacity = 128; - static const size_t nonInlineCapacity = 8192 / sizeof(JSCell*); - - void grow(); - - Heap* m_heap; - DeprecatedPtr<JSCell>* m_set; - size_t m_size; - size_t m_capacity; - DeprecatedPtr<JSCell> m_inlineSet[inlineCapacity]; -}; - -inline ConservativeSet::ConservativeSet(Heap* heap) - : m_heap(heap) - , m_set(m_inlineSet) - , m_size(0) - , m_capacity(inlineCapacity) -{ -} - -inline ConservativeSet::~ConservativeSet() -{ - if (m_set != m_inlineSet) - OSAllocator::decommitAndRelease(m_set, m_capacity * sizeof(DeprecatedPtr<JSCell>*)); -} - -inline void ConservativeSet::mark(MarkStack& markStack) -{ - for (size_t i = 0; i < m_size; ++i) - markStack.append(&m_set[i]); -} - -} // namespace JSC - -#endif // ConservativeSet_h diff --git a/Source/JavaScriptCore/runtime/DateConstructor.cpp b/Source/JavaScriptCore/runtime/DateConstructor.cpp index f1f3956..9bbb688 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 <math.h> #include <time.h> #include <wtf/DateMath.h> @@ -58,20 +57,20 @@ 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, Structure* prototypeFunctionStructure, DatePrototype* datePrototype) +DateConstructor::DateConstructor(ExecState* exec, JSGlobalObject* globalObject, Structure* 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 -JSObject* constructDate(ExecState* exec, const ArgList& args) +JSObject* constructDate(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args) { int numArgs = args.size(); @@ -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); @@ -122,13 +121,13 @@ JSObject* constructDate(ExecState* exec, const ArgList& args) } } - return new (exec) DateInstance(exec, value); + return new (exec) DateInstance(exec, globalObject->dateStructure(), value); } static EncodedJSValue JSC_HOST_CALL constructWithDateConstructor(ExecState* exec) { ArgList args(exec); - return JSValue::encode(constructDate(exec, args)); + return JSValue::encode(constructDate(exec, asInternalFunction(exec->callee())->globalObject(), args)); } ConstructType DateConstructor::getConstructData(ConstructData& constructData) diff --git a/Source/JavaScriptCore/runtime/DateConstructor.h b/Source/JavaScriptCore/runtime/DateConstructor.h index c8ca456..23a0311 100644 --- a/Source/JavaScriptCore/runtime/DateConstructor.h +++ b/Source/JavaScriptCore/runtime/DateConstructor.h @@ -29,14 +29,14 @@ namespace JSC { class DateConstructor : public InternalFunction { public: - DateConstructor(ExecState*, JSGlobalObject*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure, DatePrototype*); + DateConstructor(ExecState*, JSGlobalObject*, Structure*, Structure* functionStructure, DatePrototype*); private: virtual ConstructType getConstructData(ConstructData&); virtual CallType getCallData(CallData&); }; - JSObject* constructDate(ExecState*, const ArgList&); + JSObject* constructDate(ExecState*, JSGlobalObject*, const ArgList&); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/DateConversion.cpp b/Source/JavaScriptCore/runtime/DateConversion.cpp index d4b8232..1418876 100644 --- a/Source/JavaScriptCore/runtime/DateConversion.cpp +++ b/Source/JavaScriptCore/runtime/DateConversion.cpp @@ -44,6 +44,8 @@ #include "DateConversion.h" #include "CallFrame.h" +#include "JSObject.h" +#include "ScopeChain.h" #include "UString.h" #include <wtf/DateMath.h> #include <wtf/StringExtras.h> diff --git a/Source/JavaScriptCore/runtime/DateInstance.cpp b/Source/JavaScriptCore/runtime/DateInstance.cpp index 44e8b7d..d8ca072 100644 --- a/Source/JavaScriptCore/runtime/DateInstance.cpp +++ b/Source/JavaScriptCore/runtime/DateInstance.cpp @@ -32,23 +32,19 @@ 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> structure) +DateInstance::DateInstance(ExecState* exec, Structure* structure) : JSWrapperObject(exec->globalData(), structure) { + ASSERT(inherits(&s_info)); setInternalValue(exec->globalData(), jsNaN()); } -DateInstance::DateInstance(ExecState* exec, NonNullPassRefPtr<Structure> structure, double time) +DateInstance::DateInstance(ExecState* exec, Structure* structure, double time) : JSWrapperObject(exec->globalData(), structure) { - 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..6195c85 100644 --- a/Source/JavaScriptCore/runtime/DateInstance.h +++ b/Source/JavaScriptCore/runtime/DateInstance.h @@ -31,13 +31,12 @@ namespace JSC { class DateInstance : public JSWrapperObject { public: - DateInstance(ExecState*, double); - DateInstance(ExecState*, NonNullPassRefPtr<Structure>, double); - explicit DateInstance(ExecState*, NonNullPassRefPtr<Structure>); + DateInstance(ExecState*, Structure*, double); + explicit DateInstance(ExecState*, Structure*); 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 { @@ -53,18 +52,14 @@ namespace JSC { return calculateGregorianDateTimeUTC(exec); } - static PassRefPtr<Structure> createStructure(JSValue prototype) + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } - protected: - static const unsigned StructureFlags = OverridesMarkChildren | JSWrapperObject::StructureFlags; - private: const GregorianDateTime* calculateGregorianDateTime(ExecState*) const; const GregorianDateTime* calculateGregorianDateTimeUTC(ExecState*) const; - virtual const ClassInfo* classInfo() const { return &info; } mutable RefPtr<DateInstanceData> m_data; }; @@ -73,7 +68,7 @@ namespace JSC { inline DateInstance* asDateInstance(JSValue value) { - ASSERT(asObject(value)->inherits(&DateInstance::info)); + ASSERT(asObject(value)->inherits(&DateInstance::s_info)); return static_cast<DateInstance*>(asObject(value)); } diff --git a/Source/JavaScriptCore/runtime/DatePrototype.cpp b/Source/JavaScriptCore/runtime/DatePrototype.cpp index 5838b60..444fa98 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 @@ -429,9 +429,11 @@ const ClassInfo DatePrototype::info = {"Date", &DateInstance::info, 0, ExecState // ECMA 15.9.4 -DatePrototype::DatePrototype(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure) +DatePrototype::DatePrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* 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..2e1030d 100644 --- a/Source/JavaScriptCore/runtime/DatePrototype.h +++ b/Source/JavaScriptCore/runtime/DatePrototype.h @@ -29,22 +29,23 @@ namespace JSC { class DatePrototype : public DateInstance { public: - DatePrototype(ExecState*, JSGlobalObject*, NonNullPassRefPtr<Structure>); + DatePrototype(ExecState*, JSGlobalObject*, Structure*); 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<Structure> createStructure(JSValue prototype) + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: static const unsigned StructureFlags = OverridesGetOwnPropertySlot | DateInstance::StructureFlags; + COMPILE_ASSERT(!DateInstance::AnonymousSlotCount, DatePrototype_stomps_on_your_anonymous_slot); + static const unsigned AnonymousSlotCount = 1; }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Error.cpp b/Source/JavaScriptCore/runtime/Error.cpp index b84f5ea..7eda19f 100644 --- a/Source/JavaScriptCore/runtime/Error.cpp +++ b/Source/JavaScriptCore/runtime/Error.cpp @@ -167,7 +167,7 @@ JSObject* throwSyntaxError(ExecState* exec) class StrictModeTypeErrorFunction : public InternalFunction { public: - StrictModeTypeErrorFunction(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, const UString& message) + StrictModeTypeErrorFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, const UString& message) : InternalFunction(&exec->globalData(), globalObject, structure, exec->globalData().propertyNames->emptyIdentifier) , m_message(message) { diff --git a/Source/JavaScriptCore/runtime/ErrorConstructor.cpp b/Source/JavaScriptCore/runtime/ErrorConstructor.cpp index 2e53b95..df112dd 100644 --- a/Source/JavaScriptCore/runtime/ErrorConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ErrorConstructor.cpp @@ -29,7 +29,7 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(ErrorConstructor); -ErrorConstructor::ErrorConstructor(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, ErrorPrototype* errorPrototype) +ErrorConstructor::ErrorConstructor(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, ErrorPrototype* errorPrototype) : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, errorPrototype->classInfo()->className)) { // ECMA 15.11.3.1 Error.prototype @@ -42,7 +42,7 @@ ErrorConstructor::ErrorConstructor(ExecState* exec, JSGlobalObject* globalObject static EncodedJSValue JSC_HOST_CALL constructWithErrorConstructor(ExecState* exec) { JSValue message = exec->argumentCount() ? exec->argument(0) : jsUndefined(); - Structure* errorStructure = exec->lexicalGlobalObject()->errorStructure(); + Structure* errorStructure = asInternalFunction(exec->callee())->globalObject()->errorStructure(); return JSValue::encode(ErrorInstance::create(exec, errorStructure, message)); } @@ -55,7 +55,7 @@ ConstructType ErrorConstructor::getConstructData(ConstructData& constructData) static EncodedJSValue JSC_HOST_CALL callErrorConstructor(ExecState* exec) { JSValue message = exec->argumentCount() ? exec->argument(0) : jsUndefined(); - Structure* errorStructure = exec->lexicalGlobalObject()->errorStructure(); + Structure* errorStructure = asInternalFunction(exec->callee())->globalObject()->errorStructure(); return JSValue::encode(ErrorInstance::create(exec, errorStructure, message)); } diff --git a/Source/JavaScriptCore/runtime/ErrorConstructor.h b/Source/JavaScriptCore/runtime/ErrorConstructor.h index 3d0d706..ceec005 100644 --- a/Source/JavaScriptCore/runtime/ErrorConstructor.h +++ b/Source/JavaScriptCore/runtime/ErrorConstructor.h @@ -30,7 +30,7 @@ namespace JSC { class ErrorConstructor : public InternalFunction { public: - ErrorConstructor(ExecState*, JSGlobalObject*, NonNullPassRefPtr<Structure>, ErrorPrototype*); + ErrorConstructor(ExecState*, JSGlobalObject*, Structure*, ErrorPrototype*); private: virtual ConstructType getConstructData(ConstructData&); diff --git a/Source/JavaScriptCore/runtime/ErrorInstance.cpp b/Source/JavaScriptCore/runtime/ErrorInstance.cpp index a6208d5..ed95ba4 100644 --- a/Source/JavaScriptCore/runtime/ErrorInstance.cpp +++ b/Source/JavaScriptCore/runtime/ErrorInstance.cpp @@ -23,28 +23,30 @@ 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> structure) - : JSObject(structure) +ErrorInstance::ErrorInstance(JSGlobalData* globalData, Structure* structure) + : JSNonFinalObject(*globalData, structure) , m_appendSourceToMessage(false) { + ASSERT(inherits(&s_info)); putDirect(*globalData, globalData->propertyNames->message, jsString(globalData, "")); } -ErrorInstance::ErrorInstance(JSGlobalData* globalData, NonNullPassRefPtr<Structure> structure, const UString& message) - : JSObject(structure) +ErrorInstance::ErrorInstance(JSGlobalData* globalData, Structure* structure, const UString& message) + : JSNonFinalObject(*globalData, structure) , m_appendSourceToMessage(false) { + ASSERT(inherits(&s_info)); putDirect(*globalData, globalData->propertyNames->message, jsString(globalData, message)); } -ErrorInstance* ErrorInstance::create(JSGlobalData* globalData, NonNullPassRefPtr<Structure> structure, const UString& message) +ErrorInstance* ErrorInstance::create(JSGlobalData* globalData, Structure* structure, const UString& message) { return new (globalData) ErrorInstance(globalData, structure, message); } -ErrorInstance* ErrorInstance::create(ExecState* exec, NonNullPassRefPtr<Structure> structure, JSValue message) +ErrorInstance* ErrorInstance::create(ExecState* exec, Structure* structure, JSValue message) { if (message.isUndefined()) return new (exec) ErrorInstance(&exec->globalData(), structure); diff --git a/Source/JavaScriptCore/runtime/ErrorInstance.h b/Source/JavaScriptCore/runtime/ErrorInstance.h index b3bebec..afcf158 100644 --- a/Source/JavaScriptCore/runtime/ErrorInstance.h +++ b/Source/JavaScriptCore/runtime/ErrorInstance.h @@ -25,14 +25,17 @@ 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 Structure* createStructure(JSGlobalData& globalData, JSValue prototype) + { + return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); + } - static ErrorInstance* create(JSGlobalData*, NonNullPassRefPtr<Structure>, const UString&); - static ErrorInstance* create(ExecState* exec, NonNullPassRefPtr<Structure>, JSValue message); + static ErrorInstance* create(JSGlobalData*, Structure*, const UString&); + static ErrorInstance* create(ExecState*, Structure*, JSValue message); bool appendSourceToMessage() { return m_appendSourceToMessage; } @@ -42,8 +45,8 @@ namespace JSC { virtual bool isErrorInstance() const { return true; } protected: - explicit ErrorInstance(JSGlobalData*, NonNullPassRefPtr<Structure>); - explicit ErrorInstance(JSGlobalData*, NonNullPassRefPtr<Structure>, const UString&); + explicit ErrorInstance(JSGlobalData*, Structure*); + explicit ErrorInstance(JSGlobalData*, Structure*, const UString&); bool m_appendSourceToMessage; }; diff --git a/Source/JavaScriptCore/runtime/ErrorPrototype.cpp b/Source/JavaScriptCore/runtime/ErrorPrototype.cpp index b4e0a7c..a57e947 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, Structure* prototypeFunctionStructure) +ErrorPrototype::ErrorPrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* 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..9437d3a 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>, Structure* prototypeFunctionStructure); + ErrorPrototype(ExecState*, JSGlobalObject*, Structure*, Structure* functionStructure); }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp index 4a58800..1d74315 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, globalData->interruptedExecutionErrorStructure.get()) { } @@ -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, globalData->terminatedExecutionErrorStructure.get()) { } diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp index 25c551b..fa14ad5 100644 --- a/Source/JavaScriptCore/runtime/Executable.cpp +++ b/Source/JavaScriptCore/runtime/Executable.cpp @@ -33,20 +33,25 @@ #include "UStringBuilder.h" #include "Vector.h" +#if ENABLE(DFG_JIT) +#include "DFGByteCodeParser.h" +#include "DFGJITCompiler.h" +#endif + namespace JSC { -#if ENABLE(JIT) +const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, 0 }; + +const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0 }; + NativeExecutable::~NativeExecutable() { } -#endif -VPtrHackExecutable::~VPtrHackExecutable() -{ -} +const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0 }; EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext) - : ScriptExecutable(exec, source, inStrictContext) + : ScriptExecutable(exec->globalData().evalExecutableStructure.get(), exec, source, inStrictContext) { } @@ -54,8 +59,10 @@ EvalExecutable::~EvalExecutable() { } +const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, 0 }; + ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source) - : ScriptExecutable(exec, source, false) + : ScriptExecutable(exec->globalData().programExecutableStructure.get(), exec, source, false) { } @@ -63,8 +70,10 @@ ProgramExecutable::~ProgramExecutable() { } +const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0 }; + FunctionExecutable::FunctionExecutable(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext, int firstLine, int lastLine) - : ScriptExecutable(globalData, source, inStrictContext) + : ScriptExecutable(globalData->functionExecutableStructure.get(), globalData, source, inStrictContext) , m_numCapturedVariables(0) , m_forceUsesArguments(forceUsesArguments) , m_parameters(parameters) @@ -76,7 +85,7 @@ FunctionExecutable::FunctionExecutable(JSGlobalData* globalData, const Identifie } FunctionExecutable::FunctionExecutable(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext, int firstLine, int lastLine) - : ScriptExecutable(exec, source, inStrictContext) + : ScriptExecutable(exec->globalData().functionExecutableStructure.get(), exec, source, inStrictContext) , m_numCapturedVariables(0) , m_forceUsesArguments(forceUsesArguments) , m_parameters(parameters) @@ -87,9 +96,6 @@ FunctionExecutable::FunctionExecutable(ExecState* exec, const Identifier& name, m_lastLine = lastLine; } -FunctionExecutable::~FunctionExecutable() -{ -} JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode) { @@ -103,12 +109,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<BytecodeGenerator> 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<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(evalNode.get(), scopeChainNode, m_evalCodeBlock->symbolTable(), m_evalCodeBlock.get()))); if ((exception = generator->generate())) { m_evalCodeBlock.clear(); evalNode->destroyData(); @@ -130,6 +135,13 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scope return 0; } +void EvalExecutable::markChildren(MarkStack& markStack) +{ + ScriptExecutable::markChildren(markStack); + if (m_evalCodeBlock) + m_evalCodeBlock->markAggregate(markStack); +} + JSObject* ProgramExecutable::checkSyntax(ExecState* exec) { JSObject* exception = 0; @@ -156,11 +168,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<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(programNode.get(), scopeChain, &globalObject->symbolTable(), m_programCodeBlock.get()))); + OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(programNode.get(), scopeChainNode, &globalObject->symbolTable(), m_programCodeBlock.get()))); if ((exception = generator->generate())) { m_programCodeBlock.clear(); programNode->destroyData(); @@ -182,6 +193,41 @@ JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* sc return 0; } +#if ENABLE(JIT) +static bool tryDFGCompile(JSGlobalData* globalData, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck) +{ +#if ENABLE(DFG_JIT) +#if ENABLE(DFG_JIT_RESTRICTIONS) + // FIXME: No flow control yet supported, don't bother scanning the bytecode if there are any jump targets. + // FIXME: temporarily disable property accesses until we fix regressions. + if (codeBlock->numberOfJumpTargets() || codeBlock->numberOfStructureStubInfos()) + return false; +#endif + + DFG::Graph dfg; + if (!parse(dfg, globalData, codeBlock)) + return false; + + DFG::JITCompiler dataFlowJIT(globalData, dfg, codeBlock); + dataFlowJIT.compileFunction(jitCode, jitCodeWithArityCheck); + return true; +#else + UNUSED_PARAM(globalData); + UNUSED_PARAM(codeBlock); + UNUSED_PARAM(jitCode); + UNUSED_PARAM(jitCodeWithArityCheck); + return false; +#endif +} +#endif + +void ProgramExecutable::markChildren(MarkStack& markStack) +{ + ScriptExecutable::markChildren(markStack); + if (m_programCodeBlock) + m_programCodeBlock->markAggregate(markStack); +} + JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChainNode* scopeChainNode) { JSObject* exception = 0; @@ -196,12 +242,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<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChain, m_codeBlockForCall->symbolTable(), m_codeBlockForCall.get()))); + OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChainNode, m_codeBlockForCall->symbolTable(), m_codeBlockForCall.get()))); if ((exception = generator->generate())) { m_codeBlockForCall.clear(); body->destroyData(); @@ -217,7 +262,10 @@ JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChain #if ENABLE(JIT) if (exec->globalData().canUseJIT()) { - m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_codeBlockForCall.get(), &m_jitCodeForCallWithArityCheck); + bool dfgCompiled = tryDFGCompile(&exec->globalData(), m_codeBlockForCall.get(), m_jitCodeForCall, m_jitCodeForCallWithArityCheck); + if (!dfgCompiled) + m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_codeBlockForCall.get(), &m_jitCodeForCallWithArityCheck); + #if !ENABLE(OPCODE_SAMPLING) if (!BytecodeGenerator::dumpsGeneratedCode()) m_codeBlockForCall->discardBytecode(); @@ -242,12 +290,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<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChain, m_codeBlockForConstruct->symbolTable(), m_codeBlockForConstruct.get()))); + OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChainNode, m_codeBlockForConstruct->symbolTable(), m_codeBlockForConstruct.get()))); if ((exception = generator->generate())) { m_codeBlockForConstruct.clear(); body->destroyData(); @@ -274,8 +321,9 @@ JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, Scope return 0; } -void FunctionExecutable::markAggregate(MarkStack& markStack) +void FunctionExecutable::markChildren(MarkStack& markStack) { + ScriptExecutable::markChildren(markStack); if (m_codeBlockForCall) m_codeBlockForCall->markAggregate(markStack); if (m_codeBlockForConstruct) @@ -294,7 +342,7 @@ void FunctionExecutable::discardCode() #endif } -PassRefPtr<FunctionExecutable> FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception) +FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception) { JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); RefPtr<ProgramNode> program = exec->globalData().parser->parse<ProgramNode>(lexicalGlobalObject, debugger, exec, source, 0, JSParseNormal, exception); diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h index 544e487..fbe33cf 100644 --- a/Source/JavaScriptCore/runtime/Executable.h +++ b/Source/JavaScriptCore/runtime/Executable.h @@ -44,7 +44,7 @@ namespace JSC { struct ExceptionInfo; - class ExecutableBase : public RefCounted<ExecutableBase> { + class ExecutableBase : public JSCell { friend class JIT; protected: @@ -52,21 +52,24 @@ namespace JSC { static const int NUM_PARAMETERS_NOT_COMPILED = -1; public: - ExecutableBase(int numParameters) - : m_numParametersForCall(numParameters) + ExecutableBase(JSGlobalData& globalData, Structure* structure, int numParameters) + : JSCell(globalData, structure) + , m_numParametersForCall(numParameters) , m_numParametersForConstruct(numParameters) { } - virtual ~ExecutableBase() {} - bool isHostFunction() const { ASSERT((m_numParametersForCall == NUM_PARAMETERS_IS_HOST) == (m_numParametersForConstruct == NUM_PARAMETERS_IS_HOST)); return m_numParametersForCall == NUM_PARAMETERS_IS_HOST; } + static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info); } + protected: + static const unsigned StructureFlags = 0; + static const ClassInfo s_info; int m_numParametersForCall; int m_numParametersForConstruct; @@ -92,24 +95,33 @@ namespace JSC { #endif }; -#if ENABLE(JIT) class NativeExecutable : public ExecutableBase { friend class JIT; public: - static PassRefPtr<NativeExecutable> create(MacroAssemblerCodePtr callThunk, NativeFunction function, MacroAssemblerCodePtr constructThunk, NativeFunction constructor) +#if ENABLE(JIT) + static NativeExecutable* create(JSGlobalData& globalData, 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)); + return new (&globalData) NativeExecutable(globalData, JITCode(), function, JITCode(), constructor); + return new (&globalData) NativeExecutable(globalData, JITCode::HostFunction(callThunk), function, JITCode::HostFunction(constructThunk), constructor); } +#else + static NativeExecutable* create(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor) + { + return new (&globalData) NativeExecutable(globalData, function, constructor); + } +#endif ~NativeExecutable(); NativeFunction function() { return m_function; } + static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(LeafType, StructureFlags), AnonymousSlotCount, &s_info); } + private: - NativeExecutable(JITCode callThunk, NativeFunction function, JITCode constructThunk, NativeFunction constructor) - : ExecutableBase(NUM_PARAMETERS_IS_HOST) +#if ENABLE(JIT) + NativeExecutable(JSGlobalData& globalData, JITCode callThunk, NativeFunction function, JITCode constructThunk, NativeFunction constructor) + : ExecutableBase(globalData, globalData.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST) , m_function(function) , m_constructor(constructor) { @@ -118,28 +130,26 @@ namespace JSC { m_jitCodeForCallWithArityCheck = callThunk.addressForCall(); m_jitCodeForConstructWithArityCheck = constructThunk.addressForCall(); } +#else + NativeExecutable(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor) + : ExecutableBase(globalData, globalData.nativeExecutableStructure.get(), 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: - VPtrHackExecutable() - : ExecutableBase(NUM_PARAMETERS_IS_HOST) - { - } - - ~VPtrHackExecutable(); + static const ClassInfo s_info; }; class ScriptExecutable : public ExecutableBase { public: - ScriptExecutable(JSGlobalData* globalData, const SourceCode& source, bool isInStrictContext) - : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED) + ScriptExecutable(Structure* structure, JSGlobalData* globalData, const SourceCode& source, bool isInStrictContext) + : ExecutableBase(*globalData, structure, NUM_PARAMETERS_NOT_COMPILED) , m_source(source) , m_features(isInStrictContext ? StrictModeFeature : 0) { @@ -152,8 +162,8 @@ namespace JSC { #endif } - ScriptExecutable(ExecState* exec, const SourceCode& source, bool isInStrictContext) - : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED) + ScriptExecutable(Structure* structure, ExecState* exec, const SourceCode& source, bool isInStrictContext) + : ExecutableBase(exec->globalData(), structure, NUM_PARAMETERS_NOT_COMPILED) , m_source(source) , m_features(isInStrictContext ? StrictModeFeature : 0) { @@ -200,6 +210,7 @@ namespace JSC { JSObject* compile(ExecState* exec, ScopeChainNode* scopeChainNode) { + ASSERT(exec->globalData().dynamicGlobalObject); JSObject* error = 0; if (!m_evalCodeBlock) error = compileInternal(exec, scopeChainNode); @@ -213,7 +224,7 @@ namespace JSC { return *m_evalCodeBlock; } - static PassRefPtr<EvalExecutable> create(ExecState* exec, const SourceCode& source, bool isInStrictContext) { return adoptRef(new EvalExecutable(exec, source, isInStrictContext)); } + static EvalExecutable* create(ExecState* exec, const SourceCode& source, bool isInStrictContext) { return new (exec) EvalExecutable(exec, source, isInStrictContext); } #if ENABLE(JIT) JITCode& generatedJITCode() @@ -221,26 +232,31 @@ namespace JSC { return generatedJITCodeForCall(); } #endif + static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, 0); } private: + static const unsigned StructureFlags = OverridesMarkChildren | ScriptExecutable::StructureFlags; + static const ClassInfo s_info; EvalExecutable(ExecState*, const SourceCode&, bool); JSObject* compileInternal(ExecState*, ScopeChainNode*); + virtual void markChildren(MarkStack&); OwnPtr<EvalCodeBlock> m_evalCodeBlock; }; class ProgramExecutable : public ScriptExecutable { public: - static PassRefPtr<ProgramExecutable> create(ExecState* exec, const SourceCode& source) + static ProgramExecutable* create(ExecState* exec, const SourceCode& source) { - return adoptRef(new ProgramExecutable(exec, source)); + return new (exec) ProgramExecutable(exec, source); } ~ProgramExecutable(); JSObject* compile(ExecState* exec, ScopeChainNode* scopeChainNode) { + ASSERT(exec->globalData().dynamicGlobalObject); JSObject* error = 0; if (!m_programCodeBlock) error = compileInternal(exec, scopeChainNode); @@ -262,11 +278,16 @@ namespace JSC { return generatedJITCodeForCall(); } #endif + + static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, 0); } private: + static const unsigned StructureFlags = OverridesMarkChildren | ScriptExecutable::StructureFlags; + static const ClassInfo s_info; ProgramExecutable(ExecState*, const SourceCode&); JSObject* compileInternal(ExecState*, ScopeChainNode*); + virtual void markChildren(MarkStack&); OwnPtr<ProgramCodeBlock> m_programCodeBlock; }; @@ -274,18 +295,16 @@ namespace JSC { class FunctionExecutable : public ScriptExecutable { friend class JIT; public: - static PassRefPtr<FunctionExecutable> create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine) + static FunctionExecutable* create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine) { - return adoptRef(new FunctionExecutable(exec, name, source, forceUsesArguments, parameters, isInStrictContext, firstLine, lastLine)); + return new (exec) FunctionExecutable(exec, name, source, forceUsesArguments, parameters, isInStrictContext, firstLine, lastLine); } - static PassRefPtr<FunctionExecutable> create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine) + static FunctionExecutable* create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine) { - return adoptRef(new FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, isInStrictContext, firstLine, lastLine)); + return new (globalData) FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, isInStrictContext, firstLine, lastLine); } - ~FunctionExecutable(); - JSFunction* make(ExecState* exec, ScopeChainNode* scopeChain) { return new (exec) JSFunction(exec, this, scopeChain); @@ -304,6 +323,7 @@ namespace JSC { JSObject* compileForCall(ExecState* exec, ScopeChainNode* scopeChainNode) { + ASSERT(exec->globalData().dynamicGlobalObject); JSObject* error = 0; if (!m_codeBlockForCall) error = compileForCallInternal(exec, scopeChainNode); @@ -324,6 +344,7 @@ namespace JSC { JSObject* compileForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode) { + ASSERT(exec->globalData().dynamicGlobalObject); JSObject* error = 0; if (!m_codeBlockForConstruct) error = compileForConstructInternal(exec, scopeChainNode); @@ -349,8 +370,9 @@ namespace JSC { SharedSymbolTable* symbolTable() const { return m_symbolTable; } void discardCode(); - void markAggregate(MarkStack&); - static PassRefPtr<FunctionExecutable> fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception); + void markChildren(MarkStack&); + static FunctionExecutable* fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception); + static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, 0); } private: FunctionExecutable(JSGlobalData*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool, int firstLine, int lastLine); @@ -358,7 +380,9 @@ namespace JSC { JSObject* compileForCallInternal(ExecState*, ScopeChainNode*); JSObject* compileForConstructInternal(ExecState*, ScopeChainNode*); - + + static const unsigned StructureFlags = OverridesMarkChildren | ScriptExecutable::StructureFlags; + static const ClassInfo s_info; unsigned m_numCapturedVariables : 31; bool m_forceUsesArguments : 1; @@ -398,13 +422,11 @@ namespace JSC { return m_executable->isHostFunction(); } -#if ENABLE(JIT) inline NativeFunction JSFunction::nativeFunction() { ASSERT(isHostFunction()); return static_cast<NativeExecutable*>(m_executable.get())->function(); } -#endif } #endif diff --git a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp index 933b11f..9e7d8d5 100644 --- a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp +++ b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp @@ -37,7 +37,7 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(FunctionConstructor); -FunctionConstructor::FunctionConstructor(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, FunctionPrototype* functionPrototype) +FunctionConstructor::FunctionConstructor(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, FunctionPrototype* functionPrototype) : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, functionPrototype->classInfo()->className)) { putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, functionPrototype, DontEnum | DontDelete | ReadOnly); @@ -49,7 +49,7 @@ FunctionConstructor::FunctionConstructor(ExecState* exec, JSGlobalObject* global static EncodedJSValue JSC_HOST_CALL constructWithFunctionConstructor(ExecState* exec) { ArgList args(exec); - return JSValue::encode(constructFunction(exec, args)); + return JSValue::encode(constructFunction(exec, asInternalFunction(exec->callee())->globalObject(), args)); } ConstructType FunctionConstructor::getConstructData(ConstructData& constructData) @@ -61,7 +61,7 @@ ConstructType FunctionConstructor::getConstructData(ConstructData& constructData static EncodedJSValue JSC_HOST_CALL callFunctionConstructor(ExecState* exec) { ArgList args(exec); - return JSValue::encode(constructFunction(exec, args)); + return JSValue::encode(constructFunction(exec, asInternalFunction(exec->callee())->globalObject(), args)); } // ECMA 15.3.1 The Function Constructor Called as a Function @@ -72,7 +72,7 @@ CallType FunctionConstructor::getCallData(CallData& callData) } // ECMA 15.3.2 The Function Constructor -JSObject* constructFunction(ExecState* exec, const ArgList& args, const Identifier& functionName, const UString& sourceURL, int lineNumber) +JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, const Identifier& functionName, const UString& sourceURL, int lineNumber) { // Functions need to have a space following the opening { due to for web compatibility // see https://bugs.webkit.org/show_bug.cgi?id=24350 @@ -96,24 +96,23 @@ JSObject* constructFunction(ExecState* exec, const ArgList& args, const Identifi program = builder.toUString(); } - JSGlobalObject* globalObject = exec->lexicalGlobalObject(); JSGlobalData& globalData = globalObject->globalData(); SourceCode source = makeSource(program, sourceURL, lineNumber); JSObject* exception = 0; - RefPtr<FunctionExecutable> function = FunctionExecutable::fromGlobalCode(functionName, exec, exec->dynamicGlobalObject()->debugger(), source, &exception); + FunctionExecutable* function = FunctionExecutable::fromGlobalCode(functionName, exec, exec->dynamicGlobalObject()->debugger(), source, &exception); if (!function) { ASSERT(exception); 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 -JSObject* constructFunction(ExecState* exec, const ArgList& args) +JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args) { - return constructFunction(exec, args, Identifier(exec, "anonymous"), UString(), 1); + return constructFunction(exec, globalObject, args, Identifier(exec, "anonymous"), UString(), 1); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/FunctionConstructor.h b/Source/JavaScriptCore/runtime/FunctionConstructor.h index 6af4861..31a04c9 100644 --- a/Source/JavaScriptCore/runtime/FunctionConstructor.h +++ b/Source/JavaScriptCore/runtime/FunctionConstructor.h @@ -29,15 +29,15 @@ namespace JSC { class FunctionConstructor : public InternalFunction { public: - FunctionConstructor(ExecState*, JSGlobalObject*, NonNullPassRefPtr<Structure>, FunctionPrototype*); + FunctionConstructor(ExecState*, JSGlobalObject*, Structure*, FunctionPrototype*); private: virtual ConstructType getConstructData(ConstructData&); virtual CallType getCallData(CallData&); }; - JSObject* constructFunction(ExecState*, const ArgList&, const Identifier& functionName, const UString& sourceURL, int lineNumber); - JSObject* constructFunction(ExecState*, const ArgList&); + JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&, const Identifier& functionName, const UString& sourceURL, int lineNumber); + JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp index e651538..e2a4941 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 { @@ -38,18 +37,18 @@ static EncodedJSValue JSC_HOST_CALL functionProtoFuncToString(ExecState*); static EncodedJSValue JSC_HOST_CALL functionProtoFuncApply(ExecState*); static EncodedJSValue JSC_HOST_CALL functionProtoFuncCall(ExecState*); -FunctionPrototype::FunctionPrototype(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure) +FunctionPrototype::FunctionPrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* structure) : InternalFunction(&exec->globalData(), globalObject, structure, exec->propertyNames().nullIdentifier) { 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..ab708dd 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<Structure>); - void addFunctionProperties(ExecState*, JSGlobalObject*, Structure* prototypeFunctionStructure, NativeFunctionWrapper** callFunction, NativeFunctionWrapper** applyFunction); + FunctionPrototype(ExecState*, JSGlobalObject*, Structure*); + void addFunctionProperties(ExecState*, JSGlobalObject*, Structure* functionStructure, JSFunction** callFunction, JSFunction** applyFunction); - static PassRefPtr<Structure> createStructure(JSValue proto) + static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { - return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, 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 <wtf/OwnPtr.h> #include <wtf/PassOwnPtr.h> -#if PLATFORM(CF) +#if USE(CF) #include <CoreFoundation/CoreFoundation.h> #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..2e878bf 100644 --- a/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp +++ b/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp @@ -33,10 +33,12 @@ #include "Heap.h" #include "JSGlobalData.h" #include "JSLock.h" +#include "JSObject.h" +#include "ScopeChain.h" #include <wtf/RetainPtr.h> #include <wtf/WTFThreadData.h> -#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<uintptr_t>(this) & WeakGCHandlePool::poolMask); - return reinterpret_cast<WeakGCHandlePool*>(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 <wtf/Assertions.h> - -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<JSCell*>(m_ptr & ~3); - } - - void set(JSCell* p) - { - m_ptr = reinterpret_cast<uintptr_t>(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..a222c7a 100644 --- a/Source/JavaScriptCore/runtime/GetterSetter.h +++ b/Source/JavaScriptCore/runtime/GetterSetter.h @@ -26,6 +26,7 @@ #include "JSCell.h" #include "CallFrame.h" +#include "Structure.h" namespace JSC { @@ -37,7 +38,7 @@ namespace JSC { friend class JIT; public: GetterSetter(ExecState* exec) - : JSCell(exec->globalData().getterSetterStructure.get()) + : JSCell(exec->globalData(), exec->globalData().getterSetterStructure.get()) { } @@ -47,9 +48,9 @@ namespace JSC { void setGetter(JSGlobalData& globalData, JSObject* getter) { m_getter.set(globalData, this, getter); } JSObject* setter() const { return m_setter.get(); } void setSetter(JSGlobalData& globalData, JSObject* setter) { m_setter.set(globalData, this, setter); } - static PassRefPtr<Structure> createStructure(JSValue prototype) + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { - return Structure::create(prototype, TypeInfo(GetterSetterType, OverridesMarkChildren), AnonymousSlotCount); + return Structure::create(globalData, 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 <wtf/Assertions.h> - -namespace JSC { - -ASSERT_CLASS_FITS_IN_CELL(GlobalEvalFunction); - -GlobalEvalFunction::GlobalEvalFunction(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> 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<Structure>, int len, const Identifier&, NativeFunction, JSGlobalObject* expectedThisObject); - JSGlobalObject* cachedGlobalObject() const { return m_cachedGlobalObject.get(); } - - static PassRefPtr<Structure> 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<JSGlobalObject> m_cachedGlobalObject; - }; - -} // namespace JSC - -#endif // GlobalEvalFunction_h diff --git a/Source/JavaScriptCore/runtime/Heap.cpp b/Source/JavaScriptCore/runtime/Heap.cpp deleted file mode 100644 index c05233c..0000000 --- a/Source/JavaScriptCore/runtime/Heap.cpp +++ /dev/null @@ -1,428 +0,0 @@ -/* - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. - * Copyright (C) 2007 Eric Seidel <eric@webkit.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "config.h" -#include "Heap.h" - -#include "CodeBlock.h" -#include "ConservativeSet.h" -#include "GCActivityCallback.h" -#include "GCHandle.h" -#include "Interpreter.h" -#include "JSGlobalData.h" -#include "JSGlobalObject.h" -#include "JSLock.h" -#include "JSONObject.h" -#include "Tracing.h" -#include <algorithm> - -#define COLLECT_ON_EVERY_ALLOCATION 0 - -using namespace std; - -namespace JSC { - -const size_t minBytesPerCycle = 512 * 1024; - -Heap::Heap(JSGlobalData* globalData) - : m_operationInProgress(NoOperation) - , m_markedSpace(globalData) - , m_markListSet(0) - , m_activityCallback(DefaultGCActivityCallback::create(this)) - , m_globalData(globalData) - , m_machineStackMarker(this) - , m_markStack(globalData->jsArrayVPtr) - , m_extraCost(0) -{ - (*m_activityCallback)(); -} - -Heap::~Heap() -{ - // The destroy function must already have been called, so assert this. - ASSERT(!m_globalData); -} - -void Heap::destroy() -{ - JSLock lock(SilenceAssertionsOnly); - - if (!m_globalData) - return; - - ASSERT(!m_globalData->dynamicGlobalObject); - ASSERT(m_operationInProgress == NoOperation); - - // The global object is not GC protected at this point, so sweeping may delete it - // (and thus the global data) before other objects that may use the global data. - RefPtr<JSGlobalData> protect(m_globalData); - - delete m_markListSet; - m_markListSet = 0; - - m_markedSpace.destroy(); - - m_globalData = 0; -} - -void Heap::reportExtraMemoryCostSlowCase(size_t cost) -{ - // Our frequency of garbage collection tries to balance memory use against speed - // by collecting based on the number of newly created values. However, for values - // that hold on to a great deal of memory that's not in the form of other JS values, - // that is not good enough - in some cases a lot of those objects can pile up and - // use crazy amounts of memory without a GC happening. So we track these extra - // memory costs. Only unusually large objects are noted, and we only keep track - // of this extra cost until the next GC. In garbage collected languages, most values - // are either very short lived temporaries, or have extremely long lifetimes. So - // if a large value survives one garbage collection, there is not much point to - // collecting more frequently as long as it stays alive. - - if (m_extraCost > maxExtraCost && m_extraCost > m_markedSpace.capacity() / 2) - collectAllGarbage(); - m_extraCost += cost; -} - -void* Heap::allocate(size_t s) -{ - ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable()); - ASSERT(JSLock::lockCount() > 0); - ASSERT(JSLock::currentThreadIsHoldingLock()); - ASSERT_UNUSED(s, s <= MarkedBlock::CELL_SIZE); - ASSERT(m_operationInProgress == NoOperation); - -#if COLLECT_ON_EVERY_ALLOCATION - collectAllGarbage(); - ASSERT(m_operationInProgress == NoOperation); -#endif - - m_operationInProgress = Allocation; - void* result = m_markedSpace.allocate(s); - 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); - ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance()); - - if (!k.isCell()) - return; - - m_protectedValues.add(k.asCell()); -} - -bool Heap::unprotect(JSValue k) -{ - ASSERT(k); - ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance()); - - if (!k.isCell()) - return false; - - return m_protectedValues.remove(k.asCell()); -} - -void Heap::markProtectedObjects(MarkStack& markStack) -{ - ProtectCountSet::iterator end = m_protectedValues.end(); - for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) - markStack.deprecatedAppend(&it->first); -} - -void Heap::pushTempSortVector(Vector<ValueStringPair>* tempVector) -{ - m_tempSortingVectors.append(tempVector); -} - -void Heap::popTempSortVector(Vector<ValueStringPair>* tempVector) -{ - ASSERT_UNUSED(tempVector, tempVector == m_tempSortingVectors.last()); - m_tempSortingVectors.removeLast(); -} - -void Heap::markTempSortVectors(MarkStack& markStack) -{ - typedef Vector<Vector<ValueStringPair>* > VectorOfValueStringVectors; - - VectorOfValueStringVectors::iterator end = m_tempSortingVectors.end(); - for (VectorOfValueStringVectors::iterator it = m_tempSortingVectors.begin(); it != end; ++it) { - Vector<ValueStringPair>* tempSortingVector = *it; - - Vector<ValueStringPair>::iterator vectorEnd = tempSortingVector->end(); - for (Vector<ValueStringPair>::iterator vectorIt = tempSortingVector->begin(); vectorIt != vectorEnd; ++vectorIt) { - if (vectorIt->first) - markStack.deprecatedAppend(&vectorIt->first); - } - } -} - -inline RegisterFile& Heap::registerFile() -{ - return m_globalData->interpreter->registerFile(); -} - -void Heap::markRoots() -{ -#ifndef NDEBUG - if (m_globalData->isSharedInstance()) { - ASSERT(JSLock::lockCount() > 0); - ASSERT(JSLock::currentThreadIsHoldingLock()); - } -#endif - - ASSERT(m_operationInProgress == NoOperation); - if (m_operationInProgress != NoOperation) - CRASH(); - - m_operationInProgress = Collection; - - // We gather the conservative set before clearing mark bits, because - // conservative gathering uses the mark bits from our last mark pass to - // determine whether a reference is valid. - ConservativeSet conservativeSet(this); - m_machineStackMarker.markMachineStackConservatively(conservativeSet); - conservativeSet.add(registerFile().start(), registerFile().end()); - - m_markedSpace.clearMarks(); - - MarkStack& markStack = m_markStack; - conservativeSet.mark(markStack); - markStack.drain(); - - // Mark explicitly registered roots. - markProtectedObjects(markStack); - markStack.drain(); - - // Mark temporary vector for Array sorting - markTempSortVectors(markStack); - markStack.drain(); - - HashSet<GlobalCodeBlock*>::const_iterator end = m_codeBlocks.end(); - for (HashSet<GlobalCodeBlock*>::const_iterator it = m_codeBlocks.begin(); it != end; ++it) - (*it)->markAggregate(markStack); - markStack.drain(); - - // Mark misc. other roots. - if (m_markListSet && m_markListSet->size()) - MarkedArgumentBuffer::markLists(markStack, *m_markListSet); - if (m_globalData->exception) - markStack.append(&m_globalData->exception); - if (m_globalData->firstStringifierToMark) - JSONObject::markStringifiers(markStack, m_globalData->firstStringifierToMark); - markStack.drain(); - - // 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_operationInProgress = NoOperation; -} - -size_t Heap::objectCount() const -{ - return m_markedSpace.objectCount(); -} - -size_t Heap::size() const -{ - return m_markedSpace.size(); -} - -size_t Heap::capacity() const -{ - return m_markedSpace.capacity(); -} - -size_t Heap::globalObjectCount() -{ - return m_globalData->globalObjects.uncheckedSize(); -} - -size_t Heap::protectedGlobalObjectCount() -{ - size_t count = 0; - - 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; - } - - return count; -} - -size_t Heap::protectedObjectCount() -{ - return m_protectedValues.size(); -} - -class TypeCounter { -public: - TypeCounter(); - void operator()(JSCell*); - PassOwnPtr<TypeCountSet> take(); - -private: - const char* typeName(JSCell*); - OwnPtr<TypeCountSet> m_typeCountSet; -}; - -inline TypeCounter::TypeCounter() - : m_typeCountSet(new TypeCountSet) -{ -} - -inline const char* TypeCounter::typeName(JSCell* cell) -{ - if (cell->isString()) - return "string"; - if (cell->isGetterSetter()) - return "Getter-Setter"; - if (cell->isAPIValueWrapper()) - return "API wrapper"; - if (cell->isPropertyNameIterator()) - return "For-in iterator"; - if (!cell->isObject()) - return "[empty cell]"; - const ClassInfo* info = cell->classInfo(); - return info ? info->className : "Object"; -} - -inline void TypeCounter::operator()(JSCell* cell) -{ - m_typeCountSet->add(typeName(cell)); -} - -inline PassOwnPtr<TypeCountSet> TypeCounter::take() -{ - return m_typeCountSet.release(); -} - -PassOwnPtr<TypeCountSet> Heap::protectedObjectTypeCounts() -{ - TypeCounter typeCounter; - - ProtectCountSet::iterator end = m_protectedValues.end(); - for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) - typeCounter(it->first); - - return typeCounter.take(); -} - -PassOwnPtr<TypeCountSet> Heap::objectTypeCounts() -{ - TypeCounter typeCounter; - forEach(typeCounter); - return typeCounter.take(); -} - -bool Heap::isBusy() -{ - return m_operationInProgress != NoOperation; -} - -void Heap::collectAllGarbage() -{ - reset(DoSweep); -} - -void Heap::reset(SweepToggle sweepToggle) -{ - ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable()); - JAVASCRIPTCORE_GC_BEGIN(); - - markRoots(); - - JAVASCRIPTCORE_GC_MARKED(); - - m_markedSpace.reset(); - m_extraCost = 0; - - if (sweepToggle == DoSweep) { - m_markedSpace.sweep(); - m_markedSpace.shrink(); - } - - size_t proportionalBytes = static_cast<size_t>(1.5 * m_markedSpace.size()); - m_markedSpace.setHighWaterMark(max(proportionalBytes, minBytesPerCycle)); - - JAVASCRIPTCORE_GC_END(); - - (*m_activityCallback)(); -} - -void Heap::setActivityCallback(PassOwnPtr<GCActivityCallback> activityCallback) -{ - m_activityCallback = activityCallback; -} - -GCActivityCallback* Heap::activityCallback() -{ - return m_activityCallback.get(); -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Heap.h b/Source/JavaScriptCore/runtime/Heap.h deleted file mode 100644 index 6591a5b..0000000 --- a/Source/JavaScriptCore/runtime/Heap.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (C) 1999-2000 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. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef Heap_h -#define Heap_h - -#include "MarkStack.h" -#include "MarkedSpace.h" -#include <wtf/Forward.h> -#include <wtf/HashSet.h> - -namespace JSC { - - class GCActivityCallback; - class GlobalCodeBlock; - class JSCell; - class JSGlobalData; - class JSValue; - class JSValue; - class LiveObjectIterator; - class MarkStack; - class MarkedArgumentBuffer; - class RegisterFile; - class UString; - class WeakGCHandlePool; - - typedef std::pair<JSValue, UString> ValueStringPair; - typedef HashCountedSet<JSCell*> ProtectCountSet; - typedef HashCountedSet<const char*> TypeCountSet; - - enum OperationInProgress { NoOperation, Allocation, Collection }; - - class Heap { - WTF_MAKE_NONCOPYABLE(Heap); - public: - static Heap* heap(JSValue); // 0 for immediate values - static Heap* heap(JSCell*); - - static bool isMarked(const JSCell*); - static bool testAndSetMarked(const JSCell*); - static void setMarked(JSCell*); - - Heap(JSGlobalData*); - ~Heap(); - void destroy(); // JSGlobalData must call destroy() before ~Heap(). - - JSGlobalData* globalData() const { return m_globalData; } - MarkedSpace& markedSpace() { return m_markedSpace; } - MachineStackMarker& machineStackMarker() { return m_machineStackMarker; } - - GCActivityCallback* activityCallback(); - void setActivityCallback(PassOwnPtr<GCActivityCallback>); - - bool isBusy(); // true if an allocation or collection is in progress - void* allocate(size_t); - void collectAllGarbage(); - - void reportExtraMemoryCost(size_t cost); - - void protect(JSValue); - bool unprotect(JSValue); // True when the protect count drops to 0. - - bool contains(void*); - - size_t size() const; - size_t capacity() const; - size_t objectCount() const; - size_t globalObjectCount(); - size_t protectedObjectCount(); - size_t protectedGlobalObjectCount(); - PassOwnPtr<TypeCountSet> protectedObjectTypeCounts(); - PassOwnPtr<TypeCountSet> objectTypeCounts(); - - WeakGCHandle* addWeakGCHandle(JSCell*); - - void pushTempSortVector(Vector<ValueStringPair>*); - void popTempSortVector(Vector<ValueStringPair>*); - - HashSet<GlobalCodeBlock*>& codeBlocks() { return m_codeBlocks; } - - HashSet<MarkedArgumentBuffer*>& markListSet() { if (!m_markListSet) m_markListSet = new HashSet<MarkedArgumentBuffer*>; return *m_markListSet; } - - template <typename Functor> void forEach(Functor&); - - private: - friend class JSGlobalData; - - static const size_t minExtraCost = 256; - static const size_t maxExtraCost = 1024 * 1024; - - 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); - - RegisterFile& registerFile(); - - OperationInProgress m_operationInProgress; - MarkedSpace m_markedSpace; - - ProtectCountSet m_protectedValues; - Vector<PageAllocationAligned> m_weakGCHandlePools; - Vector<Vector<ValueStringPair>* > m_tempSortingVectors; - HashSet<GlobalCodeBlock*> m_codeBlocks; - - HashSet<MarkedArgumentBuffer*>* m_markListSet; - - OwnPtr<GCActivityCallback> m_activityCallback; - - JSGlobalData* m_globalData; - - MachineStackMarker m_machineStackMarker; - MarkStack m_markStack; - - size_t m_extraCost; - }; - - inline bool Heap::isMarked(const JSCell* cell) - { - return MarkedSpace::isMarked(cell); - } - - inline bool Heap::testAndSetMarked(const JSCell* cell) - { - return MarkedSpace::testAndSetMarked(cell); - } - - inline void Heap::setMarked(JSCell* cell) - { - MarkedSpace::setMarked(cell); - } - - inline bool Heap::contains(void* p) - { - return m_markedSpace.contains(p); - } - - inline void Heap::reportExtraMemoryCost(size_t cost) - { - if (cost > minExtraCost) - reportExtraMemoryCostSlowCase(cost); - } - - inline WeakGCHandlePool* Heap::weakGCHandlePool(size_t index) - { - return static_cast<WeakGCHandlePool*>(m_weakGCHandlePools[index].base()); - } - - template <typename Functor> inline void Heap::forEach(Functor& functor) - { - m_markedSpace.forEach(functor); - } - -} // namespace JSC - -#endif // Heap_h diff --git a/Source/JavaScriptCore/runtime/Identifier.cpp b/Source/JavaScriptCore/runtime/Identifier.cpp index 28cfd0a..4a99b19 100644 --- a/Source/JavaScriptCore/runtime/Identifier.cpp +++ b/Source/JavaScriptCore/runtime/Identifier.cpp @@ -22,7 +22,9 @@ #include "Identifier.h" #include "CallFrame.h" +#include "JSObject.h" #include "NumericStrings.h" +#include "ScopeChain.h" #include <new> // for placement new #include <string.h> // for strlen #include <wtf/Assertions.h> @@ -89,7 +91,7 @@ bool Identifier::equal(const StringImpl* r, const UChar* s, unsigned length) struct IdentifierCStringTranslator { static unsigned hash(const char* c) { - return WTF::StringHasher::createHash<char>(c); + return StringHasher::computeHash<char>(c); } static bool equal(StringImpl* r, const char* s) @@ -149,7 +151,7 @@ struct UCharBuffer { struct IdentifierUCharBufferTranslator { static unsigned hash(const UCharBuffer& buf) { - return WTF::StringHasher::createHash<UChar>(buf.s, buf.length); + return StringHasher::computeHash<UChar>(buf.s, buf.length); } static bool equal(StringImpl* str, const UCharBuffer& buf) @@ -215,7 +217,7 @@ PassRefPtr<StringImpl> Identifier::add(JSGlobalData* globalData, const UChar* s, { if (length == 1) { UChar c = s[0]; - if (c <= 0xFF) + if (c <= maxSingleCharacterString) return add(globalData, globalData->smallStrings.singleCharacterStringRep(c)); } if (!length) @@ -242,7 +244,7 @@ PassRefPtr<StringImpl> Identifier::addSlowCase(JSGlobalData* globalData, StringI if (r->length() == 1) { UChar c = r->characters()[0]; - if (c <= 0xFF) + if (c <= maxSingleCharacterString) r = globalData->smallStrings.singleCharacterStringRep(c); if (r->isIdentifier()) return r; diff --git a/Source/JavaScriptCore/runtime/InternalFunction.cpp b/Source/JavaScriptCore/runtime/InternalFunction.cpp index f19ae0d..c3b07f8 100644 --- a/Source/JavaScriptCore/runtime/InternalFunction.cpp +++ b/Source/JavaScriptCore/runtime/InternalFunction.cpp @@ -29,34 +29,33 @@ 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> structure) - : JSObjectWithGlobalObject(structure) +InternalFunction::InternalFunction(VPtrStealingHackType) + : JSObjectWithGlobalObject(VPtrStealingHack) { } -InternalFunction::InternalFunction(JSGlobalData* globalData, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, const Identifier& name) +InternalFunction::InternalFunction(JSGlobalData* globalData, JSGlobalObject* globalObject, Structure* 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); } const UString& InternalFunction::name(ExecState* exec) { - return asString(getDirect(exec->globalData().propertyNames->name))->tryGetValue(); + return asString(getDirect(exec->globalData(), exec->globalData().propertyNames->name))->tryGetValue(); } const UString InternalFunction::displayName(ExecState* exec) { - JSValue displayName = getDirect(exec->globalData().propertyNames->displayName); + JSValue displayName = getDirect(exec->globalData(), exec->globalData().propertyNames->displayName); if (displayName && isJSString(&exec->globalData(), displayName)) return asString(displayName)->tryGetValue(); diff --git a/Source/JavaScriptCore/runtime/InternalFunction.h b/Source/JavaScriptCore/runtime/InternalFunction.h index 401f17b..28e260e 100644 --- a/Source/JavaScriptCore/runtime/InternalFunction.h +++ b/Source/JavaScriptCore/runtime/InternalFunction.h @@ -33,35 +33,36 @@ 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*); const UString calculatedDisplayName(ExecState*); - static PassRefPtr<Structure> createStructure(JSValue proto) + static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { - return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: static const unsigned StructureFlags = ImplementsHasInstance | JSObject::StructureFlags; // Only used to allow us to determine the JSFunction vptr - InternalFunction(NonNullPassRefPtr<Structure> structure); + InternalFunction(VPtrStealingHackType); - InternalFunction(JSGlobalData*, JSGlobalObject*, NonNullPassRefPtr<Structure>, const Identifier&); + InternalFunction(JSGlobalData*, JSGlobalObject*, Structure*, const Identifier&); 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<InternalFunction*>(asObject(value)); } diff --git a/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h b/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h index a113e91..0165488 100644 --- a/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h +++ b/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h @@ -25,6 +25,7 @@ #include "JSCell.h" #include "CallFrame.h" +#include "Structure.h" namespace JSC { @@ -35,15 +36,15 @@ namespace JSC { virtual bool isAPIValueWrapper() const { return true; } - static PassRefPtr<Structure> createStructure(JSValue prototype) + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { - return Structure::create(prototype, TypeInfo(CompoundType, OverridesMarkChildren | OverridesGetPropertyNames), AnonymousSlotCount); + return Structure::create(globalData, prototype, TypeInfo(CompoundType, OverridesMarkChildren | OverridesGetPropertyNames), AnonymousSlotCount, 0); } private: JSAPIValueWrapper(ExecState* exec, JSValue value) - : JSCell(exec->globalData().apiWrapperStructure.get()) + : JSCell(exec->globalData(), exec->globalData().apiWrapperStructure.get()) { m_value.set(exec->globalData(), this, value); ASSERT(!value.isCell()); diff --git a/Source/JavaScriptCore/runtime/JSActivation.cpp b/Source/JavaScriptCore/runtime/JSActivation.cpp index 6fb5ced..4e36641 100644 --- a/Source/JavaScriptCore/runtime/JSActivation.cpp +++ b/Source/JavaScriptCore/runtime/JSActivation.cpp @@ -37,16 +37,25 @@ 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> functionExecutable) - : Base(callFrame->globalData().activationStructure, new JSActivationData(functionExecutable, callFrame->registers())) +JSActivation::JSActivation(CallFrame* callFrame, FunctionExecutable* functionExecutable) + : Base(callFrame->globalData(), callFrame->globalData().activationStructure.get(), functionExecutable->symbolTable(), callFrame->registers()) + , m_numParametersMinusThis(static_cast<int>(functionExecutable->parameterCount())) + , m_numCapturedVars(functionExecutable->capturedVariableCount()) + , m_requiresDynamicChecks(functionExecutable->usesEval()) + , m_argumentsRegister(functionExecutable->generatedBytecode().argumentsRegister()) { + ASSERT(inherits(&s_info)); + + // We have to manually ref and deref the symbol table as JSVariableObject + // doesn't know about SharedSymbolTable + static_cast<SharedSymbolTable*>(m_symbolTable)->ref(); } JSActivation::~JSActivation() { - delete d(); + static_cast<SharedSymbolTable*>(m_symbolTable)->deref(); } void JSActivation::markChildren(MarkStack& markStack) @@ -54,33 +63,29 @@ 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<Unknown>* registerArray = m_registerArray.get(); if (!registerArray) return; - size_t numParametersMinusThis = d()->functionExecutable->parameterCount(); - - size_t count = numParametersMinusThis; - markStack.deprecatedAppendValues(registerArray, count); - - size_t numVars = d()->functionExecutable->capturedVariableCount(); + markStack.appendValues(registerArray, m_numParametersMinusThis); // Skip the call frame, which sits between the parameters and vars. - markStack.deprecatedAppendValues(registerArray + count + RegisterFile::CallFrameHeaderSize, numVars, MayContainNullValues); + markStack.appendValues(registerArray + m_numParametersMinusThis + RegisterFile::CallFrameHeaderSize, m_numCapturedVars, MayContainNullValues); } inline bool JSActivation::symbolTableGet(const Identifier& propertyName, PropertySlot& slot) { SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl()); - if (!entry.isNull()) { - ASSERT(entry.getIndex() < static_cast<int>(d()->functionExecutable->capturedVariableCount())); - slot.setRegisterSlot(®isterAt(entry.getIndex())); - return true; - } - return false; + if (entry.isNull()) + return false; + if (entry.getIndex() >= m_numCapturedVars) + return false; + + slot.setValue(registerAt(entry.getIndex()).get()); + return true; } -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)); @@ -89,8 +94,10 @@ inline bool JSActivation::symbolTablePut(const Identifier& propertyName, JSValue return false; if (entry.isReadOnly()) return true; - ASSERT(entry.getIndex() < static_cast<int>(d()->functionExecutable->capturedVariableCount())); - registerAt(entry.getIndex()) = value; + if (entry.getIndex() >= m_numCapturedVars) + return false; + + registerAt(entry.getIndex()).set(globalData, this, value); return true; } @@ -98,15 +105,17 @@ void JSActivation::getOwnPropertyNames(ExecState* exec, PropertyNameArray& prope { SymbolTable::const_iterator end = symbolTable().end(); for (SymbolTable::const_iterator it = symbolTable().begin(); it != end; ++it) { - ASSERT(it->second.getIndex() < static_cast<int>(d()->functionExecutable->capturedVariableCount())); - if (!(it->second.getAttributes() & DontEnum) || (mode == IncludeDontEnumProperties)) - propertyNames.add(Identifier(exec, it->first.get())); + if (it->second.getAttributes() & DontEnum && mode != IncludeDontEnumProperties) + continue; + if (it->second.getIndex() >= m_numCapturedVars) + continue; + propertyNames.add(Identifier(exec, it->first.get())); } // Skip the JSVariableObject implementation of getOwnPropertyNames 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)); @@ -115,10 +124,11 @@ inline bool JSActivation::symbolTablePutWithAttributes(const Identifier& propert return false; SymbolTableEntry& entry = iter->second; ASSERT(!entry.isNull()); - if (entry.getIndex() >= static_cast<int>(d()->functionExecutable->capturedVariableCount())) + if (entry.getIndex() >= m_numCapturedVars) return false; + entry.setAttributes(attributes); - registerAt(entry.getIndex()) = value; + registerAt(entry.getIndex()).set(globalData, this, value); return true; } @@ -132,7 +142,7 @@ bool JSActivation::getOwnPropertySlot(ExecState* exec, const Identifier& propert if (symbolTableGet(propertyName, slot)) return true; - if (WriteBarrierBase<Unknown>* location = getDirectLocation(propertyName)) { + if (WriteBarrierBase<Unknown>* location = getDirectLocation(exec->globalData(), propertyName)) { slot.setValue(location->get()); return true; } @@ -148,7 +158,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 +173,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 @@ -194,15 +204,15 @@ JSValue JSActivation::toStrictThisObject(ExecState*) const bool JSActivation::isDynamicScope(bool& requiresDynamicChecks) const { - requiresDynamicChecks = d()->functionExecutable->usesEval(); + requiresDynamicChecks = m_requiresDynamicChecks; return false; } JSValue JSActivation::argumentsGetter(ExecState*, JSValue slotBase, const Identifier&) { JSActivation* activation = asActivation(slotBase); - CallFrame* callFrame = CallFrame::create(activation->d()->registers); - int argumentsRegister = activation->d()->functionExecutable->generatedBytecode().argumentsRegister(); + CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(activation->m_registers)); + int argumentsRegister = activation->m_argumentsRegister; if (JSValue arguments = callFrame->uncheckedR(argumentsRegister).jsValue()) return arguments; int realArgumentsRegister = unmodifiedArgumentsRegister(argumentsRegister); @@ -211,7 +221,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..65642f1 100644 --- a/Source/JavaScriptCore/runtime/JSActivation.h +++ b/Source/JavaScriptCore/runtime/JSActivation.h @@ -42,7 +42,7 @@ namespace JSC { class JSActivation : public JSVariableObject { typedef JSVariableObject Base; public: - JSActivation(CallFrame*, NonNullPassRefPtr<FunctionExecutable>); + JSActivation(CallFrame*, FunctionExecutable*); virtual ~JSActivation(); virtual void markChildren(MarkStack&); @@ -62,53 +62,43 @@ 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<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); } + static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: static const unsigned StructureFlags = OverridesGetOwnPropertySlot | NeedsThisConversion | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags; private: - struct JSActivationData : public JSVariableObjectData { - JSActivationData(NonNullPassRefPtr<FunctionExecutable> _functionExecutable, Register* registers) - : JSVariableObjectData(_functionExecutable->symbolTable(), registers) - , functionExecutable(_functionExecutable) - { - // We have to manually ref and deref the symbol table as JSVariableObjectData - // doesn't know about SharedSymbolTable - functionExecutable->symbolTable()->ref(); - } - ~JSActivationData() - { - static_cast<SharedSymbolTable*>(symbolTable)->deref(); - } - - RefPtr<FunctionExecutable> functionExecutable; - }; - 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(); - JSActivationData* d() const { return static_cast<JSActivationData*>(JSVariableObject::d); } + int m_numParametersMinusThis; + int m_numCapturedVars : 31; + bool m_requiresDynamicChecks : 1; + int m_argumentsRegister; }; JSActivation* asActivation(JSValue); inline JSActivation* asActivation(JSValue value) { - ASSERT(asObject(value)->inherits(&JSActivation::info)); + ASSERT(asObject(value)->inherits(&JSActivation::s_info)); return static_cast<JSActivation*>(asObject(value)); } + + ALWAYS_INLINE JSActivation* Register::activation() const + { + return asActivation(jsValue()); + } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp index ded6d87..bf61097 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,25 +127,15 @@ inline void JSArray::checkConsistency(ConsistencyCheckType) #endif JSArray::JSArray(VPtrStealingHackType) - : JSObject(createStructure(jsNull())) + : JSNonFinalObject(VPtrStealingHack) { - unsigned initialCapacity = 0; - - m_storage = static_cast<ArrayStorage*>(fastZeroedMalloc(storageSize(initialCapacity))); - m_storage->m_allocBase = m_storage; - m_indexBias = 0; - m_vectorLength = initialCapacity; - - checkConsistency(); - - // It's not safe to call Heap::heap(this) in order to report extra memory - // cost here, because the VPtrStealingHackType JSArray is not allocated on - // the heap. For the same reason, it's OK not to report extra cost. } -JSArray::JSArray(NonNullPassRefPtr<Structure> structure) - : JSObject(structure) +JSArray::JSArray(JSGlobalData& globalData, Structure* structure) + : JSNonFinalObject(globalData, structure) { + ASSERT(inherits(&s_info)); + unsigned initialCapacity = 0; m_storage = static_cast<ArrayStorage*>(fastZeroedMalloc(storageSize(initialCapacity))); @@ -158,9 +148,11 @@ JSArray::JSArray(NonNullPassRefPtr<Structure> structure) Heap::heap(this)->reportExtraMemoryCost(storageSize(0)); } -JSArray::JSArray(NonNullPassRefPtr<Structure> structure, unsigned initialLength, ArrayCreationMode creationMode) - : JSObject(structure) +JSArray::JSArray(JSGlobalData& globalData, Structure* structure, unsigned initialLength, ArrayCreationMode creationMode) + : JSNonFinalObject(globalData, structure) { + ASSERT(inherits(&s_info)); + unsigned initialCapacity; if (creationMode == CreateCompact) initialCapacity = initialLength; @@ -198,9 +190,11 @@ JSArray::JSArray(NonNullPassRefPtr<Structure> structure, unsigned initialLength, Heap::heap(this)->reportExtraMemoryCost(storageSize(initialCapacity)); } -JSArray::JSArray(JSGlobalData& globalData, NonNullPassRefPtr<Structure> structure, const ArgList& list) - : JSObject(structure) +JSArray::JSArray(JSGlobalData& globalData, Structure* structure, const ArgList& list) + : JSNonFinalObject(globalData, 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..8be8513 100644 --- a/Source/JavaScriptCore/runtime/JSArray.h +++ b/Source/JavaScriptCore/runtime/JSArray.h @@ -57,17 +57,15 @@ namespace JSC { enum ArrayCreationMode { CreateCompact, CreateInitialized }; - class JSArray : public JSObject { - friend class JIT; + class JSArray : public JSNonFinalObject { friend class Walker; public: - enum VPtrStealingHackType { VPtrStealingHack }; JSArray(VPtrStealingHackType); - explicit JSArray(NonNullPassRefPtr<Structure>); - JSArray(NonNullPassRefPtr<Structure>, unsigned initialLength, ArrayCreationMode); - JSArray(JSGlobalData&, NonNullPassRefPtr<Structure>, const ArgList& initialValues); + explicit JSArray(JSGlobalData&, Structure*); + JSArray(JSGlobalData&, Structure*, unsigned initialLength, ArrayCreationMode); + JSArray(JSGlobalData&, Structure*, const ArgList& initialValues); virtual ~JSArray(); virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); @@ -75,7 +73,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. @@ -125,13 +123,23 @@ namespace JSC { void fillArgList(ExecState*, MarkedArgumentBuffer&); void copyToRegisters(ExecState*, Register*, uint32_t); - static PassRefPtr<Structure> createStructure(JSValue prototype) + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } inline void markChildrenDirect(MarkStack& markStack); + static ptrdiff_t storageOffset() + { + return OBJECT_OFFSETOF(JSArray, m_storage); + } + + static ptrdiff_t vectorLengthOffset() + { + return OBJECT_OFFSETOF(JSArray, m_vectorLength); + } + protected: static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSObject::StructureFlags; virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); @@ -142,10 +150,8 @@ namespace JSC { void* subclassData() const; void setSubclassData(void*); - - private: - virtual const ClassInfo* classInfo() const { return &info; } + private: bool getOwnPropertySlotSlowCase(ExecState*, unsigned propertyName, PropertySlot&); void putSlowCase(ExecState*, unsigned propertyName, JSValue); @@ -167,7 +173,7 @@ namespace JSC { inline JSArray* asArray(JSCell* cell) { - ASSERT(cell->inherits(&JSArray::info)); + ASSERT(cell->inherits(&JSArray::s_info)); return static_cast<JSArray*>(cell); } @@ -176,11 +182,8 @@ namespace JSC { return asArray(value.asCell()); } - inline bool isJSArray(JSGlobalData* globalData, JSValue v) - { - return v.isCell() && v.asCell()->vptr() == globalData->jsArrayVPtr; - } inline bool isJSArray(JSGlobalData* globalData, JSCell* cell) { return cell->vptr() == globalData->jsArrayVPtr; } + inline bool isJSArray(JSGlobalData* globalData, JSValue v) { return v.isCell() && isJSArray(globalData, v.asCell()); } inline void JSArray::markChildrenDirect(MarkStack& markStack) { @@ -198,77 +201,6 @@ namespace JSC { } } - inline void MarkStack::markChildren(JSCell* cell) - { - ASSERT(Heap::isMarked(cell)); - if (!cell->structure()->typeInfo().overridesMarkChildren()) { -#ifdef NDEBUG - asObject(cell)->markChildrenDirect(*this); -#else - ASSERT(!m_isCheckingForDefaultMarkViolation); - m_isCheckingForDefaultMarkViolation = true; - cell->markChildren(*this); - ASSERT(m_isCheckingForDefaultMarkViolation); - m_isCheckingForDefaultMarkViolation = false; -#endif - return; - } - if (cell->vptr() == m_jsArrayVPtr) { - asArray(cell)->markChildrenDirect(*this); - return; - } - cell->markChildren(*this); - } - - inline void MarkStack::drain() - { -#if !ASSERT_DISABLED - ASSERT(!m_isDraining); - m_isDraining = true; -#endif - while (!m_markSets.isEmpty() || !m_values.isEmpty()) { - while (!m_markSets.isEmpty() && m_values.size() < 50) { - ASSERT(!m_markSets.isEmpty()); - MarkSet& current = m_markSets.last(); - ASSERT(current.m_values); - JSValue* end = current.m_end; - ASSERT(current.m_values); - ASSERT(current.m_values != end); - findNextUnmarkedNullValue: - ASSERT(current.m_values != end); - JSValue value = *current.m_values; - current.m_values++; - - JSCell* cell; - if (!value || !value.isCell() || Heap::testAndSetMarked(cell = value.asCell())) { - if (current.m_values == end) { - m_markSets.removeLast(); - continue; - } - goto findNextUnmarkedNullValue; - } - - if (cell->structure()->typeInfo().type() < CompoundType) { - if (current.m_values == end) { - m_markSets.removeLast(); - continue; - } - goto findNextUnmarkedNullValue; - } - - if (current.m_values == end) - m_markSets.removeLast(); - - markChildren(cell); - } - while (!m_values.isEmpty()) - markChildren(m_values.removeLast()); - } -#if !ASSERT_DISABLED - m_isDraining = false; -#endif - } - // Rule from ECMA 15.2 about what an array index is. // Must exactly match string form of an unsigned integer, and be less than 2^32 - 1. inline unsigned Identifier::toArrayIndex(bool& ok) const diff --git a/Source/JavaScriptCore/runtime/JSByteArray.cpp b/Source/JavaScriptCore/runtime/JSByteArray.cpp index 3f7d806..c2abaee 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> structure, ByteArray* storage, const JSC::ClassInfo* classInfo) - : JSObject(structure) +JSByteArray::JSByteArray(ExecState* exec, Structure* structure, ByteArray* storage) + : JSNonFinalObject(exec->globalData(), 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<Structure> JSByteArray::createStructure(JSValue prototype) +Structure* JSByteArray::createStructure(JSGlobalData& globalData, JSValue prototype, const JSC::ClassInfo* classInfo) { - PassRefPtr<Structure> result = Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); - return result; + return Structure::create(globalData, 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..c481bb4 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<unsigned char>(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<unsigned char>(static_cast<long long>(value)); + if (!(value > 0)) // Clamp NaN to 0 + value = 0; + else if (value > 255) + value = 255; + m_storage->data()[i] = static_cast<unsigned char>(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<Structure>, WTF::ByteArray* storage, const JSC::ClassInfo* = &s_defaultInfo); - static PassRefPtr<Structure> createStructure(JSValue prototype); + JSByteArray(ExecState*, Structure*, WTF::ByteArray* storage); + static Structure* createStructure(JSGlobalData&, 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(); } @@ -92,17 +100,14 @@ namespace JSC { static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSObject::StructureFlags; private: - enum VPtrStealingHackType { VPtrStealingHack }; JSByteArray(VPtrStealingHackType) - : JSObject(createStructure(jsNull())) - , m_classInfo(0) + : JSNonFinalObject(VPtrStealingHack) { } RefPtr<WTF::ByteArray> 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..afd8450 100644 --- a/Source/JavaScriptCore/runtime/JSCell.cpp +++ b/Source/JavaScriptCore/runtime/JSCell.cpp @@ -119,7 +119,7 @@ bool JSCell::getOwnPropertySlot(ExecState* exec, const Identifier& identifier, P // This is not a general purpose implementation of getOwnPropertySlot. // It should only be called by JSValue::get. // It calls getPropertySlot, not getOwnPropertySlot. - JSObject* object = toObject(exec); + JSObject* object = toObject(exec, exec->lexicalGlobalObject()); slot.setBase(object); if (!object->getPropertySlot(exec, identifier, slot)) slot.setUndefined(); @@ -131,7 +131,7 @@ bool JSCell::getOwnPropertySlot(ExecState* exec, unsigned identifier, PropertySl // This is not a general purpose implementation of getOwnPropertySlot. // It should only be called by JSValue::get. // It calls getPropertySlot, not getOwnPropertySlot. - JSObject* object = toObject(exec); + JSObject* object = toObject(exec, exec->lexicalGlobalObject()); slot.setBase(object); if (!object->getPropertySlot(exec, identifier, slot)) slot.setUndefined(); @@ -140,32 +140,27 @@ bool JSCell::getOwnPropertySlot(ExecState* exec, unsigned identifier, PropertySl void JSCell::put(ExecState* exec, const Identifier& identifier, JSValue value, PutPropertySlot& slot) { - toObject(exec)->put(exec, identifier, value, slot); + toObject(exec, exec->lexicalGlobalObject())->put(exec, identifier, value, slot); } void JSCell::put(ExecState* exec, unsigned identifier, JSValue value) { - toObject(exec)->put(exec, identifier, value); + toObject(exec, exec->lexicalGlobalObject())->put(exec, identifier, value); } bool JSCell::deleteProperty(ExecState* exec, const Identifier& identifier) { - return toObject(exec)->deleteProperty(exec, identifier); + return toObject(exec, exec->lexicalGlobalObject())->deleteProperty(exec, identifier); } bool JSCell::deleteProperty(ExecState* exec, unsigned identifier) { - return toObject(exec)->deleteProperty(exec, identifier); + return toObject(exec, exec->lexicalGlobalObject())->deleteProperty(exec, identifier); } JSObject* JSCell::toThisObject(ExecState* exec) const { - return toObject(exec); -} - -const ClassInfo* JSCell::classInfo() const -{ - return 0; + return toObject(exec, exec->lexicalGlobalObject()); } JSValue JSCell::getJSNumber() @@ -208,10 +203,20 @@ UString JSCell::toString(ExecState*) const return UString(); } -JSObject* JSCell::toObject(ExecState*) const +JSObject* JSCell::toObject(ExecState*, JSGlobalObject*) const { ASSERT_NOT_REACHED(); return 0; } +bool isZombie(const JSCell* cell) +{ +#if ENABLE(JSC_ZOMBIES) + return cell && cell->isZombie(); +#else + UNUSED_PARAM(cell); + return false; +#endif +} + } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h index 66f6197..7ee871c 100644 --- a/Source/JavaScriptCore/runtime/JSCell.h +++ b/Source/JavaScriptCore/runtime/JSCell.h @@ -24,16 +24,19 @@ #define JSCell_h #include "CallData.h" +#include "CallFrame.h" #include "ConstructData.h" #include "Heap.h" -#include "JSImmediate.h" -#include "JSValue.h" +#include "JSLock.h" +#include "JSValueInlineMethods.h" #include "MarkStack.h" -#include "Structure.h" #include <wtf/Noncopyable.h> namespace JSC { + class JSGlobalObject; + class Structure; + #if COMPILER(MSVC) // If WTF_MAKE_NONCOPYABLE is applied to JSCell we end up with a bunch of // undefined references to the JSCell copy constructor and assignment operator @@ -52,10 +55,9 @@ namespace JSC { WTF_MAKE_NONCOPYABLE(JSCell); #endif + friend class ExecutableBase; friend class GetterSetter; friend class Heap; - friend class JIT; - friend class JSNumberCell; friend class JSObject; friend class JSPropertyNameIterator; friend class JSString; @@ -65,16 +67,20 @@ namespace JSC { friend class JSGlobalData; friend class MarkedSpace; friend class MarkedBlock; + friend class ScopeChainNode; + friend class Structure; + friend class StructureChain; + + protected: + enum VPtrStealingHackType { VPtrStealingHack }; private: - explicit JSCell(Structure*); + explicit JSCell(VPtrStealingHackType) { } + JSCell(JSGlobalData&, Structure*); virtual ~JSCell(); public: - static PassRefPtr<Structure> createDummyStructure() - { - return Structure::create(jsNull(), TypeInfo(UnspecifiedType), AnonymousSlotCount); - } + static Structure* createDummyStructure(JSGlobalData&); // Querying the type. bool isString() const; @@ -105,7 +111,7 @@ namespace JSC { virtual bool toBoolean(ExecState*) const; virtual double toNumber(ExecState*) const; virtual UString toString(ExecState*) const; - virtual JSObject* toObject(ExecState*) const; + virtual JSObject* toObject(ExecState*, JSGlobalObject*) const; // Garbage collection. void* operator new(size_t, ExecState*); @@ -118,7 +124,7 @@ namespace JSC { #endif // Object operations, with the toObject operation included. - virtual const ClassInfo* classInfo() const; + const ClassInfo* classInfo() const; virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); virtual void put(ExecState*, unsigned propertyName, JSValue); virtual bool deleteProperty(ExecState*, const Identifier& propertyName); @@ -135,6 +141,16 @@ namespace JSC { // property names, we want a similar interface with appropriate optimizations.) bool fastGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); + static ptrdiff_t structureOffset() + { + return OBJECT_OFFSETOF(JSCell, m_structure); + } + + const void* addressOfStructure() const + { + return &m_structure; + } + protected: static const unsigned AnonymousSlotCount = 0; @@ -143,45 +159,28 @@ namespace JSC { virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); - Structure* m_structure; + WriteBarrier<Structure> m_structure; }; - inline JSCell::JSCell(Structure* structure) - : m_structure(structure) + inline JSCell::JSCell(JSGlobalData& globalData, Structure* structure) + : m_structure(globalData, this, structure) { + // Very first set of allocations won't have a real structure. + ASSERT(m_structure || !globalData.dummyMarkableCellStructure); } inline JSCell::~JSCell() { } - inline bool JSCell::isObject() const - { - return m_structure->typeInfo().type() == ObjectType; - } - - inline bool JSCell::isString() const - { - return m_structure->typeInfo().type() == StringType; - } - inline Structure* JSCell::structure() const { - return m_structure; - } - - inline void JSCell::markChildren(MarkStack&) - { - } - - inline void* JSCell::operator new(size_t size, JSGlobalData* globalData) - { - return globalData->heap.allocate(size); + return m_structure.get(); } - inline void* JSCell::operator new(size_t size, ExecState* exec) + inline void JSCell::markChildren(MarkStack& markStack) { - return exec->heap()->allocate(size); + markStack.append(&m_structure); } // --- JSValue inlines ---------------------------- @@ -211,6 +210,11 @@ namespace JSC { return isCell() ? asCell()->getString(exec) : UString(); } + template <typename Base> UString HandleConverter<Base, Unknown>::getString(ExecState* exec) const + { + return jsValue().getString(exec); + } + inline JSObject* JSValue::getObject() const { return isCell() ? asCell()->getObject() : 0; @@ -245,14 +249,6 @@ namespace JSC { return false; } -#if USE(JSVALUE64) - ALWAYS_INLINE JSCell* JSValue::asCell() const - { - ASSERT(isCell()); - return m_ptr; - } -#endif // USE(JSVALUE64) - inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const { return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue(); @@ -312,13 +308,6 @@ namespace JSC { return isUndefined() ? nonInlineNaN() : 0; // null and false both convert to 0. } - inline bool JSValue::needsThisConversion() const - { - if (UNLIKELY(!isCell())) - return true; - return asCell()->structure()->typeInfo().needsThisConversion(); - } - inline JSValue JSValue::getJSNumber() { if (isInt32() || isDouble()) @@ -330,57 +319,17 @@ namespace JSC { inline JSObject* JSValue::toObject(ExecState* exec) const { - return isCell() ? asCell()->toObject(exec) : toObjectSlowCase(exec); + return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject()); } - inline JSObject* JSValue::toThisObject(ExecState* exec) const - { - return isCell() ? asCell()->toThisObject(exec) : toThisObjectSlowCase(exec); - } - - template <typename T> void MarkStack::append(DeprecatedPtr<T>* slot) + inline JSObject* JSValue::toObject(ExecState* exec, JSGlobalObject* globalObject) const { - internalAppend(slot->get()); - } - - template <typename T> void MarkStack::append(WriteBarrierBase<T>* slot) - { - internalAppend(slot->get()); - } - - ALWAYS_INLINE void MarkStack::internalAppend(JSCell* cell) - { - ASSERT(!m_isCheckingForDefaultMarkViolation); - ASSERT(cell); - if (Heap::testAndSetMarked(cell)) - return; - if (cell->structure()->typeInfo().type() >= CompoundType) - m_values.append(cell); + return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject); } - ALWAYS_INLINE void MarkStack::deprecatedAppend(JSCell** value) - { - ASSERT(value); - internalAppend(*value); - } - - ALWAYS_INLINE void MarkStack::deprecatedAppend(JSValue* value) - { - ASSERT(value); - internalAppend(*value); - } - - ALWAYS_INLINE void MarkStack::deprecatedAppend(Register* value) - { - ASSERT(value); - internalAppend(value->jsValue()); - } - - ALWAYS_INLINE void MarkStack::internalAppend(JSValue value) + inline JSObject* JSValue::toThisObject(ExecState* exec) const { - ASSERT(value); - if (value.isCell()) - internalAppend(value.asCell()); + return isCell() ? asCell()->toThisObject(exec) : toThisObjectSlowCase(exec); } inline Heap* Heap::heap(JSValue v) @@ -398,25 +347,65 @@ namespace JSC { #if ENABLE(JSC_ZOMBIES) inline bool JSValue::isZombie() const { - return isCell() && asCell() && asCell()->isZombie(); + return isCell() && asCell() > (JSCell*)0x1ffffffffL && asCell()->isZombie(); } #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<JSCell*>(&cells[nextCell++]); + while (m_nextAtom < m_endAtom) { + if (!m_marks.testAndSet(m_nextAtom)) { + JSCell* cell = reinterpret_cast<JSCell*>(&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 < maxCellSize); + if (bytes < preciseCutoff) + return m_preciseSizeClasses[(bytes - 1) / preciseStep]; + return m_impreciseSizeClasses[(bytes - 1) / impreciseStep]; + } + + 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/ConservativeSet.cpp b/Source/JavaScriptCore/runtime/JSChunk.cpp index bc8bd6d..f064de8 100644 --- a/Source/JavaScriptCore/runtime/ConservativeSet.cpp +++ b/Source/JavaScriptCore/runtime/JSChunk.cpp @@ -24,42 +24,5 @@ */ #include "config.h" -#include "ConservativeSet.h" +#include "JSChunk.h" -namespace JSC { - -inline bool isPointerAligned(void* p) -{ - return !((intptr_t)(p) & (sizeof(char*) - 1)); -} - -void ConservativeSet::grow() -{ - size_t newCapacity = m_capacity == inlineCapacity ? nonInlineCapacity : m_capacity * 2; - DeprecatedPtr<JSCell>* newSet = static_cast<DeprecatedPtr<JSCell>*>(OSAllocator::reserveAndCommit(newCapacity * sizeof(JSCell*))); - memcpy(newSet, m_set, m_size * sizeof(JSCell*)); - if (m_set != m_inlineSet) - OSAllocator::decommitAndRelease(m_set, m_capacity * sizeof(JSCell*)); - m_capacity = newCapacity; - m_set = newSet; -} - -void ConservativeSet::add(void* begin, void* end) -{ - ASSERT(begin <= end); - ASSERT((static_cast<char*>(end) - static_cast<char*>(begin)) < 0x1000000); - ASSERT(isPointerAligned(begin)); - ASSERT(isPointerAligned(end)); - - for (char** it = static_cast<char**>(begin); it != static_cast<char**>(end); ++it) { - if (!m_heap->contains(*it)) - continue; - - if (m_size == m_capacity) - grow(); - - m_set[m_size++] = reinterpret_cast<JSCell*>(*it); - } -} - -} // namespace JSC 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..a18e973 100644 --- a/Source/JavaScriptCore/runtime/JSFunction.cpp +++ b/Source/JavaScriptCore/runtime/JSFunction.cpp @@ -42,62 +42,54 @@ 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 { return isHostFunction(); } -JSFunction::JSFunction(NonNullPassRefPtr<Structure> structure) - : Base(structure) - , m_executable(adoptRef(new VPtrHackExecutable())) - , m_scopeChain(NoScopeChain()) +JSFunction::JSFunction(VPtrStealingHackType) + : Base(VPtrStealingHack) { } -#if ENABLE(JIT) -JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, int length, const Identifier& name, PassRefPtr<NativeExecutable> thunk) +JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, int length, const Identifier& name, NativeExecutable* thunk) : Base(globalObject, structure) - , m_executable(thunk) - , m_scopeChain(globalObject->globalScopeChain()) + , m_executable(exec->globalData(), this, thunk) + , 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> structure, int length, const Identifier& name, NativeFunction func) +JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* 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)); + // We separate out intialisation from setting the executable + // as getHostFunction may perform a GC allocation, so we have to be able to + // mark ourselves safely + m_executable.set(exec->globalData(), this, exec->globalData().getHostFunction(func)); 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<FunctionExecutable> executable, ScopeChainNode* scopeChainNode) - : Base(scopeChainNode->globalObject, scopeChainNode->globalObject->functionStructure()) - , m_executable(executable) - , m_scopeChain(scopeChainNode) +JSFunction::JSFunction(ExecState* exec, FunctionExecutable* executable, ScopeChainNode* scopeChainNode) + : Base(scopeChainNode->globalObject.get(), scopeChainNode->globalObject->functionStructure()) + , m_executable(exec->globalData(), this, executable) + , m_scopeChain(exec->globalData(), this, scopeChainNode) { + ASSERT(inherits(&s_info)); const Identifier& name = static_cast<FunctionExecutable*>(m_executable.get())->name(); putDirect(exec->globalData(), exec->globalData().propertyNames->name, jsString(exec, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum); } @@ -105,19 +97,6 @@ JSFunction::JSFunction(ExecState* exec, NonNullPassRefPtr<FunctionExecutable> ex JSFunction::~JSFunction() { ASSERT(vptr() == JSGlobalData::jsFunctionVPtr); - - // JIT code for other functions may have had calls linked directly to the code for this function; these links - // are based on a check for the this pointer value for this JSFunction - which will no longer be valid once - // this memory is freed and may be reused (potentially for another, different JSFunction). - if (!isHostFunction()) { -#if ENABLE(JIT_OPTIMIZE_CALL) - ASSERT(m_executable); - if (jsExecutable()->isGeneratedForCall()) - jsExecutable()->generatedBytecodeForCall().unlinkCallers(); - if (jsExecutable()->isGeneratedForConstruct()) - jsExecutable()->generatedBytecodeForConstruct().unlinkCallers(); -#endif - } } static const char* StrictModeCallerAccessError = "Cannot access caller property of a strict mode function"; @@ -131,12 +110,12 @@ static void createDescriptorForThrowingProperty(ExecState* exec, PropertyDescrip const UString& JSFunction::name(ExecState* exec) { - return asString(getDirect(exec->globalData().propertyNames->name))->tryGetValue(); + return asString(getDirect(exec->globalData(), exec->globalData().propertyNames->name))->tryGetValue(); } const UString JSFunction::displayName(ExecState* exec) { - JSValue displayName = getDirect(exec->globalData().propertyNames->displayName); + JSValue displayName = getDirect(exec->globalData(), exec->globalData().propertyNames->displayName); if (displayName && isJSString(&exec->globalData(), displayName)) return asString(displayName)->tryGetValue(); @@ -157,22 +136,24 @@ const UString JSFunction::calculatedDisplayName(ExecState* exec) void JSFunction::markChildren(MarkStack& markStack) { Base::markChildren(markStack); - if (!isHostFunction()) { - jsExecutable()->markAggregate(markStack); - scope().markAggregate(markStack); + + markStack.append(&m_scopeChain); + if (m_executable) { + // Delightful race condition: m_executable may not have been initialised + // if this is a host function, as the executable isn't necessarily created + // until after the function has been allocated. + markStack.append(&m_executable); } } 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; } @@ -203,13 +184,13 @@ bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyN return Base::getOwnPropertySlot(exec, propertyName, slot); if (propertyName == exec->propertyNames().prototype) { - WriteBarrierBase<Unknown>* location = getDirectLocation(propertyName); + WriteBarrierBase<Unknown>* location = getDirectLocation(exec->globalData(), 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); + location = getDirectLocation(exec->globalData(), propertyName); } slot.setValue(this, location->get(), offsetForLocation(location)); @@ -336,7 +317,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..174cd38 100644 --- a/Source/JavaScriptCore/runtime/JSFunction.h +++ b/Source/JavaScriptCore/runtime/JSFunction.h @@ -34,6 +34,7 @@ namespace JSC { class JSActivation; class JSGlobalObject; class NativeExecutable; + class VPtrHackExecutable; EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState*); @@ -44,26 +45,24 @@ namespace JSC { typedef JSObjectWithGlobalObject Base; public: - JSFunction(ExecState*, JSGlobalObject*, NonNullPassRefPtr<Structure>, int length, const Identifier&, NativeFunction); -#if ENABLE(JIT) - JSFunction(ExecState*, JSGlobalObject*, NonNullPassRefPtr<Structure>, int length, const Identifier&, PassRefPtr<NativeExecutable>); -#endif - JSFunction(ExecState*, NonNullPassRefPtr<FunctionExecutable>, ScopeChainNode*); + JSFunction(ExecState*, JSGlobalObject*, Structure*, int length, const Identifier&, NativeFunction); + JSFunction(ExecState*, JSGlobalObject*, Structure*, int length, const Identifier&, NativeExecutable*); + JSFunction(ExecState*, FunctionExecutable*, ScopeChainNode*); virtual ~JSFunction(); const UString& name(ExecState*); 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 +71,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<Structure> createStructure(JSValue prototype) + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } NativeFunction nativeFunction(); @@ -88,7 +87,7 @@ namespace JSC { const static unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | OverridesMarkChildren | OverridesGetPropertyNames | JSObject::StructureFlags; private: - JSFunction(NonNullPassRefPtr<Structure>); + explicit JSFunction(VPtrStealingHackType); bool isHostFunctionNonInline() const; @@ -100,21 +99,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<ExecutableBase> m_executable; - ScopeChain m_scopeChain; + WriteBarrier<ExecutableBase> m_executable; + WriteBarrier<ScopeChainNode> 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<JSFunction*>(asObject(value)); } diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/Source/JavaScriptCore/runtime/JSGlobalData.cpp index ff88048..d9e5df0 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalData.cpp @@ -45,6 +45,7 @@ #include "JSNotAnObject.h" #include "JSPropertyNameIterator.h" #include "JSStaticScopeObject.h" +#include "JSZombie.h" #include "Lexer.h" #include "Lookup.h" #include "Nodes.h" @@ -68,6 +69,27 @@ using namespace WTF; +namespace { + +using namespace JSC; + +class Recompiler { +public: + void operator()(JSCell*); +}; + +inline void Recompiler::operator()(JSCell* cell) +{ + if (!cell->inherits(&JSFunction::s_info)) + return; + JSFunction* function = asFunction(cell); + if (function->executable()->isHostFunction()) + return; + function->jsExecutable()->discardCode(); +} + +} // namespace + namespace JSC { extern JSC_CONST_HASHTABLE HashTable arrayTable; @@ -75,6 +97,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; @@ -84,6 +107,15 @@ void* JSGlobalData::jsByteArrayVPtr; void* JSGlobalData::jsStringVPtr; void* JSGlobalData::jsFunctionVPtr; +#if COMPILER(GCC) +// Work around for gcc trying to coalesce our reads of the various cell vptrs +#define CLOBBER_MEMORY() do { \ + asm volatile ("" : : : "memory"); \ +} while (false) +#else +#define CLOBBER_MEMORY() do { } while (false) +#endif + void JSGlobalData::storeVPtrs() { // Enough storage to fit a JSArray, JSByteArray, JSString, or JSFunction. @@ -92,23 +124,23 @@ void JSGlobalData::storeVPtrs() COMPILE_ASSERT(sizeof(JSArray) <= sizeof(storage), sizeof_JSArray_must_be_less_than_storage); JSCell* jsArray = new (storage) JSArray(JSArray::VPtrStealingHack); + CLOBBER_MEMORY(); JSGlobalData::jsArrayVPtr = jsArray->vptr(); - jsArray->~JSCell(); COMPILE_ASSERT(sizeof(JSByteArray) <= sizeof(storage), sizeof_JSByteArray_must_be_less_than_storage); JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack); + CLOBBER_MEMORY(); JSGlobalData::jsByteArrayVPtr = jsByteArray->vptr(); - jsByteArray->~JSCell(); COMPILE_ASSERT(sizeof(JSString) <= sizeof(storage), sizeof_JSString_must_be_less_than_storage); JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack); + CLOBBER_MEMORY(); JSGlobalData::jsStringVPtr = jsString->vptr(); - jsString->~JSCell(); COMPILE_ASSERT(sizeof(JSFunction) <= sizeof(storage), sizeof_JSFunction_must_be_less_than_storage); - JSCell* jsFunction = new (storage) JSFunction(JSFunction::createStructure(jsNull())); + JSCell* jsFunction = new (storage) JSFunction(JSCell::VPtrStealingHack); + CLOBBER_MEMORY(); JSGlobalData::jsFunctionVPtr = jsFunction->vptr(); - jsFunction->~JSCell(); } JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType) @@ -119,29 +151,19 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread , jsonTable(fastNew<HashTable>(JSC::jsonTable)) , mathTable(fastNew<HashTable>(JSC::mathTable)) , numberTable(fastNew<HashTable>(JSC::numberTable)) + , objectConstructorTable(fastNew<HashTable>(JSC::objectConstructorTable)) , regExpTable(fastNew<HashTable>(JSC::regExpTable)) , regExpConstructorTable(fastNew<HashTable>(JSC::regExpConstructorTable)) , stringTable(fastNew<HashTable>(JSC::stringTable)) - , activationStructure(JSActivation::createStructure(jsNull())) - , interruptedExecutionErrorStructure(JSObject::createStructure(jsNull())) - , terminatedExecutionErrorStructure(JSObject::createStructure(jsNull())) - , staticScopeStructure(JSStaticScopeObject::createStructure(jsNull())) - , strictEvalActivationStructure(StrictEvalActivation::createStructure(jsNull())) - , stringStructure(JSString::createStructure(jsNull())) - , notAnObjectStructure(JSNotAnObject::createStructure(jsNull())) - , propertyNameIteratorStructure(JSPropertyNameIterator::createStructure(jsNull())) - , getterSetterStructure(GetterSetter::createStructure(jsNull())) - , apiWrapperStructure(JSAPIValueWrapper::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) , maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth) , m_regExpCache(new RegExpCache(this)) @@ -152,14 +174,44 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread , exclusiveThread(0) #endif { + interpreter = new Interpreter(*this); if (globalDataType == Default) m_stack = wtfThreadData().stack(); + // Need to be careful to keep everything consistent here + IdentifierTable* existingEntryIdentifierTable = wtfThreadData().setCurrentIdentifierTable(identifierTable); + JSLock lock(SilenceAssertionsOnly); + structureStructure.set(*this, Structure::createStructure(*this)); + activationStructure.set(*this, JSActivation::createStructure(*this, jsNull())); + interruptedExecutionErrorStructure.set(*this, JSNonFinalObject::createStructure(*this, jsNull())); + terminatedExecutionErrorStructure.set(*this, JSNonFinalObject::createStructure(*this, jsNull())); + staticScopeStructure.set(*this, JSStaticScopeObject::createStructure(*this, jsNull())); + strictEvalActivationStructure.set(*this, StrictEvalActivation::createStructure(*this, jsNull())); + stringStructure.set(*this, JSString::createStructure(*this, jsNull())); + notAnObjectStructure.set(*this, JSNotAnObject::createStructure(*this, jsNull())); + propertyNameIteratorStructure.set(*this, JSPropertyNameIterator::createStructure(*this, jsNull())); + getterSetterStructure.set(*this, GetterSetter::createStructure(*this, jsNull())); + apiWrapperStructure.set(*this, JSAPIValueWrapper::createStructure(*this, jsNull())); + scopeChainNodeStructure.set(*this, ScopeChainNode::createStructure(*this, jsNull())); + executableStructure.set(*this, ExecutableBase::createStructure(*this, jsNull())); + nativeExecutableStructure.set(*this, NativeExecutable::createStructure(*this, jsNull())); + evalExecutableStructure.set(*this, EvalExecutable::createStructure(*this, jsNull())); + programExecutableStructure.set(*this, ProgramExecutable::createStructure(*this, jsNull())); + functionExecutableStructure.set(*this, FunctionExecutable::createStructure(*this, jsNull())); + dummyMarkableCellStructure.set(*this, JSCell::createDummyStructure(*this)); + structureChainStructure.set(*this, StructureChain::createStructure(*this, jsNull())); + +#if ENABLE(JSC_ZOMBIES) + zombieStructure.set(*this, JSZombie::createStructure(*this, jsNull())); +#endif + + wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable); + #if PLATFORM(MAC) 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) { @@ -186,6 +238,33 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread #endif } +void JSGlobalData::clearBuiltinStructures() +{ + structureStructure.clear(); + activationStructure.clear(); + interruptedExecutionErrorStructure.clear(); + terminatedExecutionErrorStructure.clear(); + staticScopeStructure.clear(); + strictEvalActivationStructure.clear(); + stringStructure.clear(); + notAnObjectStructure.clear(); + propertyNameIteratorStructure.clear(); + getterSetterStructure.clear(); + apiWrapperStructure.clear(); + scopeChainNodeStructure.clear(); + executableStructure.clear(); + nativeExecutableStructure.clear(); + evalExecutableStructure.clear(); + programExecutableStructure.clear(); + functionExecutableStructure.clear(); + dummyMarkableCellStructure.clear(); + structureChainStructure.clear(); + +#if ENABLE(JSC_ZOMBIES) + zombieStructure.clear(); +#endif +} + JSGlobalData::~JSGlobalData() { // By the time this is destroyed, heap.destroy() must already have been called. @@ -201,6 +280,7 @@ JSGlobalData::~JSGlobalData() jsonTable->deleteTable(); mathTable->deleteTable(); numberTable->deleteTable(); + objectConstructorTable->deleteTable(); regExpTable->deleteTable(); regExpConstructorTable->deleteTable(); stringTable->deleteTable(); @@ -210,6 +290,7 @@ JSGlobalData::~JSGlobalData() fastDelete(const_cast<HashTable*>(jsonTable)); fastDelete(const_cast<HashTable*>(mathTable)); fastDelete(const_cast<HashTable*>(numberTable)); + fastDelete(const_cast<HashTable*>(objectConstructorTable)); fastDelete(const_cast<HashTable*>(regExpTable)); fastDelete(const_cast<HashTable*>(regExpConstructorTable)); fastDelete(const_cast<HashTable*>(stringTable)); @@ -244,10 +325,7 @@ PassRefPtr<JSGlobalData> JSGlobalData::create(ThreadStackType type) PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(ThreadStackType type) { - Structure::startIgnoringLeaks(); - RefPtr<JSGlobalData> data = create(type); - Structure::stopIgnoringLeaks(); - return data.release(); + return create(type); } bool JSGlobalData::sharedInstanceExists() @@ -275,14 +353,19 @@ JSGlobalData*& JSGlobalData::sharedInstanceInternal() } #if ENABLE(JIT) -PassRefPtr<NativeExecutable> JSGlobalData::getHostFunction(NativeFunction function) +NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function) { return jitStubs->hostFunctionStub(this, function); } -PassRefPtr<NativeExecutable> JSGlobalData::getHostFunction(NativeFunction function, ThunkGenerator generator) +NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, ThunkGenerator generator) { return jitStubs->hostFunctionStub(this, function, generator); } +#else +NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function) +{ + return NativeExecutable::create(*this, function, callHostFunctionAsConstructor); +} #endif JSGlobalData::ClientData::~ClientData() @@ -313,22 +396,6 @@ void JSGlobalData::dumpSampleData(ExecState* exec) interpreter->dumpSampleData(exec); } -class Recompiler { -public: - void operator()(JSCell*); -}; - -inline void Recompiler::operator()(JSCell* cell) -{ - if (!cell->inherits(&JSFunction::info)) - return; - JSFunction* function = asFunction(cell); - if (function->executable()->isHostFunction()) - return; - function->jsExecutable()->discardCode(); -} - - void JSGlobalData::recompileAllJSFunctions() { // If JavaScript is running, it's not safe to recompile, since we'll end diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.h b/Source/JavaScriptCore/runtime/JSGlobalData.h index 7b69055..f1085af 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.h +++ b/Source/JavaScriptCore/runtime/JSGlobalData.h @@ -33,13 +33,13 @@ #include "Heap.h" #include "DateInstanceCache.h" #include "ExecutableAllocator.h" +#include "Strong.h" #include "JITStubs.h" #include "JSValue.h" #include "NumericStrings.h" #include "SmallStrings.h" #include "Terminator.h" #include "TimeoutChecker.h" -#include "WeakGCMap.h" #include "WeakRandom.h" #include <wtf/BumpPointerAllocator.h> #include <wtf/Forward.h> @@ -58,11 +58,13 @@ namespace JSC { class CodeBlock; class CommonIdentifiers; + class HandleStack; class IdentifierTable; class Interpreter; class JSGlobalObject; class JSObject; class Lexer; + class NativeExecutable; class Parser; class RegExpCache; class Stringifier; @@ -75,8 +77,6 @@ namespace JSC { struct HashTable; struct Instruction; - typedef WeakGCMap<JSGlobalObject*, JSGlobalObject> GlobalObjectMap; // FIXME: Would be nice to use a WeakGCSet here. - struct DSTOffsetCache { DSTOffsetCache() { @@ -130,7 +130,7 @@ namespace JSC { #if ENABLE(JSC_MULTIPLE_THREADS) // Will start tracking threads that use the heap, which is resource-heavy. - void makeUsableFromMultipleThreads() { heap.machineStackMarker().makeUsableFromMultipleThreads(); } + void makeUsableFromMultipleThreads() { heap.machineThreads().makeUsableFromMultipleThreads(); } #endif GlobalDataType globalDataType; @@ -141,21 +141,34 @@ namespace JSC { const HashTable* jsonTable; const HashTable* mathTable; const HashTable* numberTable; + const HashTable* objectConstructorTable; const HashTable* regExpTable; const HashTable* regExpConstructorTable; const HashTable* stringTable; - RefPtr<Structure> activationStructure; - RefPtr<Structure> interruptedExecutionErrorStructure; - RefPtr<Structure> terminatedExecutionErrorStructure; - RefPtr<Structure> staticScopeStructure; - RefPtr<Structure> strictEvalActivationStructure; - RefPtr<Structure> stringStructure; - RefPtr<Structure> notAnObjectStructure; - RefPtr<Structure> propertyNameIteratorStructure; - RefPtr<Structure> getterSetterStructure; - RefPtr<Structure> apiWrapperStructure; - RefPtr<Structure> dummyMarkableCellStructure; + Strong<Structure> structureStructure; + Strong<Structure> activationStructure; + Strong<Structure> interruptedExecutionErrorStructure; + Strong<Structure> terminatedExecutionErrorStructure; + Strong<Structure> staticScopeStructure; + Strong<Structure> strictEvalActivationStructure; + Strong<Structure> stringStructure; + Strong<Structure> notAnObjectStructure; + Strong<Structure> propertyNameIteratorStructure; + Strong<Structure> getterSetterStructure; + Strong<Structure> apiWrapperStructure; + Strong<Structure> scopeChainNodeStructure; + Strong<Structure> executableStructure; + Strong<Structure> nativeExecutableStructure; + Strong<Structure> evalExecutableStructure; + Strong<Structure> programExecutableStructure; + Strong<Structure> functionExecutableStructure; + Strong<Structure> dummyMarkableCellStructure; + Strong<Structure> structureChainStructure; + +#if ENABLE(JSC_ZOMBIES) + Strong<Structure> zombieStructure; +#endif static void storeVPtrs(); static JS_EXPORTDATA void* jsArrayVPtr; @@ -199,27 +212,26 @@ namespace JSC { { return jitStubs->ctiStub(this, generator); } - PassRefPtr<NativeExecutable> getHostFunction(NativeFunction function); - PassRefPtr<NativeExecutable> getHostFunction(NativeFunction function, ThunkGenerator generator); + NativeExecutable* getHostFunction(NativeFunction, ThunkGenerator); #endif + NativeExecutable* getHostFunction(NativeFunction); + TimeoutChecker timeoutChecker; Terminator terminator; Heap heap; - DeprecatedPtr<Unknown> exception; + JSValue exception; #if ENABLE(JIT) ReturnAddressPtr exceptionLocation; #endif HashMap<OpaqueJSClass*, OpaqueJSClassContextData*> opaqueJSClassData; - GlobalObjectMap globalObjects; + unsigned globalObjectCount; JSGlobalObject* dynamicGlobalObject; HashSet<JSObject*> stringRecursionCheckVisitedObjects; - Stringifier* firstStringifierToMark; - double cachedUTCOffset; DSTOffsetCache dstOffsetCache; @@ -253,6 +265,10 @@ namespace JSC { void addRegExpToTrace(PassRefPtr<RegExp> regExp); #endif void dumpRegExpTrace(); + HandleSlot allocateGlobalHandle() { return heap.allocateGlobalHandle(); } + HandleSlot allocateLocalHandle() { return heap.allocateLocalHandle(); } + void clearBuiltinStructures(); + private: JSGlobalData(GlobalDataType, ThreadStackType); static JSGlobalData*& sharedInstanceInternal(); @@ -263,6 +279,11 @@ namespace JSC { StackBounds m_stack; }; + inline HandleSlot allocateGlobalHandle(JSGlobalData& globalData) + { + return globalData.allocateGlobalHandle(); + } + } // namespace JSC #endif // JSGlobalData_h diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp index f303196..b82949a 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" @@ -86,30 +84,17 @@ template <typename T> static inline void markIfNeeded(MarkStack& markStack, Writ markStack.append(v); } -static inline void markIfNeeded(MarkStack& markStack, const RefPtr<Structure>& s) -{ - if (s && s->storedPrototype()) - markStack.append(s->storedPrototypeSlot()); -} - JSGlobalObject::~JSGlobalObject() { ASSERT(JSLock::currentThreadIsHoldingLock()); - if (d()->debugger) - d()->debugger->detach(this); + if (m_debugger) + m_debugger->detach(this); Profiler** profiler = Profiler::enabledProfilerReference(); if (UNLIKELY(*profiler != 0)) { - (*profiler)->stopProfiling(globalExec(), UString()); + (*profiler)->stopProfiling(this); } - - d()->globalData->globalObjects.take(this); - - RegisterFile& registerFile = globalData().interpreter->registerFile(); - if (registerFile.clearGlobalObject(this)) - registerFile.setNumGlobals(0); - d()->destructor(d()); } void JSGlobalObject::init(JSObject* thisValue) @@ -118,15 +103,14 @@ 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); + m_globalData = Heap::heap(this)->globalData(); + m_globalScopeChain.set(*m_globalData, this, new (m_globalData.get()) ScopeChainNode(0, this, m_globalData.get(), this, thisValue)); - JSGlobalObject::globalExec()->init(0, 0, d()->globalScopeChain.node(), CallFrame::noCaller(), 0, 0); + JSGlobalObject::globalExec()->init(0, 0, m_globalScopeChain.get(), CallFrame::noCaller(), 0, 0); - d()->debugger = 0; + m_debugger = 0; - d()->profileGroup = 0; + m_profileGroup = 0; reset(prototype()); } @@ -135,7 +119,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,14 +128,14 @@ 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); + JSValue valueBefore = getDirect(exec->globalData(), propertyName); PutPropertySlot slot; JSVariableObject::put(exec, propertyName, value, slot); if (!valueBefore) { - JSValue valueAfter = getDirect(propertyName); + JSValue valueAfter = getDirect(exec->globalData(), propertyName); if (valueAfter) JSObject::putWithAttributes(exec, propertyName, valueAfter, attributes); } @@ -185,81 +169,80 @@ 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()->internalFunctionStructure = InternalFunction::createStructure(d()->functionPrototype.get()); - NativeFunctionWrapper* callFunction = 0; - NativeFunctionWrapper* applyFunction = 0; - d()->functionPrototype->addFunctionProperties(exec, this, d()->prototypeFunctionStructure.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()->functionPrototype->structure()->setPrototypeWithoutTransition(d()->objectPrototype.get()); + m_functionPrototype.set(exec->globalData(), this, new (exec) FunctionPrototype(exec, this, FunctionPrototype::createStructure(exec->globalData(), jsNull()))); // The real prototype will be set once ObjectPrototype is created. + m_functionStructure.set(exec->globalData(), this, JSFunction::createStructure(exec->globalData(), m_functionPrototype.get())); + m_internalFunctionStructure.set(exec->globalData(), this, InternalFunction::createStructure(exec->globalData(), m_functionPrototype.get())); + JSFunction* callFunction = 0; + JSFunction* applyFunction = 0; + m_functionPrototype->addFunctionProperties(exec, this, m_functionStructure.get(), &callFunction, &applyFunction); + m_callFunction.set(exec->globalData(), this, callFunction); + m_applyFunction.set(exec->globalData(), this, applyFunction); + m_objectPrototype.set(exec->globalData(), this, new (exec) ObjectPrototype(exec, this, ObjectPrototype::createStructure(exec->globalData(), jsNull()), m_functionStructure.get())); + m_functionPrototype->structure()->setPrototypeWithoutTransition(exec->globalData(), m_objectPrototype.get()); - d()->emptyObjectStructure = d()->objectPrototype->inheritorID(); + m_emptyObjectStructure.set(exec->globalData(), this, m_objectPrototype->inheritorID(exec->globalData())); - 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()); - d()->callbackObjectStructure = JSCallbackObject<JSObjectWithGlobalObject>::createStructure(d()->objectPrototype.get()); + m_callbackFunctionStructure.set(exec->globalData(), this, JSCallbackFunction::createStructure(exec->globalData(), m_functionPrototype.get())); + m_argumentsStructure.set(exec->globalData(), this, Arguments::createStructure(exec->globalData(), m_objectPrototype.get())); + m_callbackConstructorStructure.set(exec->globalData(), this, JSCallbackConstructor::createStructure(exec->globalData(), m_objectPrototype.get())); + m_callbackObjectStructure.set(exec->globalData(), this, JSCallbackObject<JSObjectWithGlobalObject>::createStructure(exec->globalData(), m_objectPrototype.get())); - d()->arrayPrototype.set(exec->globalData(), this, new (exec) ArrayPrototype(this, ArrayPrototype::createStructure(d()->objectPrototype.get()))); - d()->arrayStructure = JSArray::createStructure(d()->arrayPrototype.get()); - d()->regExpMatchesArrayStructure = RegExpMatchesArray::createStructure(d()->arrayPrototype.get()); + m_arrayPrototype.set(exec->globalData(), this, new (exec) ArrayPrototype(this, ArrayPrototype::createStructure(exec->globalData(), m_objectPrototype.get()))); + m_arrayStructure.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), m_arrayPrototype.get())); + m_regExpMatchesArrayStructure.set(exec->globalData(), this, RegExpMatchesArray::createStructure(exec->globalData(), m_arrayPrototype.get())); - d()->stringPrototype.set(exec->globalData(), this, new (exec) StringPrototype(exec, this, StringPrototype::createStructure(d()->objectPrototype.get()))); - d()->stringObjectStructure = StringObject::createStructure(d()->stringPrototype.get()); + m_stringPrototype.set(exec->globalData(), this, new (exec) StringPrototype(exec, this, StringPrototype::createStructure(exec->globalData(), m_objectPrototype.get()))); + m_stringObjectStructure.set(exec->globalData(), this, StringObject::createStructure(exec->globalData(), m_stringPrototype.get())); - d()->booleanPrototype.set(exec->globalData(), this, new (exec) BooleanPrototype(exec, this, BooleanPrototype::createStructure(d()->objectPrototype.get()), d()->prototypeFunctionStructure.get())); - d()->booleanObjectStructure = BooleanObject::createStructure(d()->booleanPrototype.get()); + m_booleanPrototype.set(exec->globalData(), this, new (exec) BooleanPrototype(exec, this, BooleanPrototype::createStructure(exec->globalData(), m_objectPrototype.get()), m_functionStructure.get())); + m_booleanObjectStructure.set(exec->globalData(), this, BooleanObject::createStructure(exec->globalData(), m_booleanPrototype.get())); - d()->numberPrototype.set(exec->globalData(), this, new (exec) NumberPrototype(exec, this, NumberPrototype::createStructure(d()->objectPrototype.get()), d()->prototypeFunctionStructure.get())); - d()->numberObjectStructure = NumberObject::createStructure(d()->numberPrototype.get()); + m_numberPrototype.set(exec->globalData(), this, new (exec) NumberPrototype(exec, this, NumberPrototype::createStructure(exec->globalData(), m_objectPrototype.get()), m_functionStructure.get())); + m_numberObjectStructure.set(exec->globalData(), this, NumberObject::createStructure(exec->globalData(), m_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()); + m_datePrototype.set(exec->globalData(), this, new (exec) DatePrototype(exec, this, DatePrototype::createStructure(exec->globalData(), m_objectPrototype.get()))); + m_dateStructure.set(exec->globalData(), this, DateInstance::createStructure(exec->globalData(), m_datePrototype.get())); - d()->regExpPrototype.set(exec->globalData(), this, new (exec) RegExpPrototype(exec, this, RegExpPrototype::createStructure(d()->objectPrototype.get()), d()->prototypeFunctionStructure.get())); - d()->regExpStructure = RegExpObject::createStructure(d()->regExpPrototype.get()); + m_regExpPrototype.set(exec->globalData(), this, new (exec) RegExpPrototype(exec, this, RegExpPrototype::createStructure(exec->globalData(), m_objectPrototype.get()), m_functionStructure.get())); + m_regExpStructure.set(exec->globalData(), this, RegExpObject::createStructure(exec->globalData(), m_regExpPrototype.get())); - d()->methodCallDummy.set(exec->globalData(), this, constructEmptyObject(exec)); + m_methodCallDummy.set(exec->globalData(), this, constructEmptyObject(exec)); - ErrorPrototype* errorPrototype = new (exec) ErrorPrototype(exec, this, ErrorPrototype::createStructure(d()->objectPrototype.get()), d()->prototypeFunctionStructure.get()); - d()->errorStructure = ErrorInstance::createStructure(errorPrototype); + ErrorPrototype* errorPrototype = new (exec) ErrorPrototype(exec, this, ErrorPrototype::createStructure(exec->globalData(), m_objectPrototype.get()), m_functionStructure.get()); + m_errorStructure.set(exec->globalData(), this, ErrorInstance::createStructure(exec->globalData(), errorPrototype)); // Constructors - JSCell* objectConstructor = new (exec) ObjectConstructor(exec, this, ObjectConstructor::createStructure(d()->functionPrototype.get()), d()->objectPrototype.get(), d()->prototypeFunctionStructure.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* 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()); - - d()->regExpConstructor.set(exec->globalData(), this, new (exec) RegExpConstructor(exec, this, RegExpConstructor::createStructure(d()->functionPrototype.get()), d()->regExpPrototype.get())); - - d()->errorConstructor.set(exec->globalData(), this, new (exec) ErrorConstructor(exec, this, ErrorConstructor::createStructure(d()->functionPrototype.get()), errorPrototype)); - - RefPtr<Structure> nativeErrorPrototypeStructure = NativeErrorPrototype::createStructure(errorPrototype); - RefPtr<Structure> nativeErrorStructure = NativeErrorConstructor::createStructure(d()->functionPrototype.get()); - d()->evalErrorConstructor.set(exec->globalData(), this, new (exec) NativeErrorConstructor(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "EvalError")); - d()->rangeErrorConstructor.set(exec->globalData(), this, new (exec) NativeErrorConstructor(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "RangeError")); - d()->referenceErrorConstructor.set(exec->globalData(), this, new (exec) NativeErrorConstructor(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "ReferenceError")); - d()->syntaxErrorConstructor.set(exec->globalData(), this, new (exec) NativeErrorConstructor(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "SyntaxError")); - d()->typeErrorConstructor.set(exec->globalData(), this, new (exec) NativeErrorConstructor(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "TypeError")); - d()->URIErrorConstructor.set(exec->globalData(), this, new (exec) NativeErrorConstructor(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "URIError")); - - d()->objectPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, objectConstructor, DontEnum); - d()->functionPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, functionConstructor, DontEnum); - d()->arrayPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, arrayConstructor, DontEnum); - d()->booleanPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, booleanConstructor, DontEnum); - d()->stringPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, stringConstructor, DontEnum); - d()->numberPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, numberConstructor, DontEnum); - d()->datePrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, dateConstructor, DontEnum); - d()->regExpPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, d()->regExpConstructor.get(), DontEnum); - errorPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, d()->errorConstructor.get(), DontEnum); + JSCell* objectConstructor = new (exec) ObjectConstructor(exec, this, ObjectConstructor::createStructure(exec->globalData(), m_functionPrototype.get()), m_objectPrototype.get()); + JSCell* functionConstructor = new (exec) FunctionConstructor(exec, this, FunctionConstructor::createStructure(exec->globalData(), m_functionPrototype.get()), m_functionPrototype.get()); + JSCell* arrayConstructor = new (exec) ArrayConstructor(exec, this, ArrayConstructor::createStructure(exec->globalData(), m_functionPrototype.get()), m_arrayPrototype.get(), m_functionStructure.get()); + JSCell* stringConstructor = new (exec) StringConstructor(exec, this, StringConstructor::createStructure(exec->globalData(), m_functionPrototype.get()), m_functionStructure.get(), m_stringPrototype.get()); + JSCell* booleanConstructor = new (exec) BooleanConstructor(exec, this, BooleanConstructor::createStructure(exec->globalData(), m_functionPrototype.get()), m_booleanPrototype.get()); + JSCell* numberConstructor = new (exec) NumberConstructor(exec, this, NumberConstructor::createStructure(exec->globalData(), m_functionPrototype.get()), m_numberPrototype.get()); + JSCell* dateConstructor = new (exec) DateConstructor(exec, this, DateConstructor::createStructure(exec->globalData(), m_functionPrototype.get()), m_functionStructure.get(), m_datePrototype.get()); + + m_regExpConstructor.set(exec->globalData(), this, new (exec) RegExpConstructor(exec, this, RegExpConstructor::createStructure(exec->globalData(), m_functionPrototype.get()), m_regExpPrototype.get())); + + m_errorConstructor.set(exec->globalData(), this, new (exec) ErrorConstructor(exec, this, ErrorConstructor::createStructure(exec->globalData(), m_functionPrototype.get()), errorPrototype)); + + Structure* nativeErrorPrototypeStructure = NativeErrorPrototype::createStructure(exec->globalData(), errorPrototype); + Structure* nativeErrorStructure = NativeErrorConstructor::createStructure(exec->globalData(), m_functionPrototype.get()); + m_evalErrorConstructor.set(exec->globalData(), this, new (exec) NativeErrorConstructor(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "EvalError")); + m_rangeErrorConstructor.set(exec->globalData(), this, new (exec) NativeErrorConstructor(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "RangeError")); + m_referenceErrorConstructor.set(exec->globalData(), this, new (exec) NativeErrorConstructor(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "ReferenceError")); + m_syntaxErrorConstructor.set(exec->globalData(), this, new (exec) NativeErrorConstructor(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "SyntaxError")); + m_typeErrorConstructor.set(exec->globalData(), this, new (exec) NativeErrorConstructor(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "TypeError")); + m_URIErrorConstructor.set(exec->globalData(), this, new (exec) NativeErrorConstructor(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "URIError")); + + m_objectPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, objectConstructor, DontEnum); + m_functionPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, functionConstructor, DontEnum); + m_arrayPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, arrayConstructor, DontEnum); + m_booleanPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, booleanConstructor, DontEnum); + m_stringPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, stringConstructor, DontEnum); + m_numberPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, numberConstructor, DontEnum); + m_datePrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, dateConstructor, DontEnum); + m_regExpPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, m_regExpConstructor.get(), DontEnum); + errorPrototype->putDirectFunctionWithoutTransition(exec->globalData(), exec->propertyNames().constructor, m_errorConstructor.get(), DontEnum); // Set global constructors @@ -272,121 +255,118 @@ void JSGlobalObject::reset(JSValue prototype) putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "String"), stringConstructor, DontEnum); putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "Number"), numberConstructor, DontEnum); putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "Date"), dateConstructor, DontEnum); - putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "RegExp"), d()->regExpConstructor.get(), DontEnum); - putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "Error"), d()->errorConstructor.get(), DontEnum); - putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "EvalError"), d()->evalErrorConstructor.get(), DontEnum); - putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "RangeError"), d()->rangeErrorConstructor.get(), DontEnum); - putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "ReferenceError"), d()->referenceErrorConstructor.get(), DontEnum); - putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "SyntaxError"), d()->syntaxErrorConstructor.get(), DontEnum); - putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "TypeError"), d()->typeErrorConstructor.get(), DontEnum); - putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "URIError"), d()->URIErrorConstructor.get(), DontEnum); + putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "RegExp"), m_regExpConstructor.get(), DontEnum); + putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "Error"), m_errorConstructor.get(), DontEnum); + putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "EvalError"), m_evalErrorConstructor.get(), DontEnum); + putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "RangeError"), m_rangeErrorConstructor.get(), DontEnum); + putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "ReferenceError"), m_referenceErrorConstructor.get(), DontEnum); + putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "SyntaxError"), m_syntaxErrorConstructor.get(), DontEnum); + putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "TypeError"), m_typeErrorConstructor.get(), DontEnum); + putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, "URIError"), m_URIErrorConstructor.get(), DontEnum); // Set global values. GlobalPropertyInfo staticGlobals[] = { - GlobalPropertyInfo(Identifier(exec, "Math"), new (exec) MathObject(exec, this, MathObject::createStructure(d()->objectPrototype.get())), DontEnum | DontDelete), + GlobalPropertyInfo(Identifier(exec, "Math"), new (exec) MathObject(exec, this, MathObject::createStructure(exec->globalData(), m_objectPrototype.get())), DontEnum | DontDelete), GlobalPropertyInfo(Identifier(exec, "NaN"), jsNaN(), DontEnum | DontDelete | ReadOnly), GlobalPropertyInfo(Identifier(exec, "Infinity"), jsNumber(Inf), DontEnum | DontDelete | ReadOnly), GlobalPropertyInfo(Identifier(exec, "undefined"), jsUndefined(), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(Identifier(exec, "JSON"), new (exec) JSONObject(this, JSONObject::createStructure(d()->objectPrototype.get())), DontEnum | DontDelete) + GlobalPropertyInfo(Identifier(exec, "JSON"), new (exec) JSONObject(this, JSONObject::createStructure(exec->globalData(), m_objectPrototype.get())), DontEnum | DontDelete) }; addStaticGlobals(staticGlobals, WTF_ARRAY_LENGTH(staticGlobals)); // 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)); - 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); + m_evalFunction.set(exec->globalData(), this, new (exec) JSFunction(exec, this, m_functionStructure.get(), 1, exec->propertyNames().eval, globalFuncEval)); + putDirectFunctionWithoutTransition(exec, m_evalFunction.get(), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, this, m_functionStructure.get(), 2, Identifier(exec, "parseInt"), globalFuncParseInt), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, this, m_functionStructure.get(), 1, Identifier(exec, "parseFloat"), globalFuncParseFloat), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, this, m_functionStructure.get(), 1, Identifier(exec, "isNaN"), globalFuncIsNaN), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, this, m_functionStructure.get(), 1, Identifier(exec, "isFinite"), globalFuncIsFinite), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, this, m_functionStructure.get(), 1, Identifier(exec, "escape"), globalFuncEscape), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, this, m_functionStructure.get(), 1, Identifier(exec, "unescape"), globalFuncUnescape), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, this, m_functionStructure.get(), 1, Identifier(exec, "decodeURI"), globalFuncDecodeURI), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, this, m_functionStructure.get(), 1, Identifier(exec, "decodeURIComponent"), globalFuncDecodeURIComponent), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, this, m_functionStructure.get(), 1, Identifier(exec, "encodeURI"), globalFuncEncodeURI), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, this, m_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, m_functionStructure.get(), 1, Identifier(exec, "jscprint"), globalFuncJSCPrint), DontEnum); #endif - resetPrototype(prototype); + resetPrototype(exec->globalData(), prototype); } // Set prototype, and also insert the object prototype at the end of the chain. -void JSGlobalObject::resetPrototype(JSValue prototype) +void JSGlobalObject::resetPrototype(JSGlobalData& globalData, JSValue prototype) { - setPrototype(prototype); + setPrototype(globalData, prototype); JSObject* oldLastInPrototypeChain = lastInPrototypeChain(this); - JSObject* objectPrototype = d()->objectPrototype.get(); + JSObject* objectPrototype = m_objectPrototype.get(); if (oldLastInPrototypeChain != objectPrototype) - oldLastInPrototypeChain->setPrototype(objectPrototype); + oldLastInPrototypeChain->setPrototype(globalData, objectPrototype); } void JSGlobalObject::markChildren(MarkStack& markStack) { JSVariableObject::markChildren(markStack); - - markIfNeeded(markStack, &d()->regExpConstructor); - markIfNeeded(markStack, &d()->errorConstructor); - markIfNeeded(markStack, &d()->evalErrorConstructor); - markIfNeeded(markStack, &d()->rangeErrorConstructor); - markIfNeeded(markStack, &d()->referenceErrorConstructor); - markIfNeeded(markStack, &d()->syntaxErrorConstructor); - markIfNeeded(markStack, &d()->typeErrorConstructor); - markIfNeeded(markStack, &d()->URIErrorConstructor); - - markIfNeeded(markStack, &d()->evalFunction); - markIfNeeded(markStack, &d()->callFunction); - markIfNeeded(markStack, &d()->applyFunction); - - markIfNeeded(markStack, &d()->objectPrototype); - markIfNeeded(markStack, &d()->functionPrototype); - markIfNeeded(markStack, &d()->arrayPrototype); - markIfNeeded(markStack, &d()->booleanPrototype); - markIfNeeded(markStack, &d()->stringPrototype); - markIfNeeded(markStack, &d()->numberPrototype); - markIfNeeded(markStack, &d()->datePrototype); - markIfNeeded(markStack, &d()->regExpPrototype); - - markIfNeeded(markStack, &d()->methodCallDummy); - - markIfNeeded(markStack, d()->errorStructure); - markIfNeeded(markStack, d()->argumentsStructure); - markIfNeeded(markStack, d()->arrayStructure); - markIfNeeded(markStack, d()->booleanObjectStructure); - markIfNeeded(markStack, d()->callbackConstructorStructure); - markIfNeeded(markStack, d()->callbackFunctionStructure); - markIfNeeded(markStack, d()->callbackObjectStructure); - markIfNeeded(markStack, d()->dateStructure); - markIfNeeded(markStack, d()->emptyObjectStructure); - 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); - - // No need to mark the other structures, because their prototypes are all - // guaranteed to be referenced elsewhere. - - if (d()->registerArray) { + + markIfNeeded(markStack, &m_globalScopeChain); + markIfNeeded(markStack, &m_methodCallDummy); + + markIfNeeded(markStack, &m_regExpConstructor); + markIfNeeded(markStack, &m_errorConstructor); + markIfNeeded(markStack, &m_evalErrorConstructor); + markIfNeeded(markStack, &m_rangeErrorConstructor); + markIfNeeded(markStack, &m_referenceErrorConstructor); + markIfNeeded(markStack, &m_syntaxErrorConstructor); + markIfNeeded(markStack, &m_typeErrorConstructor); + markIfNeeded(markStack, &m_URIErrorConstructor); + + markIfNeeded(markStack, &m_evalFunction); + markIfNeeded(markStack, &m_callFunction); + markIfNeeded(markStack, &m_applyFunction); + + markIfNeeded(markStack, &m_objectPrototype); + markIfNeeded(markStack, &m_functionPrototype); + markIfNeeded(markStack, &m_arrayPrototype); + markIfNeeded(markStack, &m_booleanPrototype); + markIfNeeded(markStack, &m_stringPrototype); + markIfNeeded(markStack, &m_numberPrototype); + markIfNeeded(markStack, &m_datePrototype); + markIfNeeded(markStack, &m_regExpPrototype); + + markIfNeeded(markStack, &m_argumentsStructure); + markIfNeeded(markStack, &m_arrayStructure); + markIfNeeded(markStack, &m_booleanObjectStructure); + markIfNeeded(markStack, &m_callbackConstructorStructure); + markIfNeeded(markStack, &m_callbackFunctionStructure); + markIfNeeded(markStack, &m_callbackObjectStructure); + markIfNeeded(markStack, &m_dateStructure); + markIfNeeded(markStack, &m_emptyObjectStructure); + markIfNeeded(markStack, &m_errorStructure); + markIfNeeded(markStack, &m_functionStructure); + markIfNeeded(markStack, &m_numberObjectStructure); + markIfNeeded(markStack, &m_regExpMatchesArrayStructure); + markIfNeeded(markStack, &m_regExpStructure); + markIfNeeded(markStack, &m_stringObjectStructure); + markIfNeeded(markStack, &m_internalFunctionStructure); + + if (m_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); - } else if (d()->registers) { + markStack.appendValues(m_registerArray.get(), m_registerArraySize); + } else if (m_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(m_registers - symbolTable().size(), symbolTable().size()); } } ExecState* JSGlobalObject::globalExec() { - return CallFrame::create(d()->globalCallFrame + RegisterFile::CallFrameHeaderSize); + return CallFrame::create(m_globalCallFrame + RegisterFile::CallFrameHeaderSize); } bool JSGlobalObject::isDynamicScope(bool&) const @@ -396,17 +376,17 @@ bool JSGlobalObject::isDynamicScope(bool&) const void JSGlobalObject::copyGlobalsFrom(RegisterFile& registerFile) { - ASSERT(!d()->registerArray); - ASSERT(!d()->registerArraySize); + ASSERT(!m_registerArray); + ASSERT(!m_registerArraySize); int numGlobals = registerFile.numGlobals(); if (!numGlobals) { - d()->registers = 0; + m_registers = 0; return; } - OwnArrayPtr<Register> registerArray = copyRegisterArray(registerFile.lastGlobal(), numGlobals); - Register* registers = registerArray.get() + numGlobals; + OwnArrayPtr<WriteBarrier<Unknown> > registerArray = copyRegisterArray(globalData(), reinterpret_cast<WriteBarrier<Unknown>*>(registerFile.lastGlobal()), numGlobals, numGlobals); + WriteBarrier<Unknown>* registers = registerArray.get() + numGlobals; setRegisters(registers, registerArray.release(), numGlobals); } @@ -419,37 +399,55 @@ void JSGlobalObject::copyGlobalsTo(RegisterFile& registerFile) registerFile.setGlobalObject(this); registerFile.setNumGlobals(symbolTable().size()); - if (d()->registerArray) { - memcpy(registerFile.start() - d()->registerArraySize, d()->registerArray.get(), d()->registerArraySize * sizeof(Register)); - setRegisters(registerFile.start(), 0, 0); + if (m_registerArray) { + // The register file is always a gc root so no barrier is needed here + memcpy(registerFile.start() - m_registerArraySize, m_registerArray.get(), m_registerArraySize * sizeof(WriteBarrier<Unknown>)); + setRegisters(reinterpret_cast<WriteBarrier<Unknown>*>(registerFile.start()), nullptr, 0); } } -void* JSGlobalObject::operator new(size_t size, JSGlobalData* globalData) +void JSGlobalObject::resizeRegisters(int oldSize, int newSize) { - return globalData->heap.allocate(size); + ASSERT(oldSize <= newSize); + if (newSize == oldSize) + return; + ASSERT(newSize && newSize > oldSize); + if (m_registerArray || !m_registers) { + ASSERT(static_cast<size_t>(oldSize) == m_registerArraySize); + OwnArrayPtr<WriteBarrier<Unknown> > registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[newSize]); + for (int i = 0; i < oldSize; i++) + registerArray[newSize - oldSize + i].set(globalData(), this, m_registerArray[i].get()); + WriteBarrier<Unknown>* registers = registerArray.get() + newSize; + setRegisters(registers, registerArray.release(), newSize); + } else { + ASSERT(static_cast<size_t>(newSize) < globalData().interpreter->registerFile().maxGlobals()); + globalData().interpreter->registerFile().setNumGlobals(newSize); + } + + for (int i = -newSize; i < -oldSize; ++i) + m_registers[i].setUndefined(); } -void JSGlobalObject::destroyJSGlobalObjectData(void* jsGlobalObjectData) +void* JSGlobalObject::operator new(size_t size, JSGlobalData* globalData) { - delete static_cast<JSGlobalObjectData*>(jsGlobalObjectData); + return globalData->heap.allocate(size); } -DynamicGlobalObjectScope::DynamicGlobalObjectScope(CallFrame* callFrame, JSGlobalObject* dynamicGlobalObject) - : m_dynamicGlobalObjectSlot(callFrame->globalData().dynamicGlobalObject) +DynamicGlobalObjectScope::DynamicGlobalObjectScope(JSGlobalData& globalData, JSGlobalObject* dynamicGlobalObject) + : m_dynamicGlobalObjectSlot(globalData.dynamicGlobalObject) , m_savedDynamicGlobalObject(m_dynamicGlobalObjectSlot) { if (!m_dynamicGlobalObjectSlot) { #if ENABLE(ASSEMBLER) if (ExecutableAllocator::underMemoryPressure()) - callFrame->globalData().recompileAllJSFunctions(); + globalData.recompileAllJSFunctions(); #endif m_dynamicGlobalObjectSlot = dynamicGlobalObject; // Reset the date cache between JS invocations to force the VM // to observe time zone changes. - callFrame->globalData().resetDateCache(); + globalData.resetDateCache(); } } diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h index d13d2da..0e36920 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.h +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h @@ -26,9 +26,9 @@ #include "JSGlobalData.h" #include "JSVariableObject.h" #include "JSWeakObjectMapRefInternal.h" -#include "NativeFunctionWrapper.h" #include "NumberPrototype.h" #include "StringPrototype.h" +#include "StructureChain.h" #include <wtf/HashSet.h> #include <wtf/OwnPtr.h> #include <wtf/RandomNumber.h> @@ -42,10 +42,8 @@ namespace JSC { class ErrorConstructor; class FunctionPrototype; class GlobalCodeBlock; - class GlobalEvalFunction; class NativeErrorConstructor; class ProgramCodeBlock; - class PrototypeFunction; class RegExpConstructor; class RegExpPrototype; class RegisterFile; @@ -57,101 +55,81 @@ namespace JSC { class JSGlobalObject : public JSVariableObject { protected: - using JSVariableObject::JSVariableObjectData; typedef HashSet<RefPtr<OpaqueJSWeakObjectMap> > WeakMapSet; - struct JSGlobalObjectData : public JSVariableObjectData { - // We use an explicit destructor function pointer instead of a - // virtual destructor because we want to avoid adding a vtable - // pointer to this struct. Adding a vtable pointer would force the - // compiler to emit costly pointer fixup code when casting from - // JSVariableObjectData* to JSGlobalObjectData*. - typedef void (*Destructor)(void*); - - JSGlobalObjectData(Destructor destructor) - : JSVariableObjectData(&symbolTable, 0) - , destructor(destructor) - , registerArraySize(0) - , globalScopeChain(NoScopeChain()) - , weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0))) - { - } - - Destructor destructor; - - size_t registerArraySize; - - JSGlobalObject* next; - JSGlobalObject* prev; - - Debugger* debugger; - - ScopeChain globalScopeChain; - Register globalCallFrame[RegisterFile::CallFrameHeaderSize]; - - WriteBarrier<RegExpConstructor> regExpConstructor; - WriteBarrier<ErrorConstructor> errorConstructor; - WriteBarrier<NativeErrorConstructor> evalErrorConstructor; - WriteBarrier<NativeErrorConstructor> rangeErrorConstructor; - WriteBarrier<NativeErrorConstructor> referenceErrorConstructor; - WriteBarrier<NativeErrorConstructor> syntaxErrorConstructor; - WriteBarrier<NativeErrorConstructor> typeErrorConstructor; - WriteBarrier<NativeErrorConstructor> URIErrorConstructor; - - WriteBarrier<GlobalEvalFunction> evalFunction; - WriteBarrier<NativeFunctionWrapper> callFunction; - WriteBarrier<NativeFunctionWrapper> applyFunction; - - WriteBarrier<ObjectPrototype> objectPrototype; - WriteBarrier<FunctionPrototype> functionPrototype; - WriteBarrier<ArrayPrototype> arrayPrototype; - WriteBarrier<BooleanPrototype> booleanPrototype; - WriteBarrier<StringPrototype> stringPrototype; - WriteBarrier<NumberPrototype> numberPrototype; - WriteBarrier<DatePrototype> datePrototype; - WriteBarrier<RegExpPrototype> regExpPrototype; - - WriteBarrier<JSObject> methodCallDummy; - - RefPtr<Structure> argumentsStructure; - RefPtr<Structure> arrayStructure; - RefPtr<Structure> booleanObjectStructure; - RefPtr<Structure> callbackConstructorStructure; - RefPtr<Structure> callbackFunctionStructure; - RefPtr<Structure> callbackObjectStructure; - RefPtr<Structure> dateStructure; - RefPtr<Structure> emptyObjectStructure; - RefPtr<Structure> errorStructure; - RefPtr<Structure> functionStructure; - RefPtr<Structure> numberObjectStructure; - RefPtr<Structure> prototypeFunctionStructure; - RefPtr<Structure> regExpMatchesArrayStructure; - RefPtr<Structure> regExpStructure; - RefPtr<Structure> stringObjectStructure; - RefPtr<Structure> internalFunctionStructure; - - SymbolTable symbolTable; - unsigned profileGroup; - - RefPtr<JSGlobalData> globalData; - - WeakMapSet weakMaps; - WeakRandom weakRandom; - }; + RefPtr<JSGlobalData> m_globalData; + + size_t m_registerArraySize; + Register m_globalCallFrame[RegisterFile::CallFrameHeaderSize]; + + WriteBarrier<ScopeChainNode> m_globalScopeChain; + WriteBarrier<JSObject> m_methodCallDummy; + + WriteBarrier<RegExpConstructor> m_regExpConstructor; + WriteBarrier<ErrorConstructor> m_errorConstructor; + WriteBarrier<NativeErrorConstructor> m_evalErrorConstructor; + WriteBarrier<NativeErrorConstructor> m_rangeErrorConstructor; + WriteBarrier<NativeErrorConstructor> m_referenceErrorConstructor; + WriteBarrier<NativeErrorConstructor> m_syntaxErrorConstructor; + WriteBarrier<NativeErrorConstructor> m_typeErrorConstructor; + WriteBarrier<NativeErrorConstructor> m_URIErrorConstructor; + + WriteBarrier<JSFunction> m_evalFunction; + WriteBarrier<JSFunction> m_callFunction; + WriteBarrier<JSFunction> m_applyFunction; + + WriteBarrier<ObjectPrototype> m_objectPrototype; + WriteBarrier<FunctionPrototype> m_functionPrototype; + WriteBarrier<ArrayPrototype> m_arrayPrototype; + WriteBarrier<BooleanPrototype> m_booleanPrototype; + WriteBarrier<StringPrototype> m_stringPrototype; + WriteBarrier<NumberPrototype> m_numberPrototype; + WriteBarrier<DatePrototype> m_datePrototype; + WriteBarrier<RegExpPrototype> m_regExpPrototype; + + WriteBarrier<Structure> m_argumentsStructure; + WriteBarrier<Structure> m_arrayStructure; + WriteBarrier<Structure> m_booleanObjectStructure; + WriteBarrier<Structure> m_callbackConstructorStructure; + WriteBarrier<Structure> m_callbackFunctionStructure; + WriteBarrier<Structure> m_callbackObjectStructure; + WriteBarrier<Structure> m_dateStructure; + WriteBarrier<Structure> m_emptyObjectStructure; + WriteBarrier<Structure> m_errorStructure; + WriteBarrier<Structure> m_functionStructure; + WriteBarrier<Structure> m_numberObjectStructure; + WriteBarrier<Structure> m_regExpMatchesArrayStructure; + WriteBarrier<Structure> m_regExpStructure; + WriteBarrier<Structure> m_stringObjectStructure; + WriteBarrier<Structure> m_internalFunctionStructure; + + unsigned m_profileGroup; + Debugger* m_debugger; + + WeakMapSet m_weakMaps; + WeakRandom m_weakRandom; + + SymbolTable m_symbolTable; public: void* operator new(size_t, JSGlobalData*); - explicit JSGlobalObject() - : JSVariableObject(JSGlobalObject::createStructure(jsNull()), new JSGlobalObjectData(destroyJSGlobalObjectData)) + explicit JSGlobalObject(JSGlobalData& globalData) + : JSVariableObject(globalData, JSGlobalObject::createStructure(globalData, jsNull()), &m_symbolTable, 0) + , m_registerArraySize(0) + , m_globalScopeChain() + , m_weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0))) { COMPILE_ASSERT(JSGlobalObject::AnonymousSlotCount == 1, JSGlobalObject_has_only_a_single_slot); putThisToAnonymousValue(0); init(this); } - explicit JSGlobalObject(NonNullPassRefPtr<Structure> structure) - : JSVariableObject(structure, new JSGlobalObjectData(destroyJSGlobalObjectData)) + explicit JSGlobalObject(JSGlobalData& globalData, Structure* structure) + : JSVariableObject(globalData, structure, &m_symbolTable, 0) + , m_registerArraySize(0) + , m_globalScopeChain() + , m_weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0))) { COMPILE_ASSERT(JSGlobalObject::AnonymousSlotCount == 1, JSGlobalObject_has_only_a_single_slot); putThisToAnonymousValue(0); @@ -159,8 +137,11 @@ namespace JSC { } protected: - JSGlobalObject(NonNullPassRefPtr<Structure> structure, JSGlobalObjectData* data, JSObject* thisValue) - : JSVariableObject(structure, data) + JSGlobalObject(JSGlobalData& globalData, Structure* structure, JSObject* thisValue) + : JSVariableObject(globalData, structure, &m_symbolTable, 0) + , m_registerArraySize(0) + , m_globalScopeChain() + , m_weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0))) { COMPILE_ASSERT(JSGlobalObject::AnonymousSlotCount == 1, JSGlobalObject_has_only_a_single_slot); putThisToAnonymousValue(0); @@ -181,59 +162,64 @@ 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. - RegExpConstructor* regExpConstructor() const { return d()->regExpConstructor.get(); } - - ErrorConstructor* errorConstructor() const { return d()->errorConstructor.get(); } - NativeErrorConstructor* evalErrorConstructor() const { return d()->evalErrorConstructor.get(); } - NativeErrorConstructor* rangeErrorConstructor() const { return d()->rangeErrorConstructor.get(); } - NativeErrorConstructor* referenceErrorConstructor() const { return d()->referenceErrorConstructor.get(); } - NativeErrorConstructor* syntaxErrorConstructor() const { return d()->syntaxErrorConstructor.get(); } - NativeErrorConstructor* typeErrorConstructor() const { return d()->typeErrorConstructor.get(); } - NativeErrorConstructor* URIErrorConstructor() const { return d()->URIErrorConstructor.get(); } - - GlobalEvalFunction* evalFunction() const { return d()->evalFunction.get(); } - - ObjectPrototype* objectPrototype() const { return d()->objectPrototype.get(); } - FunctionPrototype* functionPrototype() const { return d()->functionPrototype.get(); } - ArrayPrototype* arrayPrototype() const { return d()->arrayPrototype.get(); } - BooleanPrototype* booleanPrototype() const { return d()->booleanPrototype.get(); } - StringPrototype* stringPrototype() const { return d()->stringPrototype.get(); } - NumberPrototype* numberPrototype() const { return d()->numberPrototype.get(); } - DatePrototype* datePrototype() const { return d()->datePrototype.get(); } - RegExpPrototype* regExpPrototype() const { return d()->regExpPrototype.get(); } - - JSObject* methodCallDummy() const { return d()->methodCallDummy.get(); } - - Structure* argumentsStructure() const { return d()->argumentsStructure.get(); } - Structure* arrayStructure() const { return d()->arrayStructure.get(); } - Structure* booleanObjectStructure() const { return d()->booleanObjectStructure.get(); } - Structure* callbackConstructorStructure() const { return d()->callbackConstructorStructure.get(); } - Structure* callbackFunctionStructure() const { return d()->callbackFunctionStructure.get(); } - Structure* callbackObjectStructure() const { return d()->callbackObjectStructure.get(); } - Structure* dateStructure() const { return d()->dateStructure.get(); } - Structure* emptyObjectStructure() const { return d()->emptyObjectStructure.get(); } - 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(); } - Structure* stringObjectStructure() const { return d()->stringObjectStructure.get(); } - - void setProfileGroup(unsigned value) { d()->profileGroup = value; } - unsigned profileGroup() const { return d()->profileGroup; } - - Debugger* debugger() const { return d()->debugger; } - void setDebugger(Debugger* debugger) { d()->debugger = debugger; } + RegExpConstructor* regExpConstructor() const { return m_regExpConstructor.get(); } + + ErrorConstructor* errorConstructor() const { return m_errorConstructor.get(); } + NativeErrorConstructor* evalErrorConstructor() const { return m_evalErrorConstructor.get(); } + NativeErrorConstructor* rangeErrorConstructor() const { return m_rangeErrorConstructor.get(); } + NativeErrorConstructor* referenceErrorConstructor() const { return m_referenceErrorConstructor.get(); } + NativeErrorConstructor* syntaxErrorConstructor() const { return m_syntaxErrorConstructor.get(); } + NativeErrorConstructor* typeErrorConstructor() const { return m_typeErrorConstructor.get(); } + NativeErrorConstructor* URIErrorConstructor() const { return m_URIErrorConstructor.get(); } + + JSFunction* evalFunction() const { return m_evalFunction.get(); } + JSFunction* callFunction() const { return m_callFunction.get(); } + JSFunction* applyFunction() const { return m_applyFunction.get(); } + + ObjectPrototype* objectPrototype() const { return m_objectPrototype.get(); } + FunctionPrototype* functionPrototype() const { return m_functionPrototype.get(); } + ArrayPrototype* arrayPrototype() const { return m_arrayPrototype.get(); } + BooleanPrototype* booleanPrototype() const { return m_booleanPrototype.get(); } + StringPrototype* stringPrototype() const { return m_stringPrototype.get(); } + NumberPrototype* numberPrototype() const { return m_numberPrototype.get(); } + DatePrototype* datePrototype() const { return m_datePrototype.get(); } + RegExpPrototype* regExpPrototype() const { return m_regExpPrototype.get(); } + + JSObject* methodCallDummy() const { return m_methodCallDummy.get(); } + + Structure* argumentsStructure() const { return m_argumentsStructure.get(); } + Structure* arrayStructure() const { return m_arrayStructure.get(); } + Structure* booleanObjectStructure() const { return m_booleanObjectStructure.get(); } + Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); } + Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); } + Structure* callbackObjectStructure() const { return m_callbackObjectStructure.get(); } + Structure* dateStructure() const { return m_dateStructure.get(); } + Structure* emptyObjectStructure() const { return m_emptyObjectStructure.get(); } + Structure* errorStructure() const { return m_errorStructure.get(); } + Structure* functionStructure() const { return m_functionStructure.get(); } + Structure* numberObjectStructure() const { return m_numberObjectStructure.get(); } + Structure* internalFunctionStructure() const { return m_internalFunctionStructure.get(); } + Structure* regExpMatchesArrayStructure() const { return m_regExpMatchesArrayStructure.get(); } + Structure* regExpStructure() const { return m_regExpStructure.get(); } + Structure* stringObjectStructure() const { return m_stringObjectStructure.get(); } + + void setProfileGroup(unsigned value) { m_profileGroup = value; } + unsigned profileGroup() const { return m_profileGroup; } + + Debugger* debugger() const { return m_debugger; } + void setDebugger(Debugger* debugger) { m_debugger = debugger; } virtual bool supportsProfiling() const { return false; } virtual bool supportsRichSourceInfo() const { return true; } - ScopeChain& globalScopeChain() { return d()->globalScopeChain; } + ScopeChainNode* globalScopeChain() { return m_globalScopeChain.get(); } virtual bool isGlobalObject() const { return true; } @@ -247,28 +233,28 @@ namespace JSC { void copyGlobalsFrom(RegisterFile&); void copyGlobalsTo(RegisterFile&); - - void resetPrototype(JSValue prototype); + void resizeRegisters(int oldSize, int newSize); - JSGlobalData& globalData() const { return *d()->globalData.get(); } - JSGlobalObjectData* d() const { return static_cast<JSGlobalObjectData*>(JSVariableObject::d); } + void resetPrototype(JSGlobalData&, JSValue prototype); - static PassRefPtr<Structure> createStructure(JSValue prototype) + JSGlobalData& globalData() const { return *m_globalData.get(); } + + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } void registerWeakMap(OpaqueJSWeakObjectMap* map) { - d()->weakMaps.add(map); + m_weakMaps.add(map); } void deregisterWeakMap(OpaqueJSWeakObjectMap* map) { - d()->weakMaps.remove(map); + m_weakMaps.remove(map); } - double weakRandomNumber() { return d()->weakRandom.get(); } + double weakRandomNumber() { return m_weakRandom.get(); } protected: static const unsigned AnonymousSlotCount = JSVariableObject::AnonymousSlotCount + 1; @@ -289,13 +275,11 @@ namespace JSC { void addStaticGlobals(GlobalPropertyInfo*, int count); private: - static void destroyJSGlobalObjectData(void*); - // FIXME: Fold reset into init. void init(JSObject* thisValue); void reset(JSValue prototype); - void setRegisters(Register* registers, PassOwnArrayPtr<Register> registerArray, size_t count); + void setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray, size_t count); void* operator new(size_t); // can only be allocated with JSGlobalData }; @@ -308,27 +292,31 @@ namespace JSC { return static_cast<JSGlobalObject*>(asObject(value)); } - inline void JSGlobalObject::setRegisters(Register* registers, PassOwnArrayPtr<Register> registerArray, size_t count) + inline void JSGlobalObject::setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray, size_t count) { JSVariableObject::setRegisters(registers, registerArray); - d()->registerArraySize = count; + m_registerArraySize = count; } inline void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count) { - size_t oldSize = d()->registerArraySize; + size_t oldSize = m_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<WriteBarrier<Unknown> > registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[newSize]); + if (m_registerArray) { + // memcpy is safe here as we're copying barriers we already own from the existing array + memcpy(registerArray.get() + count, m_registerArray.get(), oldSize * sizeof(Register)); + } + + WriteBarrier<Unknown>* registers = registerArray.get() + newSize; + setRegisters(registers, registerArray.release(), newSize); for (int i = 0, index = -static_cast<int>(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 +343,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) @@ -369,7 +363,7 @@ namespace JSC { // We cache our prototype chain so our clients can share it. if (!isValid(exec, m_cachedPrototypeChain.get())) { JSValue prototype = prototypeForLookup(exec); - m_cachedPrototypeChain = StructureChain::create(prototype.isNull() ? 0 : asObject(prototype)->structure()); + m_cachedPrototypeChain.set(exec->globalData(), this, StructureChain::create(exec->globalData(), prototype.isNull() ? 0 : asObject(prototype)->structure())); } return m_cachedPrototypeChain.get(); } @@ -380,9 +374,9 @@ namespace JSC { return false; JSValue prototype = prototypeForLookup(exec); - RefPtr<Structure>* cachedStructure = cachedPrototypeChain->head(); + WriteBarrier<Structure>* cachedStructure = cachedPrototypeChain->head(); while(*cachedStructure && !prototype.isNull()) { - if (asObject(prototype)->structure() != *cachedStructure) + if (asObject(prototype)->structure() != cachedStructure->get()) return false; ++cachedStructure; prototype = asObject(prototype)->prototype(); @@ -401,29 +395,29 @@ 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()); + return new (exec) JSArray(exec->globalData(), exec->lexicalGlobalObject()->arrayStructure()); } inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject) { - return new (exec) JSArray(globalObject->arrayStructure()); + return new (exec) JSArray(exec->globalData(), globalObject->arrayStructure()); } inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength) { - return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), initialLength, CreateInitialized); + return new (exec) JSArray(exec->globalData(), exec->lexicalGlobalObject()->arrayStructure(), initialLength, CreateInitialized); } inline JSArray* constructArray(ExecState* exec, JSValue singleItemValue) @@ -441,7 +435,7 @@ namespace JSC { class DynamicGlobalObjectScope { WTF_MAKE_NONCOPYABLE(DynamicGlobalObjectScope); public: - DynamicGlobalObjectScope(CallFrame* callFrame, JSGlobalObject* dynamicGlobalObject); + DynamicGlobalObjectScope(JSGlobalData&, JSGlobalObject*); ~DynamicGlobalObjectScope() { diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp index 284806e..f0da773 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" @@ -450,12 +449,12 @@ EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec) if (JSValue parsedObject = preparser.tryLiteralParse()) return JSValue::encode(parsedObject); - RefPtr<EvalExecutable> eval = EvalExecutable::create(exec, makeSource(s), false); - JSObject* error = eval->compile(exec, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain().node()); + EvalExecutable* eval = EvalExecutable::create(exec, makeSource(s), false); + JSObject* error = eval->compile(exec, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain()); if (error) return throwVMError(exec, error); - return JSValue::encode(exec->interpreter()->execute(eval.get(), exec, thisObject, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain().node())); + return JSValue::encode(exec->interpreter()->execute(eval, exec, thisObject, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain())); } EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec) diff --git a/Source/JavaScriptCore/runtime/JSImmediate.cpp b/Source/JavaScriptCore/runtime/JSImmediate.cpp deleted file mode 100644 index 846238d..0000000 --- a/Source/JavaScriptCore/runtime/JSImmediate.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2003-2006, 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * 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 "JSImmediate.h" - -namespace JSC { - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSImmediate.h b/Source/JavaScriptCore/runtime/JSImmediate.h deleted file mode 100644 index 68ba75c..0000000 --- a/Source/JavaScriptCore/runtime/JSImmediate.h +++ /dev/null @@ -1,568 +0,0 @@ -/* - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. - * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) - * - * 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 JSImmediate_h -#define JSImmediate_h - -#if USE(JSVALUE64) - -#include <wtf/Assertions.h> -#include <wtf/AlwaysInline.h> -#include <wtf/MathExtras.h> -#include <wtf/StdLibExtras.h> -#include "JSValue.h" -#include <limits> -#include <limits.h> -#include <stdarg.h> -#include <stdint.h> -#include <stdlib.h> - -namespace JSC { - - class ExecState; - class JSCell; - class JSGlobalData; - class JSObject; - class UString; - - inline intptr_t reinterpretDoubleToIntptr(double value) - { - return WTF::bitwise_cast<intptr_t>(value); - } - - inline double reinterpretIntptrToDouble(intptr_t value) - { - return WTF::bitwise_cast<double>(value); - } - - /* - * A JSValue* is either a pointer to a cell (a heap-allocated object) or an immediate (a type-tagged - * value masquerading as a pointer). The low two bits in a JSValue* are available for type tagging - * because allocator alignment guarantees they will be 00 in cell pointers. - * - * For example, on a 32 bit system: - * - * JSCell*: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 00 - * [ high 30 bits: pointer address ] [ low 2 bits -- always 0 ] - * JSImmediate: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX TT - * [ high 30 bits: 'payload' ] [ low 2 bits -- tag ] - * - * Where the bottom two bits are non-zero they either indicate that the immediate is a 31 bit signed - * integer, or they mark the value as being an immediate of a type other than integer, with a secondary - * tag used to indicate the exact type. - * - * Where the lowest bit is set (TT is equal to 01 or 11) the high 31 bits form a 31 bit signed int value. - * Where TT is equal to 10 this indicates this is a type of immediate other than an integer, and the next - * two bits will form an extended tag. - * - * 31 bit signed int: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X1 - * [ high 30 bits of the value ] [ high bit part of value ] - * Other: YYYYYYYYYYYYYYYYYYYYYYYYYYYY ZZ 10 - * [ extended 'payload' ] [ extended tag ] [ tag 'other' ] - * - * Where the first bit of the extended tag is set this flags the value as being a boolean, and the following - * bit would flag the value as undefined. If neither bits are set, the value is null. - * - * Other: YYYYYYYYYYYYYYYYYYYYYYYYYYYY UB 10 - * [ extended 'payload' ] [ undefined | bool ] [ tag 'other' ] - * - * For boolean value the lowest bit in the payload holds the value of the bool, all remaining bits are zero. - * For undefined or null immediates the payload is zero. - * - * Boolean: 000000000000000000000000000V 01 10 - * [ boolean value ] [ bool ] [ tag 'other' ] - * Undefined: 0000000000000000000000000000 10 10 - * [ zero ] [ undefined ] [ tag 'other' ] - * Null: 0000000000000000000000000000 00 10 - * [ zero ] [ zero ] [ tag 'other' ] - */ - - /* - * On 64-bit platforms, we support an alternative encoding form for immediates, if - * USE(JSVALUE64) is defined. When this format is used, double precision - * floating point values may also be encoded as JSImmediates. - * - * The encoding makes use of unused NaN space in the IEEE754 representation. Any value - * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values - * can encode a 51-bit payload. Hardware produced and C-library payloads typically - * have a payload of zero. We assume that non-zero payloads are available to encode - * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are - * all set represents a NaN with a non-zero payload, we can use this space in the NaN - * ranges to encode other values (however there are also other ranges of NaN space that - * could have been selected). This range of NaN space is represented by 64-bit numbers - * begining with the 16-bit hex patterns 0xFFFE and 0xFFFF - we rely on the fact that no - * valid double-precision numbers will begin fall in these ranges. - * - * The scheme we have implemented encodes double precision values by adding 2^48 to the - * 64-bit integer representation of the number. After this manipulation, no encoded - * double-precision value will begin with the pattern 0x0000 or 0xFFFF. - * - * The top 16-bits denote the type of the encoded JSImmediate: - * - * Pointer: 0000:PPPP:PPPP:PPPP - * 0001:****:****:**** - * Double:{ ... - * FFFE:****:****:**** - * Integer: FFFF:0000:IIII:IIII - * - * 32-bit signed integers are marked with the 16-bit tag 0xFFFF. The tag 0x0000 - * denotes a pointer, or another form of tagged immediate. Boolean, null and undefined - * values are encoded in the same manner as the default format. - */ - - class JSImmediate { - private: - friend class JIT; - friend class JSValue; - friend class JSInterfaceJIT; - friend class SpecializedThunkJIT; - friend JSValue jsNumber(ExecState* exec, double d); - friend JSValue jsNumber(ExecState*, char i); - friend JSValue jsNumber(ExecState*, unsigned char i); - friend JSValue jsNumber(ExecState*, short i); - friend JSValue jsNumber(ExecState*, unsigned short i); - friend JSValue jsNumber(ExecState* exec, int i); - friend JSValue jsNumber(ExecState* exec, unsigned i); - friend JSValue jsNumber(ExecState* exec, long i); - friend JSValue jsNumber(ExecState* exec, unsigned long i); - friend JSValue jsNumber(ExecState* exec, long long i); - friend JSValue jsNumber(ExecState* exec, unsigned long long i); - friend JSValue jsNumber(JSGlobalData* globalData, double d); - friend JSValue jsNumber(JSGlobalData* globalData, short i); - friend JSValue jsNumber(JSGlobalData* globalData, unsigned short i); - friend JSValue jsNumber(JSGlobalData* globalData, int i); - friend JSValue jsNumber(JSGlobalData* globalData, unsigned i); - friend JSValue jsNumber(JSGlobalData* globalData, long i); - friend JSValue jsNumber(JSGlobalData* globalData, unsigned long i); - friend JSValue jsNumber(JSGlobalData* globalData, long long i); - friend JSValue jsNumber(JSGlobalData* globalData, unsigned long long i); - - // If all bits in the mask are set, this indicates an integer number, - // if any but not all are set this value is a double precision number. - static const intptr_t TagTypeNumber = 0xffff000000000000ll; - // This value is 2^48, used to encode doubles such that the encoded value will begin - // with a 16-bit pattern within the range 0x0001..0xFFFE. - static const intptr_t DoubleEncodeOffset = 0x1000000000000ll; - static const intptr_t TagBitTypeOther = 0x2; // second bit set indicates immediate other than an integer - static const intptr_t TagMask = TagTypeNumber | TagBitTypeOther; - - static const intptr_t ExtendedTagMask = 0xC; // extended tag holds a further two bits - static const intptr_t ExtendedTagBitBool = 0x4; - static const intptr_t ExtendedTagBitUndefined = 0x8; - - static const intptr_t FullTagTypeMask = TagMask | ExtendedTagMask; - static const intptr_t FullTagTypeBool = TagBitTypeOther | ExtendedTagBitBool; - static const intptr_t FullTagTypeUndefined = TagBitTypeOther | ExtendedTagBitUndefined; - static const intptr_t FullTagTypeNull = TagBitTypeOther; - - static const int32_t IntegerPayloadShift = 0; - static const int32_t ExtendedPayloadShift = 4; - - static const intptr_t ExtendedPayloadBitBoolValue = 1 << ExtendedPayloadShift; - - static const int32_t signBit = 0x80000000; - - static ALWAYS_INLINE bool isImmediate(JSValue v) - { - return rawValue(v) & TagMask; - } - - static ALWAYS_INLINE bool isNumber(JSValue v) - { - return rawValue(v) & TagTypeNumber; - } - - static ALWAYS_INLINE bool isIntegerNumber(JSValue v) - { - return (rawValue(v) & TagTypeNumber) == TagTypeNumber; - } - - static ALWAYS_INLINE bool isDouble(JSValue v) - { - return isNumber(v) && !isIntegerNumber(v); - } - - static ALWAYS_INLINE bool isPositiveIntegerNumber(JSValue v) - { - // A single mask to check for the sign bit and the number tag all at once. - return (rawValue(v) & (signBit | TagTypeNumber)) == TagTypeNumber; - } - - static ALWAYS_INLINE bool isBoolean(JSValue v) - { - return (rawValue(v) & FullTagTypeMask) == FullTagTypeBool; - } - - static ALWAYS_INLINE bool isUndefinedOrNull(JSValue v) - { - // Undefined and null share the same value, bar the 'undefined' bit in the extended tag. - return (rawValue(v) & ~ExtendedTagBitUndefined) == FullTagTypeNull; - } - - static JSValue from(char); - static JSValue from(signed char); - static JSValue from(unsigned char); - static JSValue from(short); - static JSValue from(unsigned short); - static JSValue from(int); - static JSValue from(unsigned); - static JSValue from(long); - static JSValue from(unsigned long); - static JSValue from(long long); - static JSValue from(unsigned long long); - static JSValue from(double); - - static ALWAYS_INLINE bool isEitherImmediate(JSValue v1, JSValue v2) - { - return (rawValue(v1) | rawValue(v2)) & TagMask; - } - - static ALWAYS_INLINE bool areBothImmediate(JSValue v1, JSValue v2) - { - return isImmediate(v1) & isImmediate(v2); - } - - static ALWAYS_INLINE bool areBothImmediateIntegerNumbers(JSValue v1, JSValue v2) - { - return (rawValue(v1) & rawValue(v2) & TagTypeNumber) == TagTypeNumber; - } - - static double toDouble(JSValue); - static bool toBoolean(JSValue); - - static bool getUInt32(JSValue, uint32_t&); - static bool getTruncatedInt32(JSValue, int32_t&); - static bool getTruncatedUInt32(JSValue, uint32_t&); - - static int32_t getTruncatedInt32(JSValue); - static uint32_t getTruncatedUInt32(JSValue); - - static JSValue trueImmediate(); - static JSValue falseImmediate(); - static JSValue undefinedImmediate(); - static JSValue nullImmediate(); - static JSValue zeroImmediate(); - static JSValue oneImmediate(); - - private: - static const int minImmediateInt = ((-INT_MAX) - 1); - static const int maxImmediateInt = INT_MAX; - static const unsigned maxImmediateUInt = maxImmediateInt; - - static ALWAYS_INLINE JSValue makeValue(intptr_t integer) - { - return JSValue::makeImmediate(integer); - } - - // With USE(JSVALUE64) we want the argument to be zero extended, so the - // integer doesn't interfere with the tag bits in the upper word. In the default encoding, - // if intptr_t id larger then int32_t we sign extend the value through the upper word. - static ALWAYS_INLINE JSValue makeInt(uint32_t value) - { - return makeValue((static_cast<intptr_t>(value) << IntegerPayloadShift) | TagTypeNumber); - } - - static ALWAYS_INLINE JSValue makeDouble(double value) - { - return makeValue(reinterpretDoubleToIntptr(value) + DoubleEncodeOffset); - } - - static ALWAYS_INLINE JSValue makeBool(bool b) - { - return makeValue((static_cast<intptr_t>(b) << ExtendedPayloadShift) | FullTagTypeBool); - } - - static ALWAYS_INLINE JSValue makeUndefined() - { - return makeValue(FullTagTypeUndefined); - } - - static ALWAYS_INLINE JSValue makeNull() - { - return makeValue(FullTagTypeNull); - } - - template<typename T> - static JSValue fromNumberOutsideIntegerRange(T); - - static ALWAYS_INLINE double doubleValue(JSValue v) - { - return reinterpretIntptrToDouble(rawValue(v) - DoubleEncodeOffset); - } - - static ALWAYS_INLINE int32_t intValue(JSValue v) - { - return static_cast<int32_t>(rawValue(v) >> IntegerPayloadShift); - } - - static ALWAYS_INLINE uint32_t uintValue(JSValue v) - { - return static_cast<uint32_t>(rawValue(v) >> IntegerPayloadShift); - } - - static ALWAYS_INLINE bool boolValue(JSValue v) - { - return rawValue(v) & ExtendedPayloadBitBoolValue; - } - - static ALWAYS_INLINE intptr_t rawValue(JSValue v) - { - return v.immediateValue(); - } - }; - - ALWAYS_INLINE JSValue JSImmediate::trueImmediate() { return makeBool(true); } - ALWAYS_INLINE JSValue JSImmediate::falseImmediate() { return makeBool(false); } - ALWAYS_INLINE JSValue JSImmediate::undefinedImmediate() { return makeUndefined(); } - ALWAYS_INLINE JSValue JSImmediate::nullImmediate() { return makeNull(); } - ALWAYS_INLINE JSValue JSImmediate::zeroImmediate() { return makeInt(0); } - ALWAYS_INLINE JSValue JSImmediate::oneImmediate() { return makeInt(1); } - - inline bool doubleToBoolean(double value) - { - return value < 0.0 || value > 0.0; - } - - ALWAYS_INLINE bool JSImmediate::toBoolean(JSValue v) - { - ASSERT(isImmediate(v)); - return isNumber(v) ? isIntegerNumber(v) ? v != zeroImmediate() - : doubleToBoolean(doubleValue(v)) : v == trueImmediate(); - } - - ALWAYS_INLINE uint32_t JSImmediate::getTruncatedUInt32(JSValue v) - { - // FIXME: should probably be asserting isPositiveIntegerNumber here. - ASSERT(isIntegerNumber(v)); - return intValue(v); - } - - template<typename T> - inline JSValue JSImmediate::fromNumberOutsideIntegerRange(T value) - { - return makeDouble(static_cast<double>(value)); - } - - ALWAYS_INLINE JSValue JSImmediate::from(char i) - { - return makeInt(i); - } - - ALWAYS_INLINE JSValue JSImmediate::from(signed char i) - { - return makeInt(i); - } - - ALWAYS_INLINE JSValue JSImmediate::from(unsigned char i) - { - return makeInt(i); - } - - ALWAYS_INLINE JSValue JSImmediate::from(short i) - { - return makeInt(i); - } - - ALWAYS_INLINE JSValue JSImmediate::from(unsigned short i) - { - return makeInt(i); - } - - ALWAYS_INLINE JSValue JSImmediate::from(int i) - { - return makeInt(i); - } - - ALWAYS_INLINE JSValue JSImmediate::from(unsigned i) - { - if (i > maxImmediateUInt) - return fromNumberOutsideIntegerRange(i); - return makeInt(i); - } - - ALWAYS_INLINE JSValue JSImmediate::from(long i) - { - if ((i < minImmediateInt) | (i > maxImmediateInt)) - return fromNumberOutsideIntegerRange(i); - return makeInt(i); - } - - ALWAYS_INLINE JSValue JSImmediate::from(unsigned long i) - { - if (i > maxImmediateUInt) - return fromNumberOutsideIntegerRange(i); - return makeInt(i); - } - - ALWAYS_INLINE JSValue JSImmediate::from(long long i) - { - if ((i < minImmediateInt) | (i > maxImmediateInt)) - return JSValue(); - return makeInt(static_cast<intptr_t>(i)); - } - - ALWAYS_INLINE JSValue JSImmediate::from(unsigned long long i) - { - if (i > maxImmediateUInt) - return fromNumberOutsideIntegerRange(i); - return makeInt(static_cast<intptr_t>(i)); - } - - ALWAYS_INLINE JSValue JSImmediate::from(double d) - { - const int intVal = static_cast<int>(d); - - // Check for data loss from conversion to int. - if (intVal != d || (!intVal && signbit(d))) - return fromNumberOutsideIntegerRange(d); - - return from(intVal); - } - - ALWAYS_INLINE int32_t JSImmediate::getTruncatedInt32(JSValue v) - { - ASSERT(isIntegerNumber(v)); - return intValue(v); - } - - ALWAYS_INLINE double JSImmediate::toDouble(JSValue v) - { - ASSERT(isImmediate(v)); - - if (isIntegerNumber(v)) - return intValue(v); - - if (isNumber(v)) { - ASSERT(isDouble(v)); - return doubleValue(v); - } - - if (rawValue(v) == FullTagTypeUndefined) - return nonInlineNaN(); - - ASSERT(JSImmediate::isBoolean(v) || (v == JSImmediate::nullImmediate())); - return rawValue(v) >> ExtendedPayloadShift; - } - - ALWAYS_INLINE bool JSImmediate::getUInt32(JSValue v, uint32_t& i) - { - i = uintValue(v); - return isPositiveIntegerNumber(v); - } - - ALWAYS_INLINE bool JSImmediate::getTruncatedInt32(JSValue v, int32_t& i) - { - i = intValue(v); - return isIntegerNumber(v); - } - - ALWAYS_INLINE bool JSImmediate::getTruncatedUInt32(JSValue v, uint32_t& i) - { - return getUInt32(v, i); - } - - inline JSValue::JSValue(JSNullTag) - { - *this = JSImmediate::nullImmediate(); - } - - inline JSValue::JSValue(JSUndefinedTag) - { - *this = JSImmediate::undefinedImmediate(); - } - - inline JSValue::JSValue(JSTrueTag) - { - *this = JSImmediate::trueImmediate(); - } - - inline JSValue::JSValue(JSFalseTag) - { - *this = JSImmediate::falseImmediate(); - } - - inline bool JSValue::isUndefinedOrNull() const - { - return JSImmediate::isUndefinedOrNull(asValue()); - } - - inline bool JSValue::isBoolean() const - { - return JSImmediate::isBoolean(asValue()); - } - - inline bool JSValue::isTrue() const - { - return asValue() == JSImmediate::trueImmediate(); - } - - inline bool JSValue::isFalse() const - { - return asValue() == JSImmediate::falseImmediate(); - } - - inline bool JSValue::getBoolean(bool& v) const - { - if (JSImmediate::isBoolean(asValue())) { - v = JSImmediate::toBoolean(asValue()); - return true; - } - - return false; - } - - inline bool JSValue::getBoolean() const - { - return asValue() == jsBoolean(true); - } - - inline bool JSValue::isCell() const - { - return !JSImmediate::isImmediate(asValue()); - } - - inline bool JSValue::isInt32() const - { - return JSImmediate::isIntegerNumber(asValue()); - } - - inline int32_t JSValue::asInt32() const - { - ASSERT(isInt32()); - return JSImmediate::getTruncatedInt32(asValue()); - } - - inline bool JSValue::isUInt32() const - { - return JSImmediate::isPositiveIntegerNumber(asValue()); - } - - inline uint32_t JSValue::asUInt32() const - { - ASSERT(isUInt32()); - return JSImmediate::getTruncatedUInt32(asValue()); - } - -} // namespace JSC - -#endif // USE(JSVALUE64) - -#endif // JSImmediate_h diff --git a/Source/JavaScriptCore/runtime/JSLock.cpp b/Source/JavaScriptCore/runtime/JSLock.cpp index 918141f..fc543f0 100644 --- a/Source/JavaScriptCore/runtime/JSLock.cpp +++ b/Source/JavaScriptCore/runtime/JSLock.cpp @@ -23,14 +23,19 @@ #include "Heap.h" #include "CallFrame.h" +#include "JSObject.h" +#include "ScopeChain.h" -#if ENABLE(JSC_MULTIPLE_THREADS) +#if USE(PTHREADS) #include <pthread.h> #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 +213,7 @@ JSLock::DropAllLocks::~DropAllLocks() --lockDropDepth; } -#else +#else // ENABLE(JSC_MULTIPLE_THREADS) && (OS(DARWIN) || USE(PTHREADS)) JSLock::JSLock(ExecState*) : m_lockBehavior(SilenceAssertionsOnly) @@ -255,6 +260,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.cpp b/Source/JavaScriptCore/runtime/JSNotAnObject.cpp index e01b401..1115dc0 100644 --- a/Source/JavaScriptCore/runtime/JSNotAnObject.cpp +++ b/Source/JavaScriptCore/runtime/JSNotAnObject.cpp @@ -67,7 +67,7 @@ UString JSNotAnObject::toString(ExecState* exec) const return ""; } -JSObject* JSNotAnObject::toObject(ExecState* exec) const +JSObject* JSNotAnObject::toObject(ExecState* exec, JSGlobalObject*) const { ASSERT_UNUSED(exec, exec->hadException()); return const_cast<JSNotAnObject*>(this); diff --git a/Source/JavaScriptCore/runtime/JSNotAnObject.h b/Source/JavaScriptCore/runtime/JSNotAnObject.h index 9f527cf..4c6806a 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(), exec->globalData().notAnObjectStructure.get()) { } - static PassRefPtr<Structure> createStructure(JSValue prototype) + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } private: @@ -58,7 +58,7 @@ namespace JSC { virtual bool toBoolean(ExecState*) const; virtual double toNumber(ExecState*) const; virtual UString toString(ExecState*) const; - virtual JSObject* toObject(ExecState*) const; + virtual JSObject* toObject(ExecState*, JSGlobalObject*) const; // JSObject methods virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); diff --git a/Source/JavaScriptCore/runtime/JSNumberCell.cpp b/Source/JavaScriptCore/runtime/JSNumberCell.cpp deleted file mode 100644 index 6fa6b2a..0000000 --- a/Source/JavaScriptCore/runtime/JSNumberCell.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) - * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2004, 2007, 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * 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 "JSNumberCell.h" - -// Keep our exported symbols lists happy. -namespace JSC { - -JSValue jsNumberCell(ExecState*, double); - -JSValue jsNumberCell(ExecState*, double) -{ - ASSERT_NOT_REACHED(); - return JSValue(); -} - -} // namespace JSC - diff --git a/Source/JavaScriptCore/runtime/JSNumberCell.h b/Source/JavaScriptCore/runtime/JSNumberCell.h deleted file mode 100644 index 1ccdf50..0000000 --- a/Source/JavaScriptCore/runtime/JSNumberCell.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) - * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2004, 2005, 2007, 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * 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 JSNumberCell_h -#define JSNumberCell_h - -#include "CallFrame.h" -#include "JSCell.h" -#include "JSImmediate.h" -#include "Heap.h" -#include "UString.h" -#include <stddef.h> // for size_t - -namespace JSC { - - extern const double NaN; - extern const double Inf; - -#if USE(JSVALUE64) - ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d) - { - *this = JSImmediate::fromNumberOutsideIntegerRange(d); - } - - inline JSValue::JSValue(double d) - { - JSValue v = JSImmediate::from(d); - ASSERT(v); - *this = v; - } - - inline JSValue::JSValue(int i) - { - JSValue v = JSImmediate::from(i); - ASSERT(v); - *this = v; - } - - inline JSValue::JSValue(unsigned i) - { - JSValue v = JSImmediate::from(i); - ASSERT(v); - *this = v; - } - - inline JSValue::JSValue(long i) - { - JSValue v = JSImmediate::from(i); - ASSERT(v); - *this = v; - } - - inline JSValue::JSValue(unsigned long i) - { - JSValue v = JSImmediate::from(i); - ASSERT(v); - *this = v; - } - - inline JSValue::JSValue(long long i) - { - JSValue v = JSImmediate::from(static_cast<double>(i)); - ASSERT(v); - *this = v; - } - - inline JSValue::JSValue(unsigned long long i) - { - JSValue v = JSImmediate::from(static_cast<double>(i)); - ASSERT(v); - *this = v; - } - - inline bool JSValue::isDouble() const - { - return JSImmediate::isDouble(asValue()); - } - - inline double JSValue::asDouble() const - { - return JSImmediate::doubleValue(asValue()); - } - - inline bool JSValue::isNumber() const - { - return JSImmediate::isNumber(asValue()); - } - - inline double JSValue::uncheckedGetNumber() const - { - ASSERT(isNumber()); - return JSImmediate::toDouble(asValue()); - } - -#endif // USE(JSVALUE64) - -#if USE(JSVALUE64) - - inline JSValue::JSValue(char i) - { - ASSERT(JSImmediate::from(i)); - *this = JSImmediate::from(i); - } - - inline JSValue::JSValue(unsigned char i) - { - ASSERT(JSImmediate::from(i)); - *this = JSImmediate::from(i); - } - - inline JSValue::JSValue(short i) - { - ASSERT(JSImmediate::from(i)); - *this = JSImmediate::from(i); - } - - inline JSValue::JSValue(unsigned short i) - { - ASSERT(JSImmediate::from(i)); - *this = JSImmediate::from(i); - } - - inline JSValue jsNaN() - { - return jsNumber(NaN); - } - - // --- JSValue inlines ---------------------------- - - ALWAYS_INLINE JSValue JSValue::toJSNumber(ExecState* exec) const - { - return isNumber() ? asValue() : jsNumber(this->toNumber(exec)); - } - - inline bool JSValue::getNumber(double &result) const - { - if (isInt32()) - result = asInt32(); - else if (LIKELY(isDouble())) - result = asDouble(); - else { - ASSERT(!isNumber()); - return false; - } - return true; - } - -#endif // USE(JSVALUE64) - -} // namespace JSC - -#endif // JSNumberCell_h diff --git a/Source/JavaScriptCore/runtime/JSONObject.cpp b/Source/JavaScriptCore/runtime/JSONObject.cpp index 0f7a576..27fc569 100644 --- a/Source/JavaScriptCore/runtime/JSONObject.cpp +++ b/Source/JavaScriptCore/runtime/JSONObject.cpp @@ -32,6 +32,8 @@ #include "JSArray.h" #include "JSGlobalObject.h" #include "LiteralParser.h" +#include "Local.h" +#include "LocalScope.h" #include "Lookup.h" #include "PropertyNameArray.h" #include "UStringBuilder.h" @@ -51,9 +53,10 @@ static EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*); namespace JSC { -JSONObject::JSONObject(JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure) +JSONObject::JSONObject(JSGlobalObject* globalObject, Structure* structure) : JSObjectWithGlobalObject(globalObject, structure) { + ASSERT(inherits(&s_info)); } // PropertyNameForFunctionCall objects must be on the stack, since the JSValue that they create is not marked. @@ -73,24 +76,22 @@ private: class Stringifier { WTF_MAKE_NONCOPYABLE(Stringifier); public: - Stringifier(ExecState*, JSValue replacer, JSValue space); - ~Stringifier(); - JSValue stringify(JSValue); + Stringifier(ExecState*, const Local<Unknown>& replacer, const Local<Unknown>& space); + Local<Unknown> stringify(Handle<Unknown>); void markAggregate(MarkStack&); private: class Holder { public: - Holder(JSObject*); + Holder(JSGlobalData&, JSObject*); JSObject* object() const { return m_object.get(); } - DeprecatedPtr<JSObject>* objectSlot() { return &m_object; } bool appendNextProperty(Stringifier&, UStringBuilder&); private: - DeprecatedPtr<JSObject> m_object; + Local<JSObject> m_object; const bool m_isArray; bool m_isJSArray; unsigned m_index; @@ -112,16 +113,14 @@ private: void unindent(); void startNewLine(UStringBuilder&) const; - Stringifier* const m_nextStringifierToMark; ExecState* const m_exec; - const JSValue m_replacer; + const Local<Unknown> m_replacer; bool m_usingArrayReplacer; PropertyNameArray m_arrayReplacerPropertyNames; CallType m_replacerCallType; CallData m_replacerCallData; const UString m_gap; - HashSet<JSObject*> m_holderCycleDetector; Vector<Holder, 16> m_holderStack; UString m_repeatedGap; UString m_indent; @@ -134,11 +133,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; } @@ -198,23 +197,20 @@ JSValue PropertyNameForFunctionCall::value(ExecState* exec) const // ------------------------------ Stringifier -------------------------------- -Stringifier::Stringifier(ExecState* exec, JSValue replacer, JSValue space) - : m_nextStringifierToMark(exec->globalData().firstStringifierToMark) - , m_exec(exec) +Stringifier::Stringifier(ExecState* exec, const Local<Unknown>& replacer, const Local<Unknown>& space) + : m_exec(exec) , m_replacer(replacer) , m_usingArrayReplacer(false) , m_arrayReplacerPropertyNames(exec) , m_replacerCallType(CallTypeNone) - , m_gap(gap(exec, space)) + , m_gap(gap(exec, space.get())) { - exec->globalData().firstStringifierToMark = this; - if (!m_replacer.isObject()) return; - if (asObject(m_replacer)->inherits(&JSArray::info)) { + if (m_replacer.asObject()->inherits(&JSArray::s_info)) { m_usingArrayReplacer = true; - JSObject* array = asObject(m_replacer); + Handle<JSObject> array = m_replacer.asObject(); unsigned length = array->get(exec, exec->globalData().propertyNames->length).toUInt32(exec); for (unsigned i = 0; i < length; ++i) { JSValue name = array->get(exec, i); @@ -234,7 +230,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()) @@ -245,40 +241,25 @@ Stringifier::Stringifier(ExecState* exec, JSValue replacer, JSValue space) return; } - m_replacerCallType = asObject(m_replacer)->getCallData(m_replacerCallData); -} - -Stringifier::~Stringifier() -{ - ASSERT(m_exec->globalData().firstStringifierToMark == this); - m_exec->globalData().firstStringifierToMark = m_nextStringifierToMark; -} - -void Stringifier::markAggregate(MarkStack& markStack) -{ - for (Stringifier* stringifier = this; stringifier; stringifier = stringifier->m_nextStringifierToMark) { - size_t size = m_holderStack.size(); - for (size_t i = 0; i < size; ++i) - markStack.append(m_holderStack[i].objectSlot()); - } + m_replacerCallType = m_replacer.asObject()->getCallData(m_replacerCallData); } -JSValue Stringifier::stringify(JSValue value) +Local<Unknown> Stringifier::stringify(Handle<Unknown> value) { JSObject* object = constructEmptyObject(m_exec); if (m_exec->hadException()) - return jsNull(); + return Local<Unknown>(m_exec->globalData(), jsNull()); PropertyNameForFunctionCall emptyPropertyName(m_exec->globalData().propertyNames->emptyIdentifier); - object->putDirect(m_exec->globalData(), m_exec->globalData().propertyNames->emptyIdentifier, value); + object->putDirect(m_exec->globalData(), m_exec->globalData().propertyNames->emptyIdentifier, value.get()); UStringBuilder result; - if (appendStringifiedValue(result, value, object, emptyPropertyName) != StringifySucceeded) - return jsUndefined(); + if (appendStringifiedValue(result, value.get(), object, emptyPropertyName) != StringifySucceeded) + return Local<Unknown>(m_exec->globalData(), jsUndefined()); if (m_exec->hadException()) - return jsNull(); + return Local<Unknown>(m_exec->globalData(), jsNull()); - return jsString(m_exec, result.toUString()); + return Local<Unknown>(m_exec->globalData(), jsString(m_exec, result.toUString())); } void Stringifier::appendQuotedString(UStringBuilder& builder, const UString& value) @@ -371,12 +352,12 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(UStringBuilder& if (m_replacerCallType != CallTypeNone) { JSValue list[] = { propertyName.value(m_exec), value }; ArgList args(list, WTF_ARRAY_LENGTH(list)); - value = call(m_exec, m_replacer, m_replacerCallType, m_replacerCallData, holder, args); + value = call(m_exec, m_replacer.get(), m_replacerCallType, m_replacerCallData, holder, args); if (m_exec->hadException()) return StringifyFailed; } - if (value.isUndefined() && !holder->inherits(&JSArray::info)) + if (value.isUndefined() && !holder->inherits(&JSArray::s_info)) return StringifyFailedDueToUndefinedValue; if (value.isNull()) { @@ -416,7 +397,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; } @@ -424,12 +405,14 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(UStringBuilder& } // Handle cycle detection, and put the holder on the stack. - if (!m_holderCycleDetector.add(object).second) { - throwError(m_exec, createTypeError(m_exec, "JSON.stringify cannot serialize cyclic structures.")); - return StringifyFailed; + for (unsigned i = 0; i < m_holderStack.size(); i++) { + if (m_holderStack[i].object() == object) { + throwError(m_exec, createTypeError(m_exec, "JSON.stringify cannot serialize cyclic structures.")); + return StringifyFailed; + } } bool holderStackWasEmpty = m_holderStack.isEmpty(); - m_holderStack.append(object); + m_holderStack.append(Holder(m_exec->globalData(), object)); if (!holderStackWasEmpty) return StringifySucceeded; @@ -449,7 +432,6 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(UStringBuilder& tickCount = localTimeoutChecker.ticksUntilNextCheck(); } } - m_holderCycleDetector.remove(m_holderStack.last().object()); m_holderStack.removeLast(); } while (!m_holderStack.isEmpty()); return StringifySucceeded; @@ -484,9 +466,9 @@ inline void Stringifier::startNewLine(UStringBuilder& builder) const builder.append(m_indent); } -inline Stringifier::Holder::Holder(JSObject* object) - : m_object(object) - , m_isArray(object->inherits(&JSArray::info)) +inline Stringifier::Holder::Holder(JSGlobalData& globalData, JSObject* object) + : m_object(globalData, object) + , m_isArray(object->inherits(&JSArray::s_info)) , m_index(0) { } @@ -601,7 +583,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 @@ -622,16 +604,11 @@ bool JSONObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& pro return getStaticFunctionDescriptor<JSObject>(exec, ExecState::jsonTable(exec), this, propertyName, descriptor); } -void JSONObject::markStringifiers(MarkStack& markStack, Stringifier* stringifier) -{ - stringifier->markAggregate(markStack); -} - class Walker { public: - Walker(ExecState* exec, JSObject* function, CallType callType, CallData callData) + Walker(ExecState* exec, Handle<JSObject> function, CallType callType, CallData callData) : m_exec(exec) - , m_function(function) + , m_function(exec->globalData(), function) , m_callType(callType) , m_callData(callData) { @@ -648,7 +625,7 @@ private: friend class Holder; ExecState* m_exec; - DeprecatedPtr<JSObject> m_function; + Local<JSObject> m_function; CallType m_callType; CallData m_callData; }; @@ -662,8 +639,8 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) { Vector<PropertyNameArray, 16> propertyStack; Vector<uint32_t, 16> indexStack; - Vector<JSObject*, 16> objectStack; - Vector<JSArray*, 16> arrayStack; + LocalStack<JSObject, 16> objectStack(m_exec->globalData()); + LocalStack<JSArray, 16> arrayStack(m_exec->globalData()); Vector<WalkerState, 16> stateStack; WalkerState state = StateUnknown; @@ -678,12 +655,12 @@ 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)); JSArray* array = asArray(inValue); - arrayStack.append(array); + arrayStack.push(array); indexStack.append(0); // fallthrough } @@ -695,11 +672,11 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) tickCount = localTimeoutChecker.ticksUntilNextCheck(); } - JSArray* array = arrayStack.last(); + JSArray* array = arrayStack.peek(); uint32_t index = indexStack.last(); if (index == array->length()) { outValue = array; - arrayStack.removeLast(); + arrayStack.pop(); indexStack.removeLast(); break; } @@ -721,7 +698,7 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) // fallthrough } case ArrayEndVisitMember: { - JSArray* array = arrayStack.last(); + JSArray* array = arrayStack.peek(); JSValue filteredValue = callReviver(array, jsString(m_exec, UString::number(indexStack.last())), outValue); if (filteredValue.isUndefined()) array->deleteProperty(m_exec, indexStack.last()); @@ -739,12 +716,12 @@ 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)); JSObject* object = asObject(inValue); - objectStack.append(object); + objectStack.push(object); indexStack.append(0); propertyStack.append(PropertyNameArray(m_exec)); object->getOwnPropertyNames(m_exec, propertyStack.last()); @@ -758,12 +735,12 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) tickCount = localTimeoutChecker.ticksUntilNextCheck(); } - JSObject* object = objectStack.last(); + JSObject* object = objectStack.peek(); uint32_t index = indexStack.last(); PropertyNameArray& properties = propertyStack.last(); if (index == properties.size()) { outValue = object; - objectStack.removeLast(); + objectStack.pop(); indexStack.removeLast(); propertyStack.removeLast(); break; @@ -786,7 +763,7 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) // fallthrough } case ObjectEndVisitMember: { - JSObject* object = objectStack.last(); + JSObject* object = objectStack.peek(); Identifier prop = propertyStack.last()[indexStack.last()]; PutPropertySlot slot; JSValue filteredValue = callReviver(object, jsString(m_exec, prop.ustring()), outValue); @@ -806,7 +783,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; } @@ -837,7 +814,8 @@ EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState* exec) UString source = value.toString(exec); if (exec->hadException()) return JSValue::encode(jsNull()); - + + LocalScope scope(exec->globalData()); LiteralParser jsonParser(exec, source, LiteralParser::StrictJSON); JSValue unfiltered = jsonParser.tryLiteralParse(); if (!unfiltered) @@ -851,7 +829,7 @@ EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState* exec) CallType callType = getCallData(function, callData); if (callType == CallTypeNone) return JSValue::encode(unfiltered); - return JSValue::encode(Walker(exec, asObject(function), callType, callData).walk(unfiltered)); + return JSValue::encode(Walker(exec, Local<JSObject>(exec->globalData(), asObject(function)), callType, callData).walk(unfiltered)); } // ECMA-262 v5 15.12.3 @@ -859,15 +837,17 @@ EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState* exec) { if (!exec->argumentCount()) return throwVMError(exec, createError(exec, "No input to stringify")); - JSValue value = exec->argument(0); - JSValue replacer = exec->argument(1); - JSValue space = exec->argument(2); - return JSValue::encode(Stringifier(exec, replacer, space).stringify(value)); + LocalScope scope(exec->globalData()); + Local<Unknown> value(exec->globalData(), exec->argument(0)); + Local<Unknown> replacer(exec->globalData(), exec->argument(1)); + Local<Unknown> space(exec->globalData(), exec->argument(2)); + return JSValue::encode(Stringifier(exec, replacer, space).stringify(value).get()); } UString JSONStringify(ExecState* exec, JSValue value, unsigned indent) { - JSValue result = Stringifier(exec, jsNull(), jsNumber(indent)).stringify(value); + LocalScope scope(exec->globalData()); + Local<Unknown> result = Stringifier(exec, Local<Unknown>(exec->globalData(), jsNull()), Local<Unknown>(exec->globalData(), jsNumber(indent))).stringify(Local<Unknown>(exec->globalData(), value)); if (result.isUndefinedOrNull()) return UString(); return result.getString(exec); diff --git a/Source/JavaScriptCore/runtime/JSONObject.h b/Source/JavaScriptCore/runtime/JSONObject.h index f64be12..c87c641 100644 --- a/Source/JavaScriptCore/runtime/JSONObject.h +++ b/Source/JavaScriptCore/runtime/JSONObject.h @@ -34,15 +34,13 @@ namespace JSC { class JSONObject : public JSObjectWithGlobalObject { public: - JSONObject(JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure); + JSONObject(JSGlobalObject*, Structure*); - static PassRefPtr<Structure> createStructure(JSValue prototype) + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } - static void markStringifiers(MarkStack&, Stringifier*); - protected: static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSObject::StructureFlags; @@ -50,8 +48,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..9677f23 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_FITS_IN_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) @@ -106,7 +109,7 @@ void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue valu // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla. if (!value.isObject() && !value.isNull()) return; - if (!setPrototypeWithCycleCheck(value)) + if (!setPrototypeWithCycleCheck(exec->globalData(), value)) throwError(exec, createError(exec, "cyclic __proto__ value")); return; } @@ -124,14 +127,14 @@ void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue valu unsigned attributes; JSCell* specificValue; - if ((m_structure->get(propertyName, attributes, specificValue) != WTF::notFound) && attributes & ReadOnly) { + if ((m_structure->get(exec->globalData(), propertyName, attributes, specificValue) != WTF::notFound) && attributes & ReadOnly) { if (slot.isStrictMode()) throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError)); return; } for (JSObject* obj = this; ; obj = asObject(prototype)) { - if (JSValue gs = obj->getDirect(propertyName)) { + if (JSValue gs = obj->getDirect(exec->globalData(), propertyName)) { if (gs.isGetterSetter()) { JSObject* setterFunc = asGetterSetter(gs)->setter(); if (!setterFunc) { @@ -215,10 +218,10 @@ bool JSObject::deleteProperty(ExecState* exec, const Identifier& propertyName) { unsigned attributes; JSCell* specificValue; - if (m_structure->get(propertyName, attributes, specificValue) != WTF::notFound) { + if (m_structure->get(exec->globalData(), propertyName, attributes, specificValue) != WTF::notFound) { if ((attributes & DontDelete)) return false; - removeDirect(propertyName); + removeDirect(exec->globalData(), propertyName); return true; } @@ -309,34 +312,33 @@ const HashEntry* JSObject::findPropertyHashEntry(ExecState* exec, const Identifi void JSObject::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes) { - JSValue object = getDirect(propertyName); + JSValue object = getDirect(exec->globalData(), propertyName); if (object && object.isGetterSetter()) { ASSERT(m_structure->hasGetterSetterProperties()); asGetterSetter(object)->setGetter(exec->globalData(), getterFunction); return; } + JSGlobalData& globalData = exec->globalData(); PutPropertySlot slot; GetterSetter* getterSetter = new (exec) GetterSetter(exec); - putDirectInternal(exec->globalData(), propertyName, getterSetter, attributes | Getter, true, slot); + putDirectInternal(globalData, propertyName, getterSetter, attributes | Getter, true, slot); // putDirect will change our Structure if we add a new property. For // getters and setters, though, we also need to change our Structure // if we override an existing non-getter or non-setter. if (slot.type() != PutPropertySlot::NewProperty) { - if (!m_structure->isDictionary()) { - RefPtr<Structure> structure = Structure::getterSetterTransition(m_structure); - setStructure(structure.release()); - } + if (!m_structure->isDictionary()) + setStructure(exec->globalData(), Structure::getterSetterTransition(globalData, m_structure.get())); } m_structure->setHasGetterSetterProperties(true); - getterSetter->setGetter(exec->globalData(), getterFunction); + getterSetter->setGetter(globalData, getterFunction); } void JSObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes) { - JSValue object = getDirect(propertyName); + JSValue object = getDirect(exec->globalData(), propertyName); if (object && object.isGetterSetter()) { ASSERT(m_structure->hasGetterSetterProperties()); asGetterSetter(object)->setSetter(exec->globalData(), setterFunction); @@ -351,21 +353,19 @@ void JSObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSO // getters and setters, though, we also need to change our Structure // if we override an existing non-getter or non-setter. if (slot.type() != PutPropertySlot::NewProperty) { - if (!m_structure->isDictionary()) { - RefPtr<Structure> structure = Structure::getterSetterTransition(m_structure); - setStructure(structure.release()); - } + if (!m_structure->isDictionary()) + setStructure(exec->globalData(), Structure::getterSetterTransition(exec->globalData(), m_structure.get())); } m_structure->setHasGetterSetterProperties(true); getterSetter->setSetter(exec->globalData(), setterFunction); } -JSValue JSObject::lookupGetter(ExecState*, const Identifier& propertyName) +JSValue JSObject::lookupGetter(ExecState* exec, const Identifier& propertyName) { JSObject* object = this; while (true) { - if (JSValue value = object->getDirect(propertyName)) { + if (JSValue value = object->getDirect(exec->globalData(), propertyName)) { if (!value.isGetterSetter()) return jsUndefined(); JSObject* functionObject = asGetterSetter(value)->getter(); @@ -380,11 +380,11 @@ JSValue JSObject::lookupGetter(ExecState*, const Identifier& propertyName) } } -JSValue JSObject::lookupSetter(ExecState*, const Identifier& propertyName) +JSValue JSObject::lookupSetter(ExecState* exec, const Identifier& propertyName) { JSObject* object = this; while (true) { - if (JSValue value = object->getDirect(propertyName)) { + if (JSValue value = object->getDirect(exec->globalData(), propertyName)) { if (!value.isGetterSetter()) return jsUndefined(); JSObject* functionObject = asGetterSetter(value)->setter(); @@ -425,10 +425,10 @@ bool JSObject::propertyIsEnumerable(ExecState* exec, const Identifier& propertyN return descriptor.enumerable(); } -bool JSObject::getPropertySpecificValue(ExecState*, const Identifier& propertyName, JSCell*& specificValue) const +bool JSObject::getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificValue) const { unsigned attributes; - if (m_structure->get(propertyName, attributes, specificValue) != WTF::notFound) + if (m_structure->get(exec->globalData(), propertyName, attributes, specificValue) != WTF::notFound) return true; // This could be a function within the static table? - should probably @@ -461,7 +461,7 @@ void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyName void JSObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { - m_structure->getPropertyNames(propertyNames, mode); + m_structure->getPropertyNames(exec->globalData(), propertyNames, mode); getClassPropertyNames(exec, classInfo(), propertyNames, mode); } @@ -486,7 +486,7 @@ UString JSObject::toString(ExecState* exec) const return primitive.toString(exec); } -JSObject* JSObject::toObject(ExecState*) const +JSObject* JSObject::toObject(ExecState*, JSGlobalObject*) const { return const_cast<JSObject*>(this); } @@ -506,18 +506,33 @@ JSObject* JSObject::unwrappedObject() return this; } -void JSObject::removeDirect(const Identifier& propertyName) +void JSObject::seal(JSGlobalData& globalData) +{ + setStructure(globalData, Structure::sealTransition(globalData, m_structure.get())); +} + +void JSObject::freeze(JSGlobalData& globalData) +{ + setStructure(globalData, Structure::freezeTransition(globalData, m_structure.get())); +} + +void JSObject::preventExtensions(JSGlobalData& globalData) +{ + if (isExtensible()) + setStructure(globalData, Structure::preventExtensionsTransition(globalData, m_structure.get())); +} + +void JSObject::removeDirect(JSGlobalData& globalData, const Identifier& propertyName) { size_t offset; if (m_structure->isUncacheableDictionary()) { - offset = m_structure->removePropertyWithoutTransition(propertyName); + offset = m_structure->removePropertyWithoutTransition(globalData, propertyName); if (offset != WTF::notFound) putUndefinedAtDirectOffset(offset); return; } - RefPtr<Structure> structure = Structure::removePropertyTransition(m_structure, propertyName, offset); - setStructure(structure.release()); + setStructure(globalData, Structure::removePropertyTransition(globalData, m_structure.get(), propertyName, offset)); if (offset != WTF::notFound) putUndefinedAtDirectOffset(offset); } @@ -553,22 +568,38 @@ NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, WriteBarr slot.setUndefined(); } -Structure* JSObject::createInheritorID() +Structure* JSObject::createInheritorID(JSGlobalData& globalData) { - m_inheritorID = JSObject::createStructure(this); + m_inheritorID.set(globalData, this, createEmptyObjectStructure(globalData, this)); + ASSERT(m_inheritorID->isEmpty()); 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<Unknown>[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) +bool JSObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) { unsigned attributes = 0; JSCell* cell = 0; - size_t offset = m_structure->get(propertyName, attributes, cell); + size_t offset = m_structure->get(exec->globalData(), propertyName, attributes, cell); if (offset == WTF::notFound) return false; descriptor.setDescriptor(getDirectOffset(offset), attributes); @@ -627,6 +658,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); @@ -703,18 +740,18 @@ bool JSObject::defineOwnProperty(ExecState* exec, const Identifier& propertyName // Changing the accessor functions of an existing accessor property ASSERT(descriptor.isAccessorDescriptor()); if (!current.configurable()) { - if (descriptor.setterPresent() && !(current.setter() && JSValue::strictEqual(exec, current.setter(), descriptor.setter()))) { + if (descriptor.setterPresent() && !(current.setterPresent() && JSValue::strictEqual(exec, current.setter(), descriptor.setter()))) { if (throwException) throwError(exec, createTypeError(exec, "Attempting to change the setter of an unconfigurable property.")); return false; } - if (descriptor.getterPresent() && !(current.getter() && JSValue::strictEqual(exec, current.getter(), descriptor.getter()))) { + if (descriptor.getterPresent() && !(current.getterPresent() && JSValue::strictEqual(exec, current.getter(), descriptor.getter()))) { if (throwException) throwError(exec, createTypeError(exec, "Attempting to change the getter of an unconfigurable property.")); return false; } } - JSValue accessor = getDirect(propertyName); + JSValue accessor = getDirect(exec->globalData(), propertyName); if (!accessor) return false; GetterSetter* getterSetter = asGetterSetter(accessor); diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h index b79249c..80735f8 100644 --- a/Source/JavaScriptCore/runtime/JSObject.h +++ b/Source/JavaScriptCore/runtime/JSObject.h @@ -29,7 +29,6 @@ #include "Completion.h" #include "CallFrame.h" #include "JSCell.h" -#include "JSNumberCell.h" #include "MarkStack.h" #include "PropertySlot.h" #include "PutPropertySlot.h" @@ -80,8 +79,6 @@ namespace JSC { friend void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot); public: - explicit JSObject(NonNullPassRefPtr<Structure>); - virtual void markChildren(MarkStack&); ALWAYS_INLINE void markChildrenDirect(MarkStack& markStack); @@ -90,11 +87,11 @@ namespace JSC { virtual ~JSObject(); JSValue prototype() const; - void setPrototype(JSValue prototype); - bool setPrototypeWithCycleCheck(JSValue prototype); + void setPrototype(JSGlobalData&, JSValue prototype); + bool setPrototypeWithCycleCheck(JSGlobalData&, JSValue prototype); - void setStructure(NonNullPassRefPtr<Structure>); - Structure* inheritorID(); + void setStructure(JSGlobalData&, Structure*); + Structure* inheritorID(JSGlobalData&); virtual UString className() const; @@ -140,7 +137,7 @@ namespace JSC { virtual bool toBoolean(ExecState*) const; virtual double toNumber(ExecState*) const; virtual UString toString(ExecState*) const; - virtual JSObject* toObject(ExecState*) const; + virtual JSObject* toObject(ExecState*, JSGlobalObject*) const; virtual JSObject* toThisObject(ExecState*) const; virtual JSValue toStrictThisObject(ExecState*) const; @@ -149,22 +146,22 @@ namespace JSC { bool getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificFunction) const; // This get function only looks at the property map. - JSValue getDirect(const Identifier& propertyName) const + JSValue getDirect(JSGlobalData& globalData, const Identifier& propertyName) const { - size_t offset = m_structure->get(propertyName); + size_t offset = m_structure->get(globalData, propertyName); return offset != WTF::notFound ? getDirectOffset(offset) : JSValue(); } - WriteBarrierBase<Unknown>* getDirectLocation(const Identifier& propertyName) + WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, const Identifier& propertyName) { - size_t offset = m_structure->get(propertyName); + size_t offset = m_structure->get(globalData, propertyName); return offset != WTF::notFound ? locationForOffset(offset) : 0; } - WriteBarrierBase<Unknown>* getDirectLocation(const Identifier& propertyName, unsigned& attributes) + WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, const Identifier& propertyName, unsigned& attributes) { JSCell* specificFunction; - size_t offset = m_structure->get(propertyName, attributes, specificFunction); + size_t offset = m_structure->get(globalData, propertyName, attributes, specificFunction); return offset != WTF::notFound ? locationForOffset(offset) : 0; } @@ -173,9 +170,9 @@ namespace JSC { return location - propertyStorage(); } - void transitionTo(Structure*); + void transitionTo(JSGlobalData&, Structure*); - void removeDirect(const Identifier& propertyName); + void removeDirect(JSGlobalData&, const Identifier& propertyName); bool hasCustomProperties() { return !m_structure->isEmpty(); } bool hasGetterSetterProperties() { return m_structure->hasGetterSetterProperties(); } @@ -212,19 +209,19 @@ namespace JSC { virtual bool isStrictModeFunction() const { return false; } virtual bool isErrorInstance() const { return false; } + void seal(JSGlobalData&); + void freeze(JSGlobalData&); + void preventExtensions(JSGlobalData&); + bool isSealed(JSGlobalData& globalData) { return m_structure->isSealed(globalData); } + bool isFrozen(JSGlobalData& globalData) { return m_structure->isFrozen(globalData); } + 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; + bool isUsingInlineStorage() const { return static_cast<const void*>(m_propertyStorage) == static_cast<const void*>(this + 1); } - static PassRefPtr<Structure> createStructure(JSValue prototype) - { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); - } + static const unsigned baseExternalStorageCapacity = 16; void flattenDictionaryObject(JSGlobalData& globalData) { @@ -246,15 +243,33 @@ namespace JSC { ASSERT(index < m_structure->anonymousSlotCount()); return locationForOffset(index)->get(); } + + static size_t offsetOfInlineStorage(); + static JS_EXPORTDATA const ClassInfo s_info; + protected: + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) + { + return Structure::create(globalData, 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(JSGlobalData&, Structure*, PropertyStorage inlineStorage); + JSObject(VPtrStealingHackType, PropertyStorage inlineStorage) + : JSCell(VPtrStealingHack) + , m_propertyStorage(inlineStorage) + { + } + private: // Nobody should ever ask any of these questions on something already known to be a JSObject. using JSCell::isAPIValueWrapper; @@ -265,8 +280,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<Unknown>* locationForOffset(size_t offset) const { @@ -285,16 +300,97 @@ namespace JSC { bool inlineGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const; - Structure* createInheritorID(); - - union { - PropertyStorage m_externalStorage; - WriteBarrierBase<Unknown> m_inlineStorage[inlineStorageCapacity]; - }; + Structure* createInheritorID(JSGlobalData&); - RefPtr<Structure> m_inheritorID; + PropertyStorage m_propertyStorage; + WriteBarrier<Structure> 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 Structure* createStructure(JSGlobalData& globalData, JSValue prototype) + { + return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); + } + + protected: + explicit JSNonFinalObject(VPtrStealingHackType) + : JSObject(VPtrStealingHack, m_inlineStorage) + { + } + explicit JSNonFinalObject(JSGlobalData& globalData, Structure* structure) + : JSObject(globalData, structure, m_inlineStorage) + { + ASSERT(!(OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage) % sizeof(double))); + ASSERT(this->structure()->propertyStorageCapacity() == JSNonFinalObject_inlineStorageCapacity); + } + + private: + WriteBarrierBase<Unknown> 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, Structure* structure) + { + return new (exec) JSFinalObject(exec->globalData(), structure); + } + + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) + { + return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); + } + + private: + explicit JSFinalObject(JSGlobalData& globalData, Structure* structure) + : JSObject(globalData, 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<Unknown> 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, Structure* structure) +{ + return JSFinalObject::create(exec, structure); +} + +inline Structure* createEmptyObjectStructure(JSGlobalData& globalData, JSValue prototype) +{ + return JSFinalObject::createStructure(globalData, prototype); +} + inline JSObject* asObject(JSCell* cell) { ASSERT(cell->isObject()); @@ -306,21 +402,22 @@ inline JSObject* asObject(JSValue value) return asObject(value.asCell()); } -inline JSObject::JSObject(NonNullPassRefPtr<Structure> structure) - : JSCell(structure.releaseRef()) // ~JSObject balances this ref() +inline JSObject::JSObject(JSGlobalData& globalData, Structure* structure, PropertyStorage inlineStorage) + : JSCell(globalData, structure) + , 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); + ASSERT(static_cast<void*>(inlineStorage) == static_cast<void*>(this + 1)); + ASSERT(m_structure->typeInfo().type() == ObjectType); } inline JSObject::~JSObject() { - ASSERT(m_structure); if (!isUsingInlineStorage()) - delete [] m_externalStorage; - m_structure->deref(); + delete [] m_propertyStorage; } inline JSValue JSObject::prototype() const @@ -328,7 +425,7 @@ inline JSValue JSObject::prototype() const return m_structure->storedPrototype(); } -inline bool JSObject::setPrototypeWithCycleCheck(JSValue prototype) +inline bool JSObject::setPrototypeWithCycleCheck(JSGlobalData& globalData, JSValue prototype) { JSValue nextPrototypeValue = prototype; while (nextPrototypeValue && nextPrototypeValue.isObject()) { @@ -337,33 +434,33 @@ inline bool JSObject::setPrototypeWithCycleCheck(JSValue prototype) return false; nextPrototypeValue = nextPrototype->prototype(); } - setPrototype(prototype); + setPrototype(globalData, prototype); return true; } -inline void JSObject::setPrototype(JSValue prototype) +inline void JSObject::setPrototype(JSGlobalData& globalData, JSValue prototype) { ASSERT(prototype); - RefPtr<Structure> newStructure = Structure::changePrototypeTransition(m_structure, prototype); - setStructure(newStructure.release()); + setStructure(globalData, Structure::changePrototypeTransition(globalData, m_structure.get(), prototype)); } -inline void JSObject::setStructure(NonNullPassRefPtr<Structure> structure) +inline void JSObject::setStructure(JSGlobalData& globalData, Structure* structure) { - m_structure->deref(); - m_structure = structure.leakRef(); // ~JSObject balances this ref() + m_structure.set(globalData, this, structure); } -inline Structure* JSObject::inheritorID() +inline Structure* JSObject::inheritorID(JSGlobalData& globalData) { - if (m_inheritorID) + if (m_inheritorID) { + ASSERT(m_inheritorID->isEmpty()); return m_inheritorID.get(); - return createInheritorID(); + } + return createInheritorID(globalData); } inline bool Structure::isUsingInlineStorage() const { - return (propertyStorageCapacity() == JSObject::inlineStorageCapacity); + return propertyStorageCapacity() < JSObject::baseExternalStorageCapacity; } inline bool JSCell::inherits(const ClassInfo* info) const @@ -383,7 +480,7 @@ inline bool JSValue::inherits(const ClassInfo* classInfo) const ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) { - if (WriteBarrierBase<Unknown>* location = getDirectLocation(propertyName)) { + if (WriteBarrierBase<Unknown>* location = getDirectLocation(exec->globalData(), propertyName)) { if (m_structure->hasGetterSetterProperties() && location->isGetterSetter()) fillGetterPropertySlot(slot, location); else @@ -469,12 +566,12 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi if (m_structure->isDictionary()) { unsigned currentAttributes; JSCell* currentSpecificFunction; - size_t offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction); + size_t offset = m_structure->get(globalData, propertyName, currentAttributes, currentSpecificFunction); if (offset != WTF::notFound) { // If there is currently a specific function, and there now either isn't, // or the new value is different, then despecify. if (currentSpecificFunction && (specificFunction != currentSpecificFunction)) - m_structure->despecifyDictionaryFunction(propertyName); + m_structure->despecifyDictionaryFunction(globalData, propertyName); if (checkReadOnly && currentAttributes & ReadOnly) return false; @@ -490,8 +587,11 @@ 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); + offset = m_structure->addPropertyWithoutTransition(globalData, propertyName, attributes, specificFunction); if (currentCapacity != m_structure->propertyStorageCapacity()) allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity()); @@ -505,12 +605,12 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi size_t offset; size_t currentCapacity = m_structure->propertyStorageCapacity(); - if (RefPtr<Structure> structure = Structure::addPropertyTransitionToExistingStructure(m_structure, propertyName, attributes, specificFunction, offset)) { + if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(m_structure.get(), propertyName, attributes, specificFunction, offset)) { if (currentCapacity != structure->propertyStorageCapacity()) allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity()); ASSERT(offset < structure->propertyStorageCapacity()); - setStructure(structure.release()); + setStructure(globalData, structure); putDirectOffset(globalData, offset, value); // This is a new property; transitions with specific values are not currently cachable, // so leave the slot in an uncachable state. @@ -521,7 +621,7 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi unsigned currentAttributes; JSCell* currentSpecificFunction; - offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction); + offset = m_structure->get(globalData, propertyName, currentAttributes, currentSpecificFunction); if (offset != WTF::notFound) { if (checkReadOnly && currentAttributes & ReadOnly) return false; @@ -542,7 +642,7 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi return true; } // case (2) Despecify, fall through to (3). - setStructure(Structure::despecifyFunctionTransition(m_structure, propertyName)); + setStructure(globalData, Structure::despecifyFunctionTransition(globalData, m_structure.get(), propertyName)); } // case (3) set the slot, do the put, return. @@ -551,23 +651,16 @@ 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 = Structure::addPropertyTransition(m_structure, propertyName, attributes, specificFunction, offset); + Structure* structure = Structure::addPropertyTransition(globalData, m_structure.get(), propertyName, attributes, specificFunction, offset); if (currentCapacity != structure->propertyStorageCapacity()) allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity()); ASSERT(offset < structure->propertyStorageCapacity()); - setStructure(structure.release()); + setStructure(globalData, structure); putDirectOffset(globalData, offset, value); // This is a new property; transitions with specific values are not currently cachable, // so leave the slot in an uncachable state. @@ -623,7 +716,7 @@ inline void JSObject::putDirectFunction(JSGlobalData& globalData, const Identifi inline void JSObject::putDirectWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes) { size_t currentCapacity = m_structure->propertyStorageCapacity(); - size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, 0); + size_t offset = m_structure->addPropertyWithoutTransition(globalData, propertyName, attributes, 0); if (currentCapacity != m_structure->propertyStorageCapacity()) allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity()); putDirectOffset(globalData, offset, value); @@ -632,17 +725,17 @@ inline void JSObject::putDirectWithoutTransition(JSGlobalData& globalData, const inline void JSObject::putDirectFunctionWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, JSCell* value, unsigned attributes) { size_t currentCapacity = m_structure->propertyStorageCapacity(); - size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, value); + size_t offset = m_structure->addPropertyWithoutTransition(globalData, propertyName, attributes, value); if (currentCapacity != m_structure->propertyStorageCapacity()) allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity()); putDirectOffset(globalData, offset, value); } -inline void JSObject::transitionTo(Structure* newStructure) +inline void JSObject::transitionTo(JSGlobalData& globalData, Structure* newStructure) { if (m_structure->propertyStorageCapacity() != newStructure->propertyStorageCapacity()) allocatePropertyStorage(m_structure->propertyStorageCapacity(), newStructure->propertyStorageCapacity()); - setStructure(newStructure); + setStructure(globalData, newStructure); } inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const @@ -727,34 +820,15 @@ 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<Unknown>[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); - markStack.append(m_structure->storedPrototypeSlot()); PropertyStorage storage = propertyStorage(); size_t storageSize = m_structure->propertyStorageSize(); markStack.appendValues(storage, storageSize); + if (m_inheritorID) + markStack.append(&m_inheritorID); } // --- JSValue inlines ---------------------------- @@ -776,6 +850,20 @@ inline JSValue JSValue::toStrictThisObject(ExecState* exec) const return asObject(asCell())->toStrictThisObject(exec); } +ALWAYS_INLINE JSObject* Register::function() const +{ + if (!jsValue()) + return 0; + return asObject(jsValue()); +} + +ALWAYS_INLINE Register Register::withCallee(JSObject* callee) +{ + Register r; + r = JSValue(callee); + return r; +} + } // namespace JSC #endif // JSObject_h diff --git a/Source/JavaScriptCore/runtime/JSObjectWithGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSObjectWithGlobalObject.cpp index c16acb1..2b489a2 100644 --- a/Source/JavaScriptCore/runtime/JSObjectWithGlobalObject.cpp +++ b/Source/JavaScriptCore/runtime/JSObjectWithGlobalObject.cpp @@ -30,8 +30,8 @@ namespace JSC { -JSObjectWithGlobalObject::JSObjectWithGlobalObject(JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure) - : JSObject(structure) +JSObjectWithGlobalObject::JSObjectWithGlobalObject(JSGlobalObject* globalObject, Structure* structure) + : JSNonFinalObject(globalObject->globalData(), structure) { COMPILE_ASSERT(AnonymousSlotCount == 1, AnonymousSlotCount_must_be_one); ASSERT(!globalObject || globalObject->isGlobalObject()); @@ -41,9 +41,15 @@ JSObjectWithGlobalObject::JSObjectWithGlobalObject(JSGlobalObject* globalObject, putAnonymousValue(globalObject->globalData(), GlobalObjectSlot, globalObject); } -JSGlobalObject* JSObjectWithGlobalObject::globalObject() const +JSObjectWithGlobalObject::JSObjectWithGlobalObject(JSGlobalData& globalData, JSGlobalObject* globalObject, Structure* structure) + : JSNonFinalObject(globalData, structure) { - return asGlobalObject((getAnonymousValue(GlobalObjectSlot).asCell())); + COMPILE_ASSERT(AnonymousSlotCount == 1, AnonymousSlotCount_must_be_one); + ASSERT(!globalObject || globalObject->isGlobalObject()); + if (!globalObject) + clearAnonymousValue(GlobalObjectSlot); + else + putAnonymousValue(globalData, GlobalObjectSlot, globalObject); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSObjectWithGlobalObject.h b/Source/JavaScriptCore/runtime/JSObjectWithGlobalObject.h index 9416a62..844bcd8 100644 --- a/Source/JavaScriptCore/runtime/JSObjectWithGlobalObject.h +++ b/Source/JavaScriptCore/runtime/JSObjectWithGlobalObject.h @@ -26,26 +26,30 @@ #ifndef JSObjectWithGlobalObject_h #define JSObjectWithGlobalObject_h -#include "JSObject.h" +#include "JSGlobalObject.h" namespace JSC { class JSGlobalObject; -class JSObjectWithGlobalObject : public JSObject { +class JSObjectWithGlobalObject : public JSNonFinalObject { public: - static PassRefPtr<Structure> createStructure(JSValue proto) + static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { - return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } - JSGlobalObject* globalObject() const; + JSGlobalObject* globalObject() const + { + return asGlobalObject((getAnonymousValue(GlobalObjectSlot).asCell())); + } protected: - JSObjectWithGlobalObject(JSGlobalObject*, NonNullPassRefPtr<Structure>); + JSObjectWithGlobalObject(JSGlobalObject*, Structure*); + JSObjectWithGlobalObject(JSGlobalData&, JSGlobalObject*, Structure*); - JSObjectWithGlobalObject(NonNullPassRefPtr<Structure> structure) - : JSObject(structure) + JSObjectWithGlobalObject(VPtrStealingHackType) + : JSNonFinalObject(VPtrStealingHack) { // 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..d5af044 100644 --- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp +++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp @@ -35,9 +35,10 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(JSPropertyNameIterator); +const ClassInfo JSPropertyNameIterator::s_info = { "JSPropertyNameIterator", 0, 0, 0 }; + inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlots) - : JSCell(exec->globalData().propertyNameIteratorStructure.get()) - , m_cachedStructure(0) + : JSCell(exec->globalData(), exec->globalData().propertyNameIteratorStructure.get()) , m_numCacheableSlots(numCacheableSlots) , m_jsStringsSize(propertyNameArrayData->propertyNameVector().size()) , m_jsStrings(adoptArrayPtr(new WriteBarrier<Unknown>[m_jsStringsSize])) @@ -47,12 +48,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() || @@ -77,22 +72,22 @@ JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSObject size_t count = normalizePrototypeChain(exec, o); StructureChain* structureChain = o->structure()->prototypeChain(exec); - RefPtr<Structure>* structure = structureChain->head(); + WriteBarrier<Structure>* structure = structureChain->head(); for (size_t i = 0; i < count; ++i) { if (structure[i]->typeInfo().overridesGetPropertyNames()) return jsPropertyNameIterator; } - jsPropertyNameIterator->setCachedPrototypeChain(structureChain); - jsPropertyNameIterator->setCachedStructure(o->structure()); - o->structure()->setEnumerationCache(jsPropertyNameIterator); + jsPropertyNameIterator->setCachedPrototypeChain(exec->globalData(), structureChain); + jsPropertyNameIterator->setCachedStructure(exec->globalData(), o->structure()); + o->structure()->setEnumerationCache(exec->globalData(), jsPropertyNameIterator); return jsPropertyNameIterator; } JSValue JSPropertyNameIterator::get(ExecState* exec, JSObject* base, size_t i) { JSValue identifier = m_jsStrings[i].get(); - if (m_cachedStructure == base->structure() && m_cachedPrototypeChain == base->structure()->prototypeChain(exec)) + if (m_cachedStructure.get() == base->structure() && m_cachedPrototypeChain.get() == base->structure()->prototypeChain(exec)) return identifier; if (!base->hasProperty(exec, Identifier(exec, asString(identifier)->value(exec)))) @@ -103,6 +98,8 @@ JSValue JSPropertyNameIterator::get(ExecState* exec, JSObject* base, size_t i) void JSPropertyNameIterator::markChildren(MarkStack& markStack) { markStack.appendValues(m_jsStrings.get(), m_jsStringsSize, MayContainNullValues); + if (m_cachedPrototypeChain) + markStack.append(&m_cachedPrototypeChain); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h index cd46243..b857dc0 100644 --- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h +++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h @@ -45,12 +45,10 @@ namespace JSC { public: static JSPropertyNameIterator* create(ExecState*, JSObject*); - static PassRefPtr<Structure> createStructure(JSValue prototype) + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { - return Structure::create(prototype, TypeInfo(CompoundType, OverridesMarkChildren), AnonymousSlotCount); + return Structure::create(globalData, prototype, TypeInfo(CompoundType, OverridesMarkChildren), AnonymousSlotCount, &s_info); } - - virtual ~JSPropertyNameIterator(); virtual bool isPropertyNameIterator() const { return true; } @@ -67,41 +65,42 @@ namespace JSC { JSValue get(ExecState*, JSObject*, size_t i); size_t size() { return m_jsStringsSize; } - void setCachedStructure(Structure* structure) + void setCachedStructure(JSGlobalData& globalData, Structure* structure) { ASSERT(!m_cachedStructure); ASSERT(structure); - m_cachedStructure = structure; + m_cachedStructure.set(globalData, this, structure); } Structure* cachedStructure() { return m_cachedStructure.get(); } - void setCachedPrototypeChain(NonNullPassRefPtr<StructureChain> cachedPrototypeChain) { m_cachedPrototypeChain = cachedPrototypeChain; } + void setCachedPrototypeChain(JSGlobalData& globalData, StructureChain* cachedPrototypeChain) { m_cachedPrototypeChain.set(globalData, this, cachedPrototypeChain); } StructureChain* cachedPrototypeChain() { return m_cachedPrototypeChain.get(); } private: + static const ClassInfo s_info; JSPropertyNameIterator(ExecState*, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlot); - RefPtr<Structure> m_cachedStructure; - RefPtr<StructureChain> m_cachedPrototypeChain; + WriteBarrier<Structure> m_cachedStructure; + WriteBarrier<StructureChain> m_cachedPrototypeChain; uint32_t m_numCacheableSlots; uint32_t m_jsStringsSize; OwnArrayPtr<WriteBarrier<Unknown> > 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, this, enumerationCache); } - inline void Structure::clearEnumerationCache(JSPropertyNameIterator* enumerationCache) + inline JSPropertyNameIterator* Structure::enumerationCache() { - m_enumerationCache.clear(enumerationCache); + return m_enumerationCache.get(); } - inline JSPropertyNameIterator* Structure::enumerationCache() + ALWAYS_INLINE JSPropertyNameIterator* Register::propertyNameIterator() const { - return m_enumerationCache.get(); + return static_cast<JSPropertyNameIterator*>(jsValue().asCell()); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp b/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp index 80b048e..3d4dc7c 100644 --- a/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp +++ b/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp @@ -28,13 +28,12 @@ #include "JSStaticScopeObject.h" namespace JSC { - ASSERT_CLASS_FITS_IN_CELL(JSStaticScopeObject); void JSStaticScopeObject::markChildren(MarkStack& markStack) { JSVariableObject::markChildren(markStack); - markStack.deprecatedAppend(&d()->registerStore); + markStack.append(&m_registerStore); } JSObject* JSStaticScopeObject::toThisObject(ExecState* exec) const @@ -47,17 +46,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(); @@ -68,13 +67,7 @@ bool JSStaticScopeObject::isDynamicScope(bool&) const return false; } -JSStaticScopeObject::~JSStaticScopeObject() -{ - ASSERT(d()); - 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..8c3a249 100644 --- a/Source/JavaScriptCore/runtime/JSStaticScopeObject.h +++ b/Source/JavaScriptCore/runtime/JSStaticScopeObject.h @@ -31,25 +31,14 @@ namespace JSC{ class JSStaticScopeObject : public JSVariableObject { - protected: - using JSVariableObject::JSVariableObjectData; - struct JSStaticScopeObjectData : public JSVariableObjectData { - JSStaticScopeObjectData() - : JSVariableObjectData(&symbolTable, ®isterStore + 1) - { - } - SymbolTable symbolTable; - Register registerStore; - }; - public: JSStaticScopeObject(ExecState* exec, const Identifier& ident, JSValue value, unsigned attributes) - : JSVariableObject(exec->globalData().staticScopeStructure, new JSStaticScopeObjectData()) + : JSVariableObject(exec->globalData(), exec->globalData().staticScopeStructure.get(), &m_symbolTable, reinterpret_cast<Register*>(&m_registerStore + 1)) { - d()->registerStore = value; + m_registerStore.set(exec->globalData(), this, value); symbolTable().add(ident.impl(), SymbolTableEntry(-1, attributes)); } - virtual ~JSStaticScopeObject(); + virtual void markChildren(MarkStack&); bool isDynamicScope(bool& requiresDynamicChecks) const; virtual JSObject* toThisObject(ExecState*) const; @@ -58,13 +47,14 @@ namespace JSC{ virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&); void putWithAttributes(ExecState*, const Identifier&, JSValue, unsigned attributes); - static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); } + static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: static const unsigned StructureFlags = OverridesGetOwnPropertySlot | NeedsThisConversion | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags; private: - JSStaticScopeObjectData* d() { return static_cast<JSStaticScopeObjectData*>(JSVariableObject::d); } + SymbolTable m_symbolTable; + WriteBarrier<Unknown> m_registerStore; }; } diff --git a/Source/JavaScriptCore/runtime/JSString.cpp b/Source/JavaScriptCore/runtime/JSString.cpp index 848c431..d9c4d46 100644 --- a/Source/JavaScriptCore/runtime/JSString.cpp +++ b/Source/JavaScriptCore/runtime/JSString.cpp @@ -152,7 +152,7 @@ JSString* JSString::substringFromRope(ExecState* exec, unsigned substringStart, if (substringLength == 1) { ASSERT(substringFiberCount == 1); UChar c = substringFibers[0].characters()[0]; - if (c <= 0xFF) + if (c <= maxSingleCharacterString) return globalData->smallStrings.singleCharacterString(globalData, c); } if (substringFiberCount == 1) @@ -253,19 +253,19 @@ UString JSString::toString(ExecState* exec) const return value(exec); } -inline StringObject* StringObject::create(ExecState* exec, JSString* string) +inline StringObject* StringObject::create(ExecState* exec, JSGlobalObject* globalObject, JSString* string) { - return new (exec) StringObject(exec->globalData(), exec->lexicalGlobalObject()->stringObjectStructure(), string); + return new (exec) StringObject(exec->globalData(), globalObject->stringObjectStructure(), string); } -JSObject* JSString::toObject(ExecState* exec) const +JSObject* JSString::toObject(ExecState* exec, JSGlobalObject* globalObject) const { - return StringObject::create(exec, const_cast<JSString*>(this)); + return StringObject::create(exec, globalObject, const_cast<JSString*>(this)); } JSObject* JSString::toThisObject(ExecState* exec) const { - return StringObject::create(exec, const_cast<JSString*>(this)); + return StringObject::create(exec, exec->lexicalGlobalObject(), const_cast<JSString*>(this)); } bool JSString::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) diff --git a/Source/JavaScriptCore/runtime/JSString.h b/Source/JavaScriptCore/runtime/JSString.h index 6696404..3422dad 100644 --- a/Source/JavaScriptCore/runtime/JSString.h +++ b/Source/JavaScriptCore/runtime/JSString.h @@ -26,10 +26,10 @@ #include "CallFrame.h" #include "CommonIdentifiers.h" #include "Identifier.h" -#include "JSNumberCell.h" #include "PropertyDescriptor.h" #include "PropertySlot.h" #include "RopeImpl.h" +#include "Structure.h" namespace JSC { @@ -185,7 +185,7 @@ namespace JSC { }; ALWAYS_INLINE JSString(JSGlobalData* globalData, const UString& value) - : JSCell(globalData->stringStructure.get()) + : JSCell(*globalData, globalData->stringStructure.get()) , m_length(value.length()) , m_value(value) , m_fiberCount(0) @@ -196,7 +196,7 @@ namespace JSC { enum HasOtherOwnerType { HasOtherOwner }; JSString(JSGlobalData* globalData, const UString& value, HasOtherOwnerType) - : JSCell(globalData->stringStructure.get()) + : JSCell(*globalData, globalData->stringStructure.get()) , m_length(value.length()) , m_value(value) , m_fiberCount(0) @@ -204,7 +204,7 @@ namespace JSC { ASSERT(!m_value.isNull()); } JSString(JSGlobalData* globalData, PassRefPtr<StringImpl> value, HasOtherOwnerType) - : JSCell(globalData->stringStructure.get()) + : JSCell(*globalData, globalData->stringStructure.get()) , m_length(value->length()) , m_value(value) , m_fiberCount(0) @@ -212,7 +212,7 @@ namespace JSC { ASSERT(!m_value.isNull()); } JSString(JSGlobalData* globalData, PassRefPtr<RopeImpl> rope) - : JSCell(globalData->stringStructure.get()) + : JSCell(*globalData, globalData->stringStructure.get()) , m_length(rope->length()) , m_fiberCount(1) { @@ -221,7 +221,7 @@ namespace JSC { // This constructor constructs a new string by concatenating s1 & s2. // This should only be called with fiberCount <= 3. JSString(JSGlobalData* globalData, unsigned fiberCount, JSString* s1, JSString* s2) - : JSCell(globalData->stringStructure.get()) + : JSCell(*globalData, globalData->stringStructure.get()) , m_length(s1->length() + s2->length()) , m_fiberCount(fiberCount) { @@ -234,7 +234,7 @@ namespace JSC { // This constructor constructs a new string by concatenating s1 & s2. // This should only be called with fiberCount <= 3. JSString(JSGlobalData* globalData, unsigned fiberCount, JSString* s1, const UString& u2) - : JSCell(globalData->stringStructure.get()) + : JSCell(*globalData, globalData->stringStructure.get()) , m_length(s1->length() + u2.length()) , m_fiberCount(fiberCount) { @@ -247,7 +247,7 @@ namespace JSC { // This constructor constructs a new string by concatenating s1 & s2. // This should only be called with fiberCount <= 3. JSString(JSGlobalData* globalData, unsigned fiberCount, const UString& u1, JSString* s2) - : JSCell(globalData->stringStructure.get()) + : JSCell(*globalData, globalData->stringStructure.get()) , m_length(u1.length() + s2->length()) , m_fiberCount(fiberCount) { @@ -262,7 +262,7 @@ namespace JSC { // value must require a fiberCount of at least one implies that the length // for each value must be exactly 1! JSString(ExecState* exec, JSValue v1, JSValue v2, JSValue v3) - : JSCell(exec->globalData().stringStructure.get()) + : JSCell(exec->globalData(), exec->globalData().stringStructure.get()) , m_length(0) , m_fiberCount(s_maxInternalRopeLength) { @@ -275,7 +275,7 @@ namespace JSC { // This constructor constructs a new string by concatenating u1 & u2. JSString(JSGlobalData* globalData, const UString& u1, const UString& u2) - : JSCell(globalData->stringStructure.get()) + : JSCell(*globalData, globalData->stringStructure.get()) , m_length(u1.length() + u2.length()) , m_fiberCount(2) { @@ -287,7 +287,7 @@ namespace JSC { // This constructor constructs a new string by concatenating u1, u2 & u3. JSString(JSGlobalData* globalData, const UString& u1, const UString& u2, const UString& u3) - : JSCell(globalData->stringStructure.get()) + : JSCell(*globalData, globalData->stringStructure.get()) , m_length(u1.length() + u2.length() + u3.length()) , m_fiberCount(s_maxInternalRopeLength) { @@ -299,7 +299,7 @@ namespace JSC { } JSString(JSGlobalData* globalData, const UString& value, JSStringFinalizerCallback finalizer, void* context) - : JSCell(globalData->stringStructure.get()) + : JSCell(*globalData, globalData->stringStructure.get()) , m_length(value.length()) , m_value(value) , m_fiberCount(0) @@ -349,12 +349,11 @@ namespace JSC { JSValue replaceCharacter(ExecState*, UChar, const UString& replacement); - static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion), AnonymousSlotCount); } + static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion), AnonymousSlotCount, 0); } private: - enum VPtrStealingHackType { VPtrStealingHack }; JSString(VPtrStealingHackType) - : JSCell(0) + : JSCell(VPtrStealingHack) , m_fiberCount(0) { } @@ -402,7 +401,7 @@ namespace JSC { virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value); virtual bool toBoolean(ExecState*) const; virtual double toNumber(ExecState*) const; - virtual JSObject* toObject(ExecState*) const; + virtual JSObject* toObject(ExecState*, JSGlobalObject*) const; virtual UString toString(ExecState*) const; virtual JSObject* toThisObject(ExecState*) const; @@ -468,7 +467,7 @@ namespace JSC { inline JSString* jsSingleCharacterString(JSGlobalData* globalData, UChar c) { - if (c <= 0xFF) + if (c <= maxSingleCharacterString) return globalData->smallStrings.singleCharacterString(globalData, c); return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(&c, 1))); } @@ -478,7 +477,7 @@ namespace JSC { JSGlobalData* globalData = &exec->globalData(); ASSERT(offset < static_cast<unsigned>(s.length())); UChar c = s.characters()[offset]; - if (c <= 0xFF) + if (c <= maxSingleCharacterString) return globalData->smallStrings.singleCharacterString(globalData, c); return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(StringImpl::create(s.impl(), offset, 1)))); } @@ -513,7 +512,7 @@ namespace JSC { return globalData->smallStrings.emptyString(globalData); if (size == 1) { UChar c = s.characters()[0]; - if (c <= 0xFF) + if (c <= maxSingleCharacterString) return globalData->smallStrings.singleCharacterString(globalData, c); } return fixupVPtr(globalData, new (globalData) JSString(globalData, s)); @@ -521,7 +520,7 @@ namespace JSC { inline JSString* jsStringWithFinalizer(ExecState* exec, const UString& s, JSStringFinalizerCallback callback, void* context) { - ASSERT(s.length() && (s.length() > 1 || s.characters()[0] > 0xFF)); + ASSERT(s.length() && (s.length() > 1 || s.characters()[0] > maxSingleCharacterString)); JSGlobalData* globalData = &exec->globalData(); return fixupVPtr(globalData, new (globalData) JSString(globalData, s, callback, context)); } @@ -548,7 +547,7 @@ namespace JSC { return globalData->smallStrings.emptyString(globalData); if (length == 1) { UChar c = s.characters()[offset]; - if (c <= 0xFF) + if (c <= maxSingleCharacterString) return globalData->smallStrings.singleCharacterString(globalData, c); } return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(StringImpl::create(s.impl(), offset, length)), JSString::HasOtherOwner)); @@ -561,7 +560,7 @@ namespace JSC { return globalData->smallStrings.emptyString(globalData); if (size == 1) { UChar c = s.characters()[0]; - if (c <= 0xFF) + if (c <= maxSingleCharacterString) return globalData->smallStrings.singleCharacterString(globalData, c); } return fixupVPtr(globalData, new (globalData) JSString(globalData, s, JSString::HasOtherOwner)); diff --git a/Source/JavaScriptCore/runtime/JSType.h b/Source/JavaScriptCore/runtime/JSType.h index 882b218..dba03f6 100644 --- a/Source/JavaScriptCore/runtime/JSType.h +++ b/Source/JavaScriptCore/runtime/JSType.h @@ -33,10 +33,11 @@ namespace JSC { NumberType = 3, NullType = 4, StringType = 5, + LeafType = 6, // The CompoundType value must come before any JSType that may have children - CompoundType = 6, - ObjectType = 7, - GetterSetterType = 8 + CompoundType = 7, + ObjectType = 8, + GetterSetterType = 9 }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSTypeInfo.h b/Source/JavaScriptCore/runtime/JSTypeInfo.h index e225bc7..acde81f 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); + ASSERT(type >= CompoundType || !(flags & OverridesMarkChildren)); // 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,22 @@ 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); } + + static ptrdiff_t flagsOffset() + { + return OBJECT_OFFSETOF(TypeInfo, m_flags); + } + + static ptrdiff_t typeOffset() + { + return OBJECT_OFFSETOF(TypeInfo, m_type); + } private: unsigned char m_type; unsigned char m_flags; + unsigned char m_flags2; }; } diff --git a/Source/JavaScriptCore/runtime/JSValue.cpp b/Source/JavaScriptCore/runtime/JSValue.cpp index f4662db..d3ee89e 100644 --- a/Source/JavaScriptCore/runtime/JSValue.cpp +++ b/Source/JavaScriptCore/runtime/JSValue.cpp @@ -54,14 +54,14 @@ double JSValue::toIntegerPreserveNaN(ExecState* exec) const return trunc(toNumber(exec)); } -JSObject* JSValue::toObjectSlowCase(ExecState* exec) const +JSObject* JSValue::toObjectSlowCase(ExecState* exec, JSGlobalObject* globalObject) const { ASSERT(!isCell()); if (isInt32() || isDouble()) - return constructNumber(exec, asValue()); + return constructNumber(exec, globalObject, asValue()); if (isTrue() || isFalse()) - return constructBooleanFromImmediateBoolean(exec, asValue()); + return constructBooleanFromImmediateBoolean(exec, globalObject, asValue()); ASSERT(isUndefinedOrNull()); throwError(exec, createNotAnObjectError(exec, *this)); @@ -73,9 +73,9 @@ JSObject* JSValue::toThisObjectSlowCase(ExecState* exec) const ASSERT(!isCell()); if (isInt32() || isDouble()) - return constructNumber(exec, asValue()); + return constructNumber(exec, exec->lexicalGlobalObject(), asValue()); if (isTrue() || isFalse()) - return constructBooleanFromImmediateBoolean(exec, asValue()); + return constructBooleanFromImmediateBoolean(exec, exec->lexicalGlobalObject(), asValue()); ASSERT(isUndefinedOrNull()); return exec->globalThisValue(); } @@ -84,9 +84,9 @@ JSObject* JSValue::synthesizeObject(ExecState* exec) const { ASSERT(!isCell()); if (isNumber()) - return constructNumber(exec, asValue()); + return constructNumber(exec, exec->lexicalGlobalObject(), asValue()); if (isBoolean()) - return constructBooleanFromImmediateBoolean(exec, asValue()); + return constructBooleanFromImmediateBoolean(exec, exec->lexicalGlobalObject(), asValue()); ASSERT(isUndefinedOrNull()); throwError(exec, createNotAnObjectError(exec, *this)); diff --git a/Source/JavaScriptCore/runtime/JSValue.h b/Source/JavaScriptCore/runtime/JSValue.h index b2e7a51..de50011 100644 --- a/Source/JavaScriptCore/runtime/JSValue.h +++ b/Source/JavaScriptCore/runtime/JSValue.h @@ -30,14 +30,18 @@ #include <wtf/Assertions.h> #include <wtf/HashTraits.h> #include <wtf/MathExtras.h> +#include <wtf/StdLibExtras.h> namespace JSC { + extern const double NaN; + extern const double Inf; + class ExecState; class Identifier; class JSCell; class JSGlobalData; - class JSImmediate; + class JSGlobalObject; class JSObject; class JSString; class PropertySlot; @@ -47,16 +51,37 @@ namespace JSC { struct ClassInfo; struct Instruction; - template <class T> class DeprecatedPtr; template <class T> class WriteBarrierBase; enum PreferredPrimitiveType { NoPreference, PreferNumber, PreferString }; + #if USE(JSVALUE32_64) typedef int64_t EncodedJSValue; #else typedef void* EncodedJSValue; #endif + + union EncodedValueDescriptor { + int64_t asInt64; +#if USE(JSVALUE32_64) + double asDouble; +#elif USE(JSVALUE64) + JSCell* ptr; +#endif + +#if CPU(BIG_ENDIAN) + struct { + int32_t tag; + int32_t payload; + } asBits; +#else + struct { + int32_t payload; + int32_t tag; + } asBits; +#endif + }; double nonInlineNaN(); @@ -72,7 +97,6 @@ namespace JSC { } class JSValue { - friend class JSImmediate; friend struct EncodedJSValueHashTraits; friend class JIT; friend class JITStubs; @@ -81,14 +105,9 @@ namespace JSC { friend class SpecializedThunkJIT; public: - static EncodedJSValue encode(JSValue value); - static JSValue decode(EncodedJSValue ptr); -#if USE(JSVALUE64) - private: - static JSValue makeImmediate(intptr_t value); - intptr_t immediateValue(); - public: -#endif + static EncodedJSValue encode(JSValue); + static JSValue decode(EncodedJSValue); + enum JSNullTag { JSNull }; enum JSUndefinedTag { JSUndefined }; enum JSTrueTag { JSTrue }; @@ -167,6 +186,7 @@ namespace JSC { UString toString(ExecState*) const; UString toPrimitiveString(ExecState*) const; JSObject* toObject(ExecState*) const; + JSObject* toObject(ExecState*, JSGlobalObject*) const; // Integer conversions. double toInteger(ExecState*) const; @@ -215,52 +235,133 @@ namespace JSC { #endif private: - template <class T> JSValue(DeprecatedPtr<T>); template <class T> JSValue(WriteBarrierBase<T>); enum HashTableDeletedValueTag { HashTableDeletedValue }; JSValue(HashTableDeletedValueTag); inline const JSValue asValue() const { return *this; } - JSObject* toObjectSlowCase(ExecState*) const; + JSObject* toObjectSlowCase(ExecState*, JSGlobalObject*) const; JSObject* toThisObjectSlowCase(ExecState*) const; JSObject* synthesizePrototype(ExecState*) const; JSObject* synthesizeObject(ExecState*) const; #if USE(JSVALUE32_64) - enum { NullTag = 0xffffffff }; - enum { UndefinedTag = 0xfffffffe }; - enum { Int32Tag = 0xfffffffd }; - enum { CellTag = 0xfffffffc }; - enum { TrueTag = 0xfffffffb }; - enum { FalseTag = 0xfffffffa }; - enum { EmptyValueTag = 0xfffffff9 }; - enum { DeletedValueTag = 0xfffffff8 }; - + /* + * On 32-bit platforms USE(JSVALUE32_64) should be defined, and we use a NaN-encoded + * form for immediates. + * + * The encoding makes use of unused NaN space in the IEEE754 representation. Any value + * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values + * can encode a 51-bit payload. Hardware produced and C-library payloads typically + * have a payload of zero. We assume that non-zero payloads are available to encode + * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are + * all set represents a NaN with a non-zero payload, we can use this space in the NaN + * ranges to encode other values (however there are also other ranges of NaN space that + * could have been selected). + * + * For JSValues that do not contain a double value, the high 32 bits contain the tag + * values listed in the enums below, which all correspond to NaN-space. In the case of + * cell, integer and bool values the lower 32 bits (the 'payload') contain the pointer + * integer or boolean value; in the case of all other tags the payload is 0. + */ + enum { Int32Tag = 0xffffffff }; + enum { BooleanTag = 0xfffffffe }; + enum { NullTag = 0xfffffffd }; + enum { UndefinedTag = 0xfffffffc }; + enum { CellTag = 0xfffffffb }; + enum { EmptyValueTag = 0xfffffffa }; + enum { DeletedValueTag = 0xfffffff9 }; + enum { LowestTag = DeletedValueTag }; - + uint32_t tag() const; int32_t payload() const; - - union { - EncodedJSValue asEncodedJSValue; - double asDouble; -#if CPU(BIG_ENDIAN) - struct { - int32_t tag; - int32_t payload; - } asBits; -#else - struct { - int32_t payload; - int32_t tag; - } asBits; +#elif USE(JSVALUE64) + /* + * On 64-bit platforms USE(JSVALUE64) should be defined, and we use a NaN-encoded + * form for immediates. + * + * The encoding makes use of unused NaN space in the IEEE754 representation. Any value + * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values + * can encode a 51-bit payload. Hardware produced and C-library payloads typically + * have a payload of zero. We assume that non-zero payloads are available to encode + * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are + * all set represents a NaN with a non-zero payload, we can use this space in the NaN + * ranges to encode other values (however there are also other ranges of NaN space that + * could have been selected). + * + * This range of NaN space is represented by 64-bit numbers begining with the 16-bit + * hex patterns 0xFFFE and 0xFFFF - we rely on the fact that no valid double-precision + * numbers will begin fall in these ranges. + * + * The top 16-bits denote the type of the encoded JSValue: + * + * Pointer { 0000:PPPP:PPPP:PPPP + * / 0001:****:****:**** + * Double { ... + * \ FFFE:****:****:**** + * Integer { FFFF:0000:IIII:IIII + * + * The scheme we have implemented encodes double precision values by performing a + * 64-bit integer addition of the value 2^48 to the number. After this manipulation + * no encoded double-precision value will begin with the pattern 0x0000 or 0xFFFF. + * Values must be decoded by reversing this operation before subsequent floating point + * operations my be peformed. + * + * 32-bit signed integers are marked with the 16-bit tag 0xFFFF. + * + * The tag 0x0000 denotes a pointer, or another form of tagged immediate. Boolean, + * null and undefined values are represented by specific, invalid pointer values: + * + * False: 0x06 + * True: 0x07 + * Undefined: 0x0a + * Null: 0x02 + * + * These values have the following properties: + * - Bit 1 (TagBitTypeOther) is set for all four values, allowing real pointers to be + * quickly distinguished from all immediate values, including these invalid pointers. + * - With bit 3 is masked out (TagBitUndefined) Undefined and Null share the + * same value, allowing null & undefined to be quickly detected. + * + * No valid JSValue will have the bit pattern 0x0, this is used to represent array + * holes, and as a C++ 'no value' result (e.g. JSValue() has an internal value of 0). + */ + + // These values are #defines since using static const integers here is a ~1% regression! + + // This value is 2^48, used to encode doubles such that the encoded value will begin + // with a 16-bit pattern within the range 0x0001..0xFFFE. + #define DoubleEncodeOffset 0x1000000000000ll + // If all bits in the mask are set, this indicates an integer number, + // if any but not all are set this value is a double precision number. + #define TagTypeNumber 0xffff000000000000ll + + // All non-numeric (bool, null, undefined) immediates have bit 2 set. + #define TagBitTypeOther 0x2ll + #define TagBitBool 0x4ll + #define TagBitUndefined 0x8ll + // Combined integer value for non-numeric immediates. + #define ValueFalse (TagBitTypeOther | TagBitBool | false) + #define ValueTrue (TagBitTypeOther | TagBitBool | true) + #define ValueUndefined (TagBitTypeOther | TagBitUndefined) + #define ValueNull (TagBitTypeOther) + + // TagMask is used to check for all types of immediate values (either number or 'other'). + #define TagMask (TagTypeNumber | TagBitTypeOther) + + // These special values are never visible to JavaScript code; Empty is used to represent + // Array holes, and for uninitialized JSValues. Deleted is used in hash table code. + // These values would map to cell types in the JSValue encoding, but not valid GC cell + // pointer should have either of these values (Empty is null, deleted is at an invalid + // alignment for a GC cell, and in the zero page). + #define ValueEmpty 0x0ll + #define ValueDeleted 0x4ll #endif - } u; -#else // USE(JSVALUE32_64) - JSCell* m_ptr; -#endif // USE(JSVALUE32_64) + + EncodedValueDescriptor u; }; #if USE(JSVALUE32_64) @@ -363,412 +464,7 @@ namespace JSC { inline bool operator!=(const JSValue a, const JSCell* b) { return a != JSValue(b); } inline bool operator!=(const JSCell* a, const JSValue b) { return JSValue(a) != b; } - ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const - { - if (isInt32()) - return asInt32(); - return JSC::toInt32(toNumber(exec)); - } - - inline uint32_t JSValue::toUInt32(ExecState* exec) const - { - // See comment on JSC::toUInt32, above. - return toInt32(exec); - } - -#if USE(JSVALUE32_64) - inline JSValue jsNaN() - { - return JSValue(nonInlineNaN()); - } - - // JSValue member functions. - inline EncodedJSValue JSValue::encode(JSValue value) - { - return value.u.asEncodedJSValue; - } - - inline JSValue JSValue::decode(EncodedJSValue encodedJSValue) - { - JSValue v; - v.u.asEncodedJSValue = encodedJSValue; -#if ENABLE(JSC_ZOMBIES) - ASSERT(!v.isZombie()); -#endif - return v; - } - - inline JSValue::JSValue() - { - u.asBits.tag = EmptyValueTag; - u.asBits.payload = 0; - } - - inline JSValue::JSValue(JSNullTag) - { - u.asBits.tag = NullTag; - u.asBits.payload = 0; - } - - inline JSValue::JSValue(JSUndefinedTag) - { - u.asBits.tag = UndefinedTag; - u.asBits.payload = 0; - } - - inline JSValue::JSValue(JSTrueTag) - { - u.asBits.tag = TrueTag; - u.asBits.payload = 0; - } - - inline JSValue::JSValue(JSFalseTag) - { - u.asBits.tag = FalseTag; - u.asBits.payload = 0; - } - - inline JSValue::JSValue(HashTableDeletedValueTag) - { - u.asBits.tag = DeletedValueTag; - u.asBits.payload = 0; - } - - inline JSValue::JSValue(JSCell* ptr) - { - if (ptr) - u.asBits.tag = CellTag; - else - u.asBits.tag = EmptyValueTag; - u.asBits.payload = reinterpret_cast<int32_t>(ptr); -#if ENABLE(JSC_ZOMBIES) - ASSERT(!isZombie()); -#endif - } - - inline JSValue::JSValue(const JSCell* ptr) - { - if (ptr) - u.asBits.tag = CellTag; - else - u.asBits.tag = EmptyValueTag; - u.asBits.payload = reinterpret_cast<int32_t>(const_cast<JSCell*>(ptr)); -#if ENABLE(JSC_ZOMBIES) - ASSERT(!isZombie()); -#endif - } - - inline JSValue::operator bool() const - { - ASSERT(tag() != DeletedValueTag); - return tag() != EmptyValueTag; - } - - inline bool JSValue::operator==(const JSValue& other) const - { - return u.asEncodedJSValue == other.u.asEncodedJSValue; - } - - inline bool JSValue::operator!=(const JSValue& other) const - { - return u.asEncodedJSValue != other.u.asEncodedJSValue; - } - - inline bool JSValue::isUndefined() const - { - return tag() == UndefinedTag; - } - - inline bool JSValue::isNull() const - { - return tag() == NullTag; - } - - inline bool JSValue::isUndefinedOrNull() const - { - return isUndefined() || isNull(); - } - - inline bool JSValue::isCell() const - { - return tag() == CellTag; - } - - inline bool JSValue::isInt32() const - { - return tag() == Int32Tag; - } - - inline bool JSValue::isUInt32() const - { - return tag() == Int32Tag && asInt32() > -1; - } - - inline bool JSValue::isDouble() const - { - return tag() < LowestTag; - } - - inline bool JSValue::isTrue() const - { - return tag() == TrueTag; - } - - inline bool JSValue::isFalse() const - { - return tag() == FalseTag; - } - - inline uint32_t JSValue::tag() const - { - return u.asBits.tag; - } - - inline int32_t JSValue::payload() const - { - return u.asBits.payload; - } - - inline int32_t JSValue::asInt32() const - { - ASSERT(isInt32()); - return u.asBits.payload; - } - - inline uint32_t JSValue::asUInt32() const - { - ASSERT(isUInt32()); - return u.asBits.payload; - } - - inline double JSValue::asDouble() const - { - ASSERT(isDouble()); - return u.asDouble; - } - - ALWAYS_INLINE JSCell* JSValue::asCell() const - { - ASSERT(isCell()); - return reinterpret_cast<JSCell*>(u.asBits.payload); - } - - ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d) - { - u.asDouble = d; - } - - inline JSValue::JSValue(double d) - { - const int32_t asInt32 = static_cast<int32_t>(d); - if (asInt32 != d || (!asInt32 && signbit(d))) { // true for -0.0 - u.asDouble = d; - return; - } - *this = JSValue(static_cast<int32_t>(d)); - } - - inline JSValue::JSValue(char i) - { - *this = JSValue(static_cast<int32_t>(i)); - } - - inline JSValue::JSValue(unsigned char i) - { - *this = JSValue(static_cast<int32_t>(i)); - } - - inline JSValue::JSValue(short i) - { - *this = JSValue(static_cast<int32_t>(i)); - } - - inline JSValue::JSValue(unsigned short i) - { - *this = JSValue(static_cast<int32_t>(i)); - } - - inline JSValue::JSValue(int i) - { - u.asBits.tag = Int32Tag; - u.asBits.payload = i; - } - - inline JSValue::JSValue(unsigned i) - { - if (static_cast<int32_t>(i) < 0) { - *this = JSValue(static_cast<double>(i)); - return; - } - *this = JSValue(static_cast<int32_t>(i)); - } - - inline JSValue::JSValue(long i) - { - if (static_cast<int32_t>(i) != i) { - *this = JSValue(static_cast<double>(i)); - return; - } - *this = JSValue(static_cast<int32_t>(i)); - } - - inline JSValue::JSValue(unsigned long i) - { - if (static_cast<uint32_t>(i) != i) { - *this = JSValue(static_cast<double>(i)); - return; - } - *this = JSValue(static_cast<uint32_t>(i)); - } - - inline JSValue::JSValue(long long i) - { - if (static_cast<int32_t>(i) != i) { - *this = JSValue(static_cast<double>(i)); - return; - } - *this = JSValue(static_cast<int32_t>(i)); - } - - inline JSValue::JSValue(unsigned long long i) - { - if (static_cast<uint32_t>(i) != i) { - *this = JSValue(static_cast<double>(i)); - return; - } - *this = JSValue(static_cast<uint32_t>(i)); - } - - inline bool JSValue::isNumber() const - { - return isInt32() || isDouble(); - } - - inline bool JSValue::isBoolean() const - { - return isTrue() || isFalse(); - } - - inline bool JSValue::getBoolean(bool& v) const - { - if (isTrue()) { - v = true; - return true; - } - if (isFalse()) { - v = false; - return true; - } - - return false; - } - - inline bool JSValue::getBoolean() const - { - ASSERT(isBoolean()); - return tag() == TrueTag; - } - - inline double JSValue::uncheckedGetNumber() const - { - ASSERT(isNumber()); - return isInt32() ? asInt32() : asDouble(); - } - - ALWAYS_INLINE JSValue JSValue::toJSNumber(ExecState* exec) const - { - return isNumber() ? asValue() : jsNumber(this->toNumber(exec)); - } - - inline bool JSValue::getNumber(double& result) const - { - if (isInt32()) { - result = asInt32(); - return true; - } - if (isDouble()) { - result = asDouble(); - return true; - } - return false; - } - -#else // USE(JSVALUE32_64) - - // JSValue member functions. - inline EncodedJSValue JSValue::encode(JSValue value) - { - return reinterpret_cast<EncodedJSValue>(value.m_ptr); - } - - inline JSValue JSValue::decode(EncodedJSValue ptr) - { - return JSValue(reinterpret_cast<JSCell*>(ptr)); - } - - inline JSValue JSValue::makeImmediate(intptr_t value) - { - return JSValue(reinterpret_cast<JSCell*>(value)); - } - - inline intptr_t JSValue::immediateValue() - { - return reinterpret_cast<intptr_t>(m_ptr); - } - - // 0x0 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x0, which is in the (invalid) zero page. - inline JSValue::JSValue() - : m_ptr(0) - { - } - - // 0x4 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x4, which is in the (invalid) zero page. - inline JSValue::JSValue(HashTableDeletedValueTag) - : m_ptr(reinterpret_cast<JSCell*>(0x4)) - { - } - - inline JSValue::JSValue(JSCell* ptr) - : m_ptr(ptr) - { -#if ENABLE(JSC_ZOMBIES) - ASSERT(!isZombie()); -#endif - } - - inline JSValue::JSValue(const JSCell* ptr) - : m_ptr(const_cast<JSCell*>(ptr)) - { -#if ENABLE(JSC_ZOMBIES) - ASSERT(!isZombie()); -#endif - } - - inline JSValue::operator bool() const - { - return m_ptr; - } - - inline bool JSValue::operator==(const JSValue& other) const - { - return m_ptr == other.m_ptr; - } - - inline bool JSValue::operator!=(const JSValue& other) const - { - return m_ptr != other.m_ptr; - } - - inline bool JSValue::isUndefined() const - { - return asValue() == jsUndefined(); - } - - inline bool JSValue::isNull() const - { - return asValue() == jsNull(); - } -#endif // USE(JSVALUE32_64) + bool isZombie(const JSCell*); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSValueInlineMethods.h b/Source/JavaScriptCore/runtime/JSValueInlineMethods.h new file mode 100644 index 0000000..b4f6f80 --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSValueInlineMethods.h @@ -0,0 +1,532 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSValueInlineMethods_h +#define JSValueInlineMethods_h + +#include "JSValue.h" + +namespace JSC { + + ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const + { + if (isInt32()) + return asInt32(); + return JSC::toInt32(toNumber(exec)); + } + + inline uint32_t JSValue::toUInt32(ExecState* exec) const + { + // See comment on JSC::toUInt32, above. + return toInt32(exec); + } + + inline bool JSValue::isUInt32() const + { + return isInt32() && asInt32() >= 0; + } + + inline uint32_t JSValue::asUInt32() const + { + ASSERT(isUInt32()); + return asInt32(); + } + + inline double JSValue::uncheckedGetNumber() const + { + ASSERT(isNumber()); + return isInt32() ? asInt32() : asDouble(); + } + + ALWAYS_INLINE JSValue JSValue::toJSNumber(ExecState* exec) const + { + return isNumber() ? asValue() : jsNumber(this->toNumber(exec)); + } + + inline JSValue jsNaN() + { + return JSValue(nonInlineNaN()); + } + + inline bool JSValue::getNumber(double& result) const + { + if (isInt32()) { + result = asInt32(); + return true; + } + if (isDouble()) { + result = asDouble(); + return true; + } + return false; + } + + inline bool JSValue::getBoolean(bool& v) const + { + if (isTrue()) { + v = true; + return true; + } + if (isFalse()) { + v = false; + return true; + } + + return false; + } + + inline JSValue::JSValue(char i) + { + *this = JSValue(static_cast<int32_t>(i)); + } + + inline JSValue::JSValue(unsigned char i) + { + *this = JSValue(static_cast<int32_t>(i)); + } + + inline JSValue::JSValue(short i) + { + *this = JSValue(static_cast<int32_t>(i)); + } + + inline JSValue::JSValue(unsigned short i) + { + *this = JSValue(static_cast<int32_t>(i)); + } + + inline JSValue::JSValue(unsigned i) + { + if (static_cast<int32_t>(i) < 0) { + *this = JSValue(EncodeAsDouble, static_cast<double>(i)); + return; + } + *this = JSValue(static_cast<int32_t>(i)); + } + + inline JSValue::JSValue(long i) + { + if (static_cast<int32_t>(i) != i) { + *this = JSValue(EncodeAsDouble, static_cast<double>(i)); + return; + } + *this = JSValue(static_cast<int32_t>(i)); + } + + inline JSValue::JSValue(unsigned long i) + { + if (static_cast<uint32_t>(i) != i) { + *this = JSValue(EncodeAsDouble, static_cast<double>(i)); + return; + } + *this = JSValue(static_cast<uint32_t>(i)); + } + + inline JSValue::JSValue(long long i) + { + if (static_cast<int32_t>(i) != i) { + *this = JSValue(EncodeAsDouble, static_cast<double>(i)); + return; + } + *this = JSValue(static_cast<int32_t>(i)); + } + + inline JSValue::JSValue(unsigned long long i) + { + if (static_cast<uint32_t>(i) != i) { + *this = JSValue(EncodeAsDouble, static_cast<double>(i)); + return; + } + *this = JSValue(static_cast<uint32_t>(i)); + } + + inline JSValue::JSValue(double d) + { + const int32_t asInt32 = static_cast<int32_t>(d); + if (asInt32 != d || (!asInt32 && signbit(d))) { // true for -0.0 + *this = JSValue(EncodeAsDouble, d); + return; + } + *this = JSValue(static_cast<int32_t>(d)); + } + +#if USE(JSVALUE32_64) + inline EncodedJSValue JSValue::encode(JSValue value) + { + return value.u.asInt64; + } + + inline JSValue JSValue::decode(EncodedJSValue encodedJSValue) + { + JSValue v; + v.u.asInt64 = encodedJSValue; + return v; + } + + inline JSValue::JSValue() + { + u.asBits.tag = EmptyValueTag; + u.asBits.payload = 0; + } + + inline JSValue::JSValue(JSNullTag) + { + u.asBits.tag = NullTag; + u.asBits.payload = 0; + } + + inline JSValue::JSValue(JSUndefinedTag) + { + u.asBits.tag = UndefinedTag; + u.asBits.payload = 0; + } + + inline JSValue::JSValue(JSTrueTag) + { + u.asBits.tag = BooleanTag; + u.asBits.payload = 1; + } + + inline JSValue::JSValue(JSFalseTag) + { + u.asBits.tag = BooleanTag; + u.asBits.payload = 0; + } + + inline JSValue::JSValue(HashTableDeletedValueTag) + { + u.asBits.tag = DeletedValueTag; + u.asBits.payload = 0; + } + + inline JSValue::JSValue(JSCell* ptr) + { + if (ptr) + u.asBits.tag = CellTag; + else + u.asBits.tag = EmptyValueTag; + u.asBits.payload = reinterpret_cast<int32_t>(ptr); +#if ENABLE(JSC_ZOMBIES) + ASSERT(!isZombie()); +#endif + } + + inline JSValue::JSValue(const JSCell* ptr) + { + if (ptr) + u.asBits.tag = CellTag; + else + u.asBits.tag = EmptyValueTag; + u.asBits.payload = reinterpret_cast<int32_t>(const_cast<JSCell*>(ptr)); +#if ENABLE(JSC_ZOMBIES) + ASSERT(!isZombie()); +#endif + } + + inline JSValue::operator bool() const + { + ASSERT(tag() != DeletedValueTag); + return tag() != EmptyValueTag; + } + + inline bool JSValue::operator==(const JSValue& other) const + { + return u.asInt64 == other.u.asInt64; + } + + inline bool JSValue::operator!=(const JSValue& other) const + { + return u.asInt64 != other.u.asInt64; + } + + inline bool JSValue::isUndefined() const + { + return tag() == UndefinedTag; + } + + inline bool JSValue::isNull() const + { + return tag() == NullTag; + } + + inline bool JSValue::isUndefinedOrNull() const + { + return isUndefined() || isNull(); + } + + inline bool JSValue::isCell() const + { + return tag() == CellTag; + } + + inline bool JSValue::isInt32() const + { + return tag() == Int32Tag; + } + + inline bool JSValue::isDouble() const + { + return tag() < LowestTag; + } + + inline bool JSValue::isTrue() const + { + return tag() == BooleanTag && payload(); + } + + inline bool JSValue::isFalse() const + { + return tag() == BooleanTag && !payload(); + } + + inline uint32_t JSValue::tag() const + { + return u.asBits.tag; + } + + inline int32_t JSValue::payload() const + { + return u.asBits.payload; + } + + inline int32_t JSValue::asInt32() const + { + ASSERT(isInt32()); + return u.asBits.payload; + } + + inline double JSValue::asDouble() const + { + ASSERT(isDouble()); + return u.asDouble; + } + + ALWAYS_INLINE JSCell* JSValue::asCell() const + { + ASSERT(isCell()); + return reinterpret_cast<JSCell*>(u.asBits.payload); + } + + ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d) + { + u.asDouble = d; + } + + inline JSValue::JSValue(int i) + { + u.asBits.tag = Int32Tag; + u.asBits.payload = i; + } + + inline bool JSValue::isNumber() const + { + return isInt32() || isDouble(); + } + + inline bool JSValue::isBoolean() const + { + return isTrue() || isFalse(); + } + + inline bool JSValue::getBoolean() const + { + ASSERT(isBoolean()); + return payload(); + } + +#else // USE(JSVALUE32_64) + + // JSValue member functions. + inline EncodedJSValue JSValue::encode(JSValue value) + { + return value.u.ptr; + } + + inline JSValue JSValue::decode(EncodedJSValue ptr) + { + return JSValue(reinterpret_cast<JSCell*>(ptr)); + } + + // 0x0 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x0, which is in the (invalid) zero page. + inline JSValue::JSValue() + { + u.asInt64 = ValueEmpty; + } + + // 0x4 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x4, which is in the (invalid) zero page. + inline JSValue::JSValue(HashTableDeletedValueTag) + { + u.asInt64 = ValueDeleted; + } + + inline JSValue::JSValue(JSCell* ptr) + { + u.ptr = ptr; +#if ENABLE(JSC_ZOMBIES) + ASSERT(!isZombie()); +#endif + } + + inline JSValue::JSValue(const JSCell* ptr) + { + u.ptr = const_cast<JSCell*>(ptr); +#if ENABLE(JSC_ZOMBIES) + ASSERT(!isZombie()); +#endif + } + + inline JSValue::operator bool() const + { + return u.ptr; + } + + inline bool JSValue::operator==(const JSValue& other) const + { + return u.ptr == other.u.ptr; + } + + inline bool JSValue::operator!=(const JSValue& other) const + { + return u.ptr != other.u.ptr; + } + + inline bool JSValue::isUndefined() const + { + return asValue() == jsUndefined(); + } + + inline bool JSValue::isNull() const + { + return asValue() == jsNull(); + } + + inline bool JSValue::isTrue() const + { + return asValue() == JSValue(JSTrue); + } + + inline bool JSValue::isFalse() const + { + return asValue() == JSValue(JSFalse); + } + + inline bool JSValue::getBoolean() const + { + ASSERT(asValue() == jsBoolean(true) || asValue() == jsBoolean(false)); + return asValue() == jsBoolean(true); + } + + inline int32_t JSValue::asInt32() const + { + ASSERT(isInt32()); + return static_cast<int32_t>(u.asInt64); + } + + inline bool JSValue::isDouble() const + { + return isNumber() && !isInt32(); + } + + inline JSValue::JSValue(JSNullTag) + { + u.asInt64 = ValueNull; + } + + inline JSValue::JSValue(JSUndefinedTag) + { + u.asInt64 = ValueUndefined; + } + + inline JSValue::JSValue(JSTrueTag) + { + u.asInt64 = ValueTrue; + } + + inline JSValue::JSValue(JSFalseTag) + { + u.asInt64 = ValueFalse; + } + + inline bool JSValue::isUndefinedOrNull() const + { + // Undefined and null share the same value, bar the 'undefined' bit in the extended tag. + return (u.asInt64 & ~TagBitUndefined) == ValueNull; + } + + inline bool JSValue::isBoolean() const + { + return (u.asInt64 & ~1) == ValueFalse; + } + + inline bool JSValue::isCell() const + { + return !(u.asInt64 & TagMask); + } + + inline bool JSValue::isInt32() const + { + return (u.asInt64 & TagTypeNumber) == TagTypeNumber; + } + + inline intptr_t reinterpretDoubleToIntptr(double value) + { + return bitwise_cast<intptr_t>(value); + } + inline double reinterpretIntptrToDouble(intptr_t value) + { + return bitwise_cast<double>(value); + } + + ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d) + { + u.asInt64 = reinterpretDoubleToIntptr(d) + DoubleEncodeOffset; + } + + inline JSValue::JSValue(int i) + { + u.asInt64 = TagTypeNumber | static_cast<uint32_t>(i); + } + + inline double JSValue::asDouble() const + { + return reinterpretIntptrToDouble(u.asInt64 - DoubleEncodeOffset); + } + + inline bool JSValue::isNumber() const + { + return u.asInt64 & TagTypeNumber; + } + + ALWAYS_INLINE JSCell* JSValue::asCell() const + { + ASSERT(isCell()); + return u.ptr; + } + +#endif // USE(JSVALUE64) + +} // namespace JSC + +#endif // JSValueInlineMethods_h 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..89bb6b0 100644 --- a/Source/JavaScriptCore/runtime/JSVariableObject.h +++ b/Source/JavaScriptCore/runtime/JSVariableObject.h @@ -40,11 +40,11 @@ namespace JSC { class Register; - class JSVariableObject : public JSObject { + class JSVariableObject : public JSNonFinalObject { friend class JIT; public: - SymbolTable& symbolTable() const { return *d->symbolTable; } + SymbolTable& symbolTable() const { return *m_symbolTable; } virtual void putWithAttributes(ExecState*, const Identifier&, JSValue, unsigned attributes) = 0; @@ -54,58 +54,46 @@ namespace JSC { virtual bool isVariableObject() const; virtual bool isDynamicScope(bool& requiresDynamicChecks) const = 0; - Register& registerAt(int index) const { return d->registers[index]; } + WriteBarrier<Unknown>& registerAt(int index) const { return m_registers[index]; } - static PassRefPtr<Structure> createStructure(JSValue prototype) + WriteBarrier<Unknown>* const * addressOfRegisters() const { return &m_registers; } + + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: static const unsigned StructureFlags = OverridesGetPropertyNames | JSObject::StructureFlags; - // Subclasses of JSVariableObject can subclass this struct to add data - // without increasing their own size (since there's a hard limit on the - // size of a JSCell). - struct JSVariableObjectData { - JSVariableObjectData(SymbolTable* symbolTable, Register* registers) - : symbolTable(symbolTable) - , registers(registers) - { - ASSERT(symbolTable); - } - - SymbolTable* symbolTable; // Maps name -> offset from "r" in register file. - Register* registers; // "r" in the register file. - OwnArrayPtr<Register> registerArray; // Independent copy of registers, used when a variable object copies its registers out of the register file. - - private: - JSVariableObjectData(const JSVariableObjectData&); - JSVariableObjectData& operator=(const JSVariableObjectData&); - }; - - JSVariableObject(NonNullPassRefPtr<Structure> structure, JSVariableObjectData* data) - : JSObject(structure) - , d(data) // Subclass owns this pointer. + + JSVariableObject(JSGlobalData& globalData, Structure* structure, SymbolTable* symbolTable, Register* registers) + : JSNonFinalObject(globalData, structure) + , m_symbolTable(symbolTable) + , m_registers(reinterpret_cast<WriteBarrier<Unknown>*>(registers)) { + ASSERT(m_symbolTable); + COMPILE_ASSERT(sizeof(WriteBarrier<Unknown>) == sizeof(Register), Register_should_be_same_size_as_WriteBarrier); } - PassOwnArrayPtr<Register> copyRegisterArray(Register* src, size_t count); - void setRegisters(Register* registers, PassOwnArrayPtr<Register> registerArray); + PassOwnArrayPtr<WriteBarrier<Unknown> > copyRegisterArray(JSGlobalData&, WriteBarrier<Unknown>* src, size_t count, size_t callframeStarts); + void setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > 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; + SymbolTable* m_symbolTable; // Maps name -> offset from "r" in register file. + WriteBarrier<Unknown>* m_registers; // "r" in the register file. + OwnArrayPtr<WriteBarrier<Unknown> > m_registerArray; // Independent copy of registers, used when a variable object copies its registers out of the register file. }; inline bool JSVariableObject::symbolTableGet(const Identifier& propertyName, PropertySlot& slot) { 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 +103,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 +119,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,23 +133,26 @@ 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<Register> JSVariableObject::copyRegisterArray(Register* src, size_t count) + inline PassOwnArrayPtr<WriteBarrier<Unknown> > JSVariableObject::copyRegisterArray(JSGlobalData& globalData, WriteBarrier<Unknown>* src, size_t count, size_t callframeStarts) { - OwnArrayPtr<Register> registerArray = adoptArrayPtr(new Register[count]); - memcpy(registerArray.get(), src, count * sizeof(Register)); + OwnArrayPtr<WriteBarrier<Unknown> > registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[count]); + for (size_t i = 0; i < callframeStarts; i++) + registerArray[i].set(globalData, this, src[i].get()); + for (size_t i = callframeStarts + RegisterFile::CallFrameHeaderSize; i < count; i++) + registerArray[i].set(globalData, this, src[i].get()); return registerArray.release(); } - inline void JSVariableObject::setRegisters(Register* registers, PassOwnArrayPtr<Register> registerArray) + inline void JSVariableObject::setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray) { - ASSERT(registerArray != d->registerArray); - d->registerArray = registerArray; - d->registers = registers; + ASSERT(registerArray != m_registerArray); + m_registerArray = registerArray; + m_registers = registers; } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSWrapperObject.h b/Source/JavaScriptCore/runtime/JSWrapperObject.h index 0b0d3fd..a7dbe0d 100644 --- a/Source/JavaScriptCore/runtime/JSWrapperObject.h +++ b/Source/JavaScriptCore/runtime/JSWrapperObject.h @@ -28,21 +28,21 @@ 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<Structure>); + explicit JSWrapperObject(JSGlobalData&, Structure*); public: - JSValue internalValue() const { return m_internalValue.get(); } + JSValue internalValue() const; void setInternalValue(JSGlobalData&, JSValue); - static PassRefPtr<Structure> createStructure(JSValue prototype) + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: - static const unsigned AnonymousSlotCount = 1 + JSObject::AnonymousSlotCount; + static const unsigned StructureFlags = OverridesMarkChildren | JSNonFinalObject::StructureFlags; private: virtual void markChildren(MarkStack&); @@ -50,10 +50,14 @@ namespace JSC { WriteBarrier<Unknown> m_internalValue; }; - inline JSWrapperObject::JSWrapperObject(JSGlobalData& globalData, NonNullPassRefPtr<Structure> structure) - : JSObject(structure) + inline JSWrapperObject::JSWrapperObject(JSGlobalData& globalData, Structure* structure) + : JSNonFinalObject(globalData, structure) { - putAnonymousValue(globalData, 0, jsNull()); + } + + inline JSValue JSWrapperObject::internalValue() const + { + return m_internalValue.get(); } inline void JSWrapperObject::setInternalValue(JSGlobalData& globalData, JSValue value) @@ -61,7 +65,6 @@ namespace JSC { ASSERT(value); ASSERT(!value.isObject()); m_internalValue.set(globalData, this, value); - putAnonymousValue(globalData, 0, value); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSZombie.cpp b/Source/JavaScriptCore/runtime/JSZombie.cpp index 8a36bda..efabc93 100644 --- a/Source/JavaScriptCore/runtime/JSZombie.cpp +++ b/Source/JavaScriptCore/runtime/JSZombie.cpp @@ -26,6 +26,8 @@ #include "config.h" #include "JSZombie.h" #include "ClassInfo.h" +#include "JSObject.h" +#include "ScopeChain.h" #if ENABLE(JSC_ZOMBIES) @@ -33,16 +35,6 @@ namespace JSC { const ClassInfo JSZombie::s_info = { "Zombie", 0, 0, 0 }; -Structure* JSZombie::leakedZombieStructure() { - static Structure* structure = 0; - if (!structure) { - Structure::startIgnoringLeaks(); - structure = Structure::create(jsNull(), TypeInfo(UnspecifiedType), 0).leakRef(); - Structure::stopIgnoringLeaks(); - } - return structure; -} - } #endif // ENABLE(JSC_ZOMBIES) diff --git a/Source/JavaScriptCore/runtime/JSZombie.h b/Source/JavaScriptCore/runtime/JSZombie.h index da45699..0559b96 100644 --- a/Source/JavaScriptCore/runtime/JSZombie.h +++ b/Source/JavaScriptCore/runtime/JSZombie.h @@ -27,20 +27,21 @@ #define JSZombie_h #include "JSCell.h" +#include "Structure.h" #if ENABLE(JSC_ZOMBIES) namespace JSC { class JSZombie : public JSCell { public: - JSZombie(const ClassInfo* oldInfo, Structure* structure) - : JSCell(structure) + JSZombie(JSGlobalData& globalData, const ClassInfo* oldInfo, Structure* structure) + : JSCell(globalData, 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; } virtual bool isAPIValueWrapper() 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 Structure* createStructure(JSGlobalData& globalData, JSValue prototype) + { + return Structure::create(globalData, prototype, TypeInfo(LeafType, 0), 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..25b516e 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 { @@ -74,20 +73,20 @@ void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* ASSERT(thisObj->structure()->anonymousSlotCount() > 0); ASSERT(thisObj->getAnonymousValue(0).isCell() && asObject(thisObj->getAnonymousValue(0).asCell())->isGlobalObject()); ASSERT(entry->attributes() & Function); - WriteBarrierBase<Unknown>* location = thisObj->getDirectLocation(propertyName); + WriteBarrierBase<Unknown>* location = thisObj->getDirectLocation(exec->globalData(), 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); + location = thisObj->getDirectLocation(exec->globalData(), propertyName); } slot.setValue(thisObj, location->get(), thisObj->offsetForLocation(location)); diff --git a/Source/JavaScriptCore/runtime/MachineStackMarker.cpp b/Source/JavaScriptCore/runtime/MachineStackMarker.cpp deleted file mode 100644 index 4430947..0000000 --- a/Source/JavaScriptCore/runtime/MachineStackMarker.cpp +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. - * Copyright (C) 2007 Eric Seidel <eric@webkit.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "config.h" -#include "MachineStackMarker.h" - -#include "ConservativeSet.h" -#include "Heap.h" -#include "JSArray.h" -#include "JSGlobalData.h" -#include <setjmp.h> -#include <stdlib.h> - -#if OS(DARWIN) - -#include <mach/mach_init.h> -#include <mach/mach_port.h> -#include <mach/task.h> -#include <mach/thread_act.h> -#include <mach/vm_map.h> - -#elif OS(WINDOWS) - -#include <windows.h> -#include <malloc.h> - -#elif OS(HAIKU) - -#include <OS.h> - -#elif OS(UNIX) - -#include <stdlib.h> -#if !OS(HAIKU) -#include <sys/mman.h> -#endif -#include <unistd.h> - -#if OS(SOLARIS) -#include <thread.h> -#else -#include <pthread.h> -#endif - -#if HAVE(PTHREAD_NP_H) -#include <pthread_np.h> -#endif - -#if OS(QNX) -#include <fcntl.h> -#include <sys/procfs.h> -#include <stdio.h> -#include <errno.h> -#endif - -#endif - -namespace JSC { - -static inline void swapIfBackwards(void*& begin, void*& end) -{ -#if OS(WINCE) - if (begin <= end) - return; - std::swap(begin, end); -#else -UNUSED_PARAM(begin); -UNUSED_PARAM(end); -#endif -} - -#if ENABLE(JSC_MULTIPLE_THREADS) - -#if OS(DARWIN) -typedef mach_port_t PlatformThread; -#elif OS(WINDOWS) -typedef HANDLE PlatformThread; -#endif - -class MachineStackMarker::Thread { -public: - Thread(pthread_t pthread, const PlatformThread& platThread, void* base) - : posixThread(pthread) - , platformThread(platThread) - , stackBase(base) - { - } - - Thread* next; - pthread_t posixThread; - PlatformThread platformThread; - void* stackBase; -}; - -#endif - -MachineStackMarker::MachineStackMarker(Heap* heap) - : m_heap(heap) -#if ENABLE(JSC_MULTIPLE_THREADS) - , m_registeredThreads(0) - , m_currentThreadRegistrar(0) -#endif -{ -} - -MachineStackMarker::~MachineStackMarker() -{ -#if ENABLE(JSC_MULTIPLE_THREADS) - if (m_currentThreadRegistrar) { - int error = pthread_key_delete(m_currentThreadRegistrar); - ASSERT_UNUSED(error, !error); - } - - MutexLocker registeredThreadsLock(m_registeredThreadsMutex); - for (Thread* t = m_registeredThreads; t;) { - Thread* next = t->next; - delete t; - t = next; - } -#endif -} - -#if ENABLE(JSC_MULTIPLE_THREADS) - -static inline PlatformThread getCurrentPlatformThread() -{ -#if OS(DARWIN) - return pthread_mach_thread_np(pthread_self()); -#elif OS(WINDOWS) - return pthread_getw32threadhandle_np(pthread_self()); -#endif -} - -void MachineStackMarker::makeUsableFromMultipleThreads() -{ - if (m_currentThreadRegistrar) - return; - - int error = pthread_key_create(&m_currentThreadRegistrar, unregisterThread); - if (error) - CRASH(); -} - -void MachineStackMarker::registerThread() -{ - ASSERT(!m_heap->globalData()->exclusiveThread || m_heap->globalData()->exclusiveThread == currentThread()); - - if (!m_currentThreadRegistrar || pthread_getspecific(m_currentThreadRegistrar)) - return; - - pthread_setspecific(m_currentThreadRegistrar, this); - Thread* thread = new Thread(pthread_self(), getCurrentPlatformThread(), m_heap->globalData()->stack().origin()); - - MutexLocker lock(m_registeredThreadsMutex); - - thread->next = m_registeredThreads; - m_registeredThreads = thread; -} - -void MachineStackMarker::unregisterThread(void* p) -{ - if (p) - static_cast<MachineStackMarker*>(p)->unregisterThread(); -} - -void MachineStackMarker::unregisterThread() -{ - pthread_t currentPosixThread = pthread_self(); - - MutexLocker lock(m_registeredThreadsMutex); - - if (pthread_equal(currentPosixThread, m_registeredThreads->posixThread)) { - Thread* t = m_registeredThreads; - m_registeredThreads = m_registeredThreads->next; - delete t; - } else { - Thread* last = m_registeredThreads; - Thread* t; - for (t = m_registeredThreads->next; t; t = t->next) { - if (pthread_equal(t->posixThread, currentPosixThread)) { - last->next = t->next; - break; - } - last = t; - } - ASSERT(t); // If t is NULL, we never found ourselves in the list. - delete t; - } -} - -#endif - -void NEVER_INLINE MachineStackMarker::markCurrentThreadConservativelyInternal(ConservativeSet& conservativeSet) -{ - void* begin = m_heap->globalData()->stack().current(); - void* end = m_heap->globalData()->stack().origin(); - swapIfBackwards(begin, end); - conservativeSet.add(begin, end); -} - -#if COMPILER(GCC) -#define REGISTER_BUFFER_ALIGNMENT __attribute__ ((aligned (sizeof(void*)))) -#else -#define REGISTER_BUFFER_ALIGNMENT -#endif - -void MachineStackMarker::markCurrentThreadConservatively(ConservativeSet& conservativeSet) -{ - // setjmp forces volatile registers onto the stack - jmp_buf registers REGISTER_BUFFER_ALIGNMENT; -#if COMPILER(MSVC) -#pragma warning(push) -#pragma warning(disable: 4611) -#endif - setjmp(registers); -#if COMPILER(MSVC) -#pragma warning(pop) -#endif - - markCurrentThreadConservativelyInternal(conservativeSet); -} - -#if ENABLE(JSC_MULTIPLE_THREADS) - -static inline void suspendThread(const PlatformThread& platformThread) -{ -#if OS(DARWIN) - thread_suspend(platformThread); -#elif OS(WINDOWS) - SuspendThread(platformThread); -#else -#error Need a way to suspend threads on this platform -#endif -} - -static inline void resumeThread(const PlatformThread& platformThread) -{ -#if OS(DARWIN) - thread_resume(platformThread); -#elif OS(WINDOWS) - ResumeThread(platformThread); -#else -#error Need a way to resume threads on this platform -#endif -} - -typedef unsigned long usword_t; // word size, assumed to be either 32 or 64 bit - -#if OS(DARWIN) - -#if CPU(X86) -typedef i386_thread_state_t PlatformThreadRegisters; -#elif CPU(X86_64) -typedef x86_thread_state64_t PlatformThreadRegisters; -#elif CPU(PPC) -typedef ppc_thread_state_t PlatformThreadRegisters; -#elif CPU(PPC64) -typedef ppc_thread_state64_t PlatformThreadRegisters; -#elif CPU(ARM) -typedef arm_thread_state_t PlatformThreadRegisters; -#else -#error Unknown Architecture -#endif - -#elif OS(WINDOWS) && CPU(X86) -typedef CONTEXT PlatformThreadRegisters; -#else -#error Need a thread register struct for this platform -#endif - -static size_t getPlatformThreadRegisters(const PlatformThread& platformThread, PlatformThreadRegisters& regs) -{ -#if OS(DARWIN) - -#if CPU(X86) - unsigned user_count = sizeof(regs)/sizeof(int); - thread_state_flavor_t flavor = i386_THREAD_STATE; -#elif CPU(X86_64) - unsigned user_count = x86_THREAD_STATE64_COUNT; - thread_state_flavor_t flavor = x86_THREAD_STATE64; -#elif CPU(PPC) - unsigned user_count = PPC_THREAD_STATE_COUNT; - thread_state_flavor_t flavor = PPC_THREAD_STATE; -#elif CPU(PPC64) - unsigned user_count = PPC_THREAD_STATE64_COUNT; - thread_state_flavor_t flavor = PPC_THREAD_STATE64; -#elif CPU(ARM) - unsigned user_count = ARM_THREAD_STATE_COUNT; - thread_state_flavor_t flavor = ARM_THREAD_STATE; -#else -#error Unknown Architecture -#endif - - kern_return_t result = thread_get_state(platformThread, flavor, (thread_state_t)®s, &user_count); - if (result != KERN_SUCCESS) { - WTFReportFatalError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, - "JavaScript garbage collection failed because thread_get_state returned an error (%d). This is probably the result of running inside Rosetta, which is not supported.", result); - CRASH(); - } - return user_count * sizeof(usword_t); -// end OS(DARWIN) - -#elif OS(WINDOWS) && CPU(X86) - regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS; - GetThreadContext(platformThread, ®s); - return sizeof(CONTEXT); -#else -#error Need a way to get thread registers on this platform -#endif -} - -static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs) -{ -#if OS(DARWIN) - -#if __DARWIN_UNIX03 - -#if CPU(X86) - return reinterpret_cast<void*>(regs.__esp); -#elif CPU(X86_64) - return reinterpret_cast<void*>(regs.__rsp); -#elif CPU(PPC) || CPU(PPC64) - return reinterpret_cast<void*>(regs.__r1); -#elif CPU(ARM) - return reinterpret_cast<void*>(regs.__sp); -#else -#error Unknown Architecture -#endif - -#else // !__DARWIN_UNIX03 - -#if CPU(X86) - return reinterpret_cast<void*>(regs.esp); -#elif CPU(X86_64) - return reinterpret_cast<void*>(regs.rsp); -#elif CPU(PPC) || CPU(PPC64) - return reinterpret_cast<void*>(regs.r1); -#else -#error Unknown Architecture -#endif - -#endif // __DARWIN_UNIX03 - -// end OS(DARWIN) -#elif CPU(X86) && OS(WINDOWS) - return reinterpret_cast<void*>((uintptr_t) regs.Esp); -#else -#error Need a way to get the stack pointer for another thread on this platform -#endif -} - -void MachineStackMarker::markOtherThreadConservatively(ConservativeSet& conservativeSet, Thread* thread) -{ - suspendThread(thread->platformThread); - - PlatformThreadRegisters regs; - size_t regSize = getPlatformThreadRegisters(thread->platformThread, regs); - - // mark the thread's registers - conservativeSet.add(static_cast<void*>(®s), static_cast<void*>(reinterpret_cast<char*>(®s) + regSize)); - - void* stackPointer = otherThreadStackPointer(regs); - void* stackBase = thread->stackBase; - swapIfBackwards(stackPointer, stackBase); - conservativeSet.add(stackPointer, stackBase); - - resumeThread(thread->platformThread); -} - -#endif - -void MachineStackMarker::markMachineStackConservatively(ConservativeSet& conservativeSet) -{ - markCurrentThreadConservatively(conservativeSet); - -#if ENABLE(JSC_MULTIPLE_THREADS) - - if (m_currentThreadRegistrar) { - - MutexLocker lock(m_registeredThreadsMutex); - -#ifndef NDEBUG - // Forbid malloc during the mark phase. Marking a thread suspends it, so - // a malloc inside markChildren() would risk a deadlock with a thread that had been - // suspended while holding the malloc lock. - fastMallocForbid(); -#endif - // It is safe to access the registeredThreads list, because we earlier asserted that locks are being held, - // and since this is a shared heap, they are real locks. - for (Thread* thread = m_registeredThreads; thread; thread = thread->next) { - if (!pthread_equal(thread->posixThread, pthread_self())) - markOtherThreadConservatively(conservativeSet, thread); - } -#ifndef NDEBUG - fastMallocAllow(); -#endif - } -#endif -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/MachineStackMarker.h b/Source/JavaScriptCore/runtime/MachineStackMarker.h deleted file mode 100644 index 8afdb46..0000000 --- a/Source/JavaScriptCore/runtime/MachineStackMarker.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 1999-2000 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. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef MachineStackMarker_h -#define MachineStackMarker_h - -#include <wtf/Noncopyable.h> -#include <wtf/ThreadingPrimitives.h> - -#if ENABLE(JSC_MULTIPLE_THREADS) -#include <pthread.h> -#endif - -namespace JSC { - - class Heap; - class ConservativeSet; - - class MachineStackMarker { - WTF_MAKE_NONCOPYABLE(MachineStackMarker); - public: - MachineStackMarker(Heap*); - ~MachineStackMarker(); - - void markMachineStackConservatively(ConservativeSet&); - -#if ENABLE(JSC_MULTIPLE_THREADS) - void makeUsableFromMultipleThreads(); - void registerThread(); // Only needs to be called by clients that can use the same heap from multiple threads. -#endif - - private: - void markCurrentThreadConservatively(ConservativeSet&); - void markCurrentThreadConservativelyInternal(ConservativeSet&); - -#if ENABLE(JSC_MULTIPLE_THREADS) - class Thread; - - static void unregisterThread(void*); - - void unregisterThread(); - void markOtherThreadConservatively(ConservativeSet&, Thread*); -#endif - - Heap* m_heap; - -#if ENABLE(JSC_MULTIPLE_THREADS) - Mutex m_registeredThreadsMutex; - Thread* m_registeredThreads; - pthread_key_t m_currentThreadRegistrar; -#endif - }; - -} // namespace JSC - -#endif // MachineStackMarker_h diff --git a/Source/JavaScriptCore/runtime/MarkStack.cpp b/Source/JavaScriptCore/runtime/MarkStack.cpp deleted file mode 100644 index a350c35..0000000 --- a/Source/JavaScriptCore/runtime/MarkStack.cpp +++ /dev/null @@ -1,40 +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. - */ - -#include "config.h" -#include "MarkStack.h" - -namespace JSC { - -size_t MarkStack::s_pageSize = 0; - -void MarkStack::compact() -{ - ASSERT(s_pageSize); - m_values.shrinkAllocation(s_pageSize); - m_markSets.shrinkAllocation(s_pageSize); -} - -} diff --git a/Source/JavaScriptCore/runtime/MarkStack.h b/Source/JavaScriptCore/runtime/MarkStack.h deleted file mode 100644 index 0b7941e..0000000 --- a/Source/JavaScriptCore/runtime/MarkStack.h +++ /dev/null @@ -1,202 +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 MarkStack_h -#define MarkStack_h - -#include "JSValue.h" -#include "WriteBarrier.h" -#include <wtf/Vector.h> -#include <wtf/Noncopyable.h> -#include <wtf/OSAllocator.h> - -namespace JSC { - - class JSGlobalData; - class Register; - - enum MarkSetProperties { MayContainNullValues, NoNullValues }; - - class MarkStack { - WTF_MAKE_NONCOPYABLE(MarkStack); - public: - MarkStack(void* jsArrayVPtr) - : m_jsArrayVPtr(jsArrayVPtr) -#if !ASSERT_DISABLED - , m_isCheckingForDefaultMarkViolation(false) - , m_isDraining(false) -#endif - { - } - - void deprecatedAppend(JSValue*); - void deprecatedAppend(JSCell**); - void deprecatedAppend(Register*); - template <typename T> void append(WriteBarrierBase<T>*); - template <typename T> void append(DeprecatedPtr<T>*); - - ALWAYS_INLINE void deprecatedAppendValues(Register* registers, size_t count, MarkSetProperties properties = NoNullValues) - { - JSValue* values = reinterpret_cast<JSValue*>(registers); - if (count) - m_markSets.append(MarkSet(values, values + count, properties)); - } - - void appendValues(WriteBarrierBase<Unknown>* barriers, size_t count, MarkSetProperties properties = NoNullValues) - { - JSValue* values = barriers->slot(); - if (count) - m_markSets.append(MarkSet(values, values + count, properties)); - } - - inline void drain(); - void compact(); - - ~MarkStack() - { - ASSERT(m_markSets.isEmpty()); - ASSERT(m_values.isEmpty()); - } - - private: - void internalAppend(JSCell*); - void internalAppend(JSValue); - void markChildren(JSCell*); - - struct MarkSet { - MarkSet(JSValue* values, JSValue* end, MarkSetProperties properties) - : m_values(values) - , m_end(end) - , m_properties(properties) - { - ASSERT(values); - } - JSValue* m_values; - JSValue* m_end; - MarkSetProperties m_properties; - }; - - static void* allocateStack(size_t size) { return OSAllocator::reserveAndCommit(size); } - static void releaseStack(void* addr, size_t size) { OSAllocator::decommitAndRelease(addr, size); } - - static void initializePagesize(); - static size_t pageSize() - { - if (!s_pageSize) - initializePagesize(); - return s_pageSize; - } - - template <typename T> struct MarkStackArray { - MarkStackArray() - : m_top(0) - , m_allocated(MarkStack::pageSize()) - , m_capacity(m_allocated / sizeof(T)) - { - m_data = reinterpret_cast<T*>(allocateStack(m_allocated)); - } - - ~MarkStackArray() - { - releaseStack(m_data, m_allocated); - } - - void expand() - { - size_t oldAllocation = m_allocated; - m_allocated *= 2; - m_capacity = m_allocated / sizeof(T); - void* newData = allocateStack(m_allocated); - memcpy(newData, m_data, oldAllocation); - releaseStack(m_data, oldAllocation); - m_data = reinterpret_cast<T*>(newData); - } - - inline void append(const T& v) - { - if (m_top == m_capacity) - expand(); - m_data[m_top++] = v; - } - - inline T removeLast() - { - ASSERT(m_top); - return m_data[--m_top]; - } - - inline T& last() - { - ASSERT(m_top); - return m_data[m_top - 1]; - } - - inline bool isEmpty() - { - return m_top == 0; - } - - inline size_t size() { return m_top; } - - inline void shrinkAllocation(size_t size) - { - ASSERT(size <= m_allocated); - ASSERT(0 == (size % MarkStack::pageSize())); - if (size == m_allocated) - return; -#if OS(WINDOWS) || OS(SYMBIAN) || PLATFORM(BREWMP) - // We cannot release a part of a region with VirtualFree. To get around this, - // we'll release the entire region and reallocate the size that we want. - releaseStack(m_data, m_allocated); - m_data = reinterpret_cast<T*>(allocateStack(size)); -#else - releaseStack(reinterpret_cast<char*>(m_data) + size, m_allocated - size); -#endif - m_allocated = size; - m_capacity = m_allocated / sizeof(T); - } - - private: - size_t m_top; - size_t m_allocated; - size_t m_capacity; - T* m_data; - }; - - void* m_jsArrayVPtr; - MarkStackArray<MarkSet> m_markSets; - MarkStackArray<JSCell*> m_values; - static size_t s_pageSize; - -#if !ASSERT_DISABLED - public: - bool m_isCheckingForDefaultMarkViolation; - bool m_isDraining; -#endif - }; - -} - -#endif diff --git a/Source/JavaScriptCore/runtime/MarkStackPosix.cpp b/Source/JavaScriptCore/runtime/MarkStackPosix.cpp deleted file mode 100644 index 2a5b298..0000000 --- a/Source/JavaScriptCore/runtime/MarkStackPosix.cpp +++ /dev/null @@ -1,43 +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. - */ - -#include "config.h" -#include "MarkStack.h" - -#if OS(UNIX) && !OS(SYMBIAN) - -#include <unistd.h> -#include <sys/mman.h> - -namespace JSC { - -void MarkStack::initializePagesize() -{ - MarkStack::s_pageSize = getpagesize(); -} - -} - -#endif diff --git a/Source/JavaScriptCore/runtime/MarkStackSymbian.cpp b/Source/JavaScriptCore/runtime/MarkStackSymbian.cpp deleted file mode 100644 index a3893d7..0000000 --- a/Source/JavaScriptCore/runtime/MarkStackSymbian.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) - - 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 "MarkStack.h" - -#if OS(SYMBIAN) - -#include <e32hal.h> - -namespace JSC { - -void MarkStack::initializePagesize() -{ - TInt page_size; - UserHal::PageSizeInBytes(page_size); - MarkStack::s_pageSize = page_size; -} - -} - -#endif diff --git a/Source/JavaScriptCore/runtime/MarkStackWin.cpp b/Source/JavaScriptCore/runtime/MarkStackWin.cpp deleted file mode 100644 index 2d2a1b3..0000000 --- a/Source/JavaScriptCore/runtime/MarkStackWin.cpp +++ /dev/null @@ -1,44 +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. - */ - -#include "config.h" -#include "MarkStack.h" - -#if OS(WINDOWS) - -#include "windows.h" - -namespace JSC { - -void MarkStack::initializePagesize() -{ - SYSTEM_INFO system_info; - GetSystemInfo(&system_info); - MarkStack::s_pageSize = system_info.dwPageSize; -} - -} - -#endif diff --git a/Source/JavaScriptCore/runtime/MarkedBlock.cpp b/Source/JavaScriptCore/runtime/MarkedBlock.cpp deleted file mode 100644 index 16053f2..0000000 --- a/Source/JavaScriptCore/runtime/MarkedBlock.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2011 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "MarkedBlock.h" - -#include "JSCell.h" - -namespace JSC { - -MarkedBlock* MarkedBlock::create(JSGlobalData* globalData) -{ - PageAllocationAligned allocation = PageAllocationAligned::allocate(BLOCK_SIZE, BLOCK_SIZE, OSAllocator::JSGCHeapPages); - if (!static_cast<bool>(allocation)) - CRASH(); - return new (allocation.base()) MarkedBlock(allocation, globalData); -} - -void MarkedBlock::destroy(MarkedBlock* block) -{ - for (size_t i = 0; i < CELLS_PER_BLOCK; ++i) - reinterpret_cast<JSCell*>(&block->cells[i])->~JSCell(); - block->m_allocation.deallocate(); -} - -MarkedBlock::MarkedBlock(const PageAllocationAligned& allocation, JSGlobalData* globalData) - : m_allocation(allocation) - , m_heap(&globalData->heap) -{ - marked.set(CELLS_PER_BLOCK - 1); - - Structure* dummyMarkableCellStructure = globalData->dummyMarkableCellStructure.get(); - for (size_t i = 0; i < CELLS_PER_BLOCK; ++i) - new (&cells[i]) JSCell(dummyMarkableCellStructure); -} - -void MarkedBlock::sweep() -{ -#if !ENABLE(JSC_ZOMBIES) - Structure* dummyMarkableCellStructure = m_heap->globalData()->dummyMarkableCellStructure.get(); -#endif - - for (size_t i = 0; i < CELLS_PER_BLOCK; ++i) { - if (marked.get(i)) - continue; - - JSCell* cell = reinterpret_cast<JSCell*>(&cells[i]); -#if ENABLE(JSC_ZOMBIES) - if (!cell->isZombie()) { - const ClassInfo* info = cell->classInfo(); - cell->~JSCell(); - new (cell) JSZombie(info, JSZombie::leakedZombieStructure()); - marked.set(i); - } -#else - cell->~JSCell(); - new (cell) JSCell(dummyMarkableCellStructure); -#endif - } -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/MarkedBlock.h b/Source/JavaScriptCore/runtime/MarkedBlock.h deleted file mode 100644 index f726c25..0000000 --- a/Source/JavaScriptCore/runtime/MarkedBlock.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 1999-2000 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. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef MarkedBlock_h -#define MarkedBlock_h - -#include <wtf/Bitmap.h> -#include <wtf/FixedArray.h> -#include <wtf/PageAllocationAligned.h> - -#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<BITS_PER_BLOCK>)) / CELL_SIZE; // Division rounds down intentionally. - - struct CollectorCell { - FixedArray<double, CELL_ARRAY_LENGTH> memory; - }; - - // 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); - - public: - static MarkedBlock* create(JSGlobalData*); - static void destroy(MarkedBlock*); - - static bool isCellAligned(const void*); - static MarkedBlock* blockFor(const void*); - - Heap* heap() const; - - void* allocate(size_t& nextCell); - void sweep(); - - bool isEmpty(); - - void clearMarks(); - size_t markCount(); - size_t size(); - size_t capacity(); - - size_t cellNumber(const void*); - bool isMarked(const void*); - bool testAndSetMarked(const void*); - void setMarked(const void*); - - template <typename Functor> void forEach(Functor&); - - FixedArray<CollectorCell, CELLS_PER_BLOCK> cells; - - private: - MarkedBlock(const PageAllocationAligned&, JSGlobalData*); - - WTF::Bitmap<BITS_PER_BLOCK> marked; - PageAllocationAligned m_allocation; - Heap* m_heap; - }; - - inline bool MarkedBlock::isCellAligned(const void* p) - { - return !((intptr_t)(p) & CELL_MASK); - } - - inline MarkedBlock* MarkedBlock::blockFor(const void* p) - { - return reinterpret_cast<MarkedBlock*>(reinterpret_cast<uintptr_t>(p) & BLOCK_MASK); - } - - inline Heap* MarkedBlock::heap() const - { - return m_heap; - } - - 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; - } - - inline void MarkedBlock::clearMarks() - { - // allocate() assumes that the last mark bit is always set. - marked.clearAll(); - marked.set(CELLS_PER_BLOCK - 1); - } - - inline size_t MarkedBlock::markCount() - { - return marked.count() - 1; // The last mark bit is always set. - } - - inline size_t MarkedBlock::size() - { - return markCount() * CELL_SIZE; - } - - inline size_t MarkedBlock::capacity() - { - return BLOCK_SIZE; - } - - inline size_t MarkedBlock::cellNumber(const void* cell) - { - return (reinterpret_cast<uintptr_t>(cell) & BLOCK_OFFSET_MASK) / CELL_SIZE; - } - - inline bool MarkedBlock::isMarked(const void* cell) - { - return marked.get(cellNumber(cell)); - } - - inline bool MarkedBlock::testAndSetMarked(const void* cell) - { - return marked.testAndSet(cellNumber(cell)); - } - - inline void MarkedBlock::setMarked(const void* cell) - { - marked.set(cellNumber(cell)); - } - - template <typename Functor> 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)) - continue; - functor(reinterpret_cast<JSCell*>(&cells[i])); - } - } - -} // namespace JSC - -#endif // MarkedSpace_h diff --git a/Source/JavaScriptCore/runtime/MarkedSpace.cpp b/Source/JavaScriptCore/runtime/MarkedSpace.cpp deleted file mode 100644 index 2f8075d..0000000 --- a/Source/JavaScriptCore/runtime/MarkedSpace.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. - * Copyright (C) 2007 Eric Seidel <eric@webkit.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "config.h" -#include "MarkedSpace.h" - -#include "JSCell.h" -#include "JSGlobalData.h" -#include "JSLock.h" - -namespace JSC { - -class Structure; - -MarkedSpace::MarkedSpace(JSGlobalData* globalData) - : m_waterMark(0) - , m_highWaterMark(0) - , m_globalData(globalData) -{ - allocateBlock(); -} - -void MarkedSpace::destroy() -{ - clearMarks(); // Make sure weak pointers appear dead during destruction. - - while (m_heap.blocks.size()) - freeBlock(0); - m_heap.blocks.clear(); -} - -NEVER_INLINE MarkedBlock* MarkedSpace::allocateBlock() -{ - MarkedBlock* block = MarkedBlock::create(globalData()); - m_heap.blocks.append(block); - return block; -} - -NEVER_INLINE void MarkedSpace::freeBlock(size_t block) -{ - MarkedBlock::destroy(m_heap.blocks[block]); - - // swap with the last block so we compact as we go - m_heap.blocks[block] = m_heap.blocks.last(); - m_heap.blocks.removeLast(); -} - -void* MarkedSpace::allocate(size_t) -{ - 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)) - 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 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; - } -} - -void MarkedSpace::clearMarks() -{ - for (size_t i = 0; i < m_heap.blocks.size(); ++i) - m_heap.collectorBlock(i)->clearMarks(); -} - -void MarkedSpace::sweep() -{ - for (size_t i = 0; i < m_heap.blocks.size(); ++i) - m_heap.collectorBlock(i)->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(); - 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(); - 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(); - return result; -} - -void MarkedSpace::reset() -{ - m_heap.nextCell = 0; - m_heap.nextBlock = 0; - m_waterMark = 0; -#if ENABLE(JSC_ZOMBIES) - sweep(); -#endif -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/MarkedSpace.h b/Source/JavaScriptCore/runtime/MarkedSpace.h deleted file mode 100644 index fcb93b7..0000000 --- a/Source/JavaScriptCore/runtime/MarkedSpace.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 1999-2000 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. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef MarkedSpace_h -#define MarkedSpace_h - -#include "MachineStackMarker.h" -#include "MarkedBlock.h" -#include "PageAllocationAligned.h" -#include <wtf/Bitmap.h> -#include <wtf/FixedArray.h> -#include <wtf/HashCountedSet.h> -#include <wtf/Noncopyable.h> -#include <wtf/Vector.h> - -namespace JSC { - - class Heap; - class JSCell; - class JSGlobalData; - class LiveObjectIterator; - 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<MarkedBlock*> blocks; - }; - - class MarkedSpace { - WTF_MAKE_NONCOPYABLE(MarkedSpace); - public: - static Heap* heap(JSCell*); - - static bool isMarked(const JSCell*); - static bool testAndSetMarked(const JSCell*); - static void setMarked(const JSCell*); - - MarkedSpace(JSGlobalData*); - void destroy(); - - JSGlobalData* globalData() { return m_globalData; } - - size_t highWaterMark() { return m_highWaterMark; } - void setHighWaterMark(size_t highWaterMark) { m_highWaterMark = highWaterMark; } - - void* allocate(size_t); - - void clearMarks(); - void markRoots(); - void reset(); - void sweep(); - void shrink(); - - size_t size() const; - size_t capacity() const; - size_t objectCount() const; - - bool contains(const void*); - - template<typename Functor> void forEach(Functor&); - - private: - NEVER_INLINE MarkedBlock* allocateBlock(); - NEVER_INLINE void freeBlock(size_t); - - void clearMarks(MarkedBlock*); - - CollectorHeap m_heap; - size_t m_waterMark; - size_t m_highWaterMark; - JSGlobalData* m_globalData; - }; - - inline Heap* MarkedSpace::heap(JSCell* cell) - { - return MarkedBlock::blockFor(cell)->heap(); - } - - inline bool MarkedSpace::isMarked(const JSCell* cell) - { - return MarkedBlock::blockFor(cell)->isMarked(cell); - } - - inline bool MarkedSpace::testAndSetMarked(const JSCell* cell) - { - return MarkedBlock::blockFor(cell)->testAndSetMarked(cell); - } - - inline void MarkedSpace::setMarked(const JSCell* cell) - { - MarkedBlock::blockFor(cell)->setMarked(cell); - } - - inline bool MarkedSpace::contains(const void* x) - { - if (!MarkedBlock::isCellAligned(x)) - return false; - - MarkedBlock* block = MarkedBlock::blockFor(x); - if (!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; - } - - template <typename Functor> inline void MarkedSpace::forEach(Functor& functor) - { - for (size_t i = 0; i < m_heap.blocks.size(); ++i) - m_heap.collectorBlock(i)->forEach(functor); - } - -} // namespace JSC - -#endif // MarkedSpace_h diff --git a/Source/JavaScriptCore/runtime/MathObject.cpp b/Source/JavaScriptCore/runtime/MathObject.cpp index c79316b..52bd76a 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 @@ -86,14 +86,16 @@ const ClassInfo MathObject::info = { "Math", 0, 0, ExecState::mathTable }; @end */ -MathObject::MathObject(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure) +MathObject::MathObject(ExecState* exec, JSGlobalObject* globalObject, Structure* 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..75753be 100644 --- a/Source/JavaScriptCore/runtime/MathObject.h +++ b/Source/JavaScriptCore/runtime/MathObject.h @@ -27,17 +27,16 @@ namespace JSC { class MathObject : public JSObjectWithGlobalObject { public: - MathObject(ExecState*, JSGlobalObject*, NonNullPassRefPtr<Structure>); + MathObject(ExecState*, JSGlobalObject*, Structure*); 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<Structure> createStructure(JSValue prototype) + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: diff --git a/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp b/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp index 421eecf..9cd5dcb 100644 --- a/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp +++ b/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp @@ -30,22 +30,34 @@ 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> structure, NonNullPassRefPtr<Structure> prototypeStructure, const UString& nameAndMessage) +NativeErrorConstructor::NativeErrorConstructor(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, Structure* 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 putDirect(exec->globalData(), exec->propertyNames().prototype, prototype, DontDelete | ReadOnly | DontEnum); - m_errorStructure = ErrorInstance::createStructure(prototype); + m_errorStructure.set(exec->globalData(), this, ErrorInstance::createStructure(exec->globalData(), prototype)); + ASSERT(m_errorStructure); + ASSERT(m_errorStructure->typeInfo().type() == ObjectType); +} + +void NativeErrorConstructor::markChildren(MarkStack& markStack) +{ + InternalFunction::markChildren(markStack); + if (m_errorStructure) + markStack.append(&m_errorStructure); } static EncodedJSValue JSC_HOST_CALL constructWithNativeErrorConstructor(ExecState* exec) { JSValue message = exec->argumentCount() ? exec->argument(0) : jsUndefined(); Structure* errorStructure = static_cast<NativeErrorConstructor*>(exec->callee())->errorStructure(); + ASSERT(errorStructure); return JSValue::encode(ErrorInstance::create(exec, errorStructure, message)); } diff --git a/Source/JavaScriptCore/runtime/NativeErrorConstructor.h b/Source/JavaScriptCore/runtime/NativeErrorConstructor.h index 1ff8207..e96daf6 100644 --- a/Source/JavaScriptCore/runtime/NativeErrorConstructor.h +++ b/Source/JavaScriptCore/runtime/NativeErrorConstructor.h @@ -31,19 +31,24 @@ namespace JSC { class NativeErrorConstructor : public InternalFunction { public: - NativeErrorConstructor(ExecState*, JSGlobalObject*, NonNullPassRefPtr<Structure> structure, NonNullPassRefPtr<Structure> prototypeStructure, const UString&); + NativeErrorConstructor(ExecState*, JSGlobalObject*, Structure*, Structure* prototypeStructure, const UString&); - static const ClassInfo info; + static const ClassInfo s_info; + + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) + { + return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); + } Structure* errorStructure() { return m_errorStructure.get(); } private: + static const unsigned StructureFlags = OverridesMarkChildren | InternalFunction::StructureFlags; virtual ConstructType getConstructData(ConstructData&); virtual CallType getCallData(CallData&); + virtual void markChildren(MarkStack&); - virtual const ClassInfo* classInfo() const { return &info; } - - RefPtr<Structure> m_errorStructure; + WriteBarrier<Structure> m_errorStructure; }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp b/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp index 4e10268..de27d59 100644 --- a/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp +++ b/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp @@ -31,7 +31,7 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(NativeErrorPrototype); -NativeErrorPrototype::NativeErrorPrototype(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, const UString& nameAndMessage, NativeErrorConstructor* constructor) +NativeErrorPrototype::NativeErrorPrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, const UString& nameAndMessage, NativeErrorConstructor* constructor) : JSObjectWithGlobalObject(globalObject, structure) { putDirect(exec->globalData(), exec->propertyNames().name, jsString(exec, nameAndMessage), 0); diff --git a/Source/JavaScriptCore/runtime/NativeErrorPrototype.h b/Source/JavaScriptCore/runtime/NativeErrorPrototype.h index 30690d5..e1b05ce 100644 --- a/Source/JavaScriptCore/runtime/NativeErrorPrototype.h +++ b/Source/JavaScriptCore/runtime/NativeErrorPrototype.h @@ -28,7 +28,7 @@ namespace JSC { class NativeErrorPrototype : public JSObjectWithGlobalObject { public: - NativeErrorPrototype(ExecState*, JSGlobalObject*, NonNullPassRefPtr<Structure>, const UString&, NativeErrorConstructor*); + NativeErrorPrototype(ExecState*, JSGlobalObject*, Structure*, const UString&, NativeErrorConstructor*); }; } // namespace JSC 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..4193f79 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 @@ -54,9 +54,11 @@ const ClassInfo NumberConstructor::info = { "Function", &InternalFunction::info, @end */ -NumberConstructor::NumberConstructor(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, NumberPrototype* numberPrototype) - : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, numberPrototype->info.className)) +NumberConstructor::NumberConstructor(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, NumberPrototype* numberPrototype) + : 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); @@ -102,7 +104,7 @@ static JSValue numberConstructorMinValue(ExecState*, JSValue, const Identifier&) // ECMA 15.7.1 static EncodedJSValue JSC_HOST_CALL constructWithNumberConstructor(ExecState* exec) { - NumberObject* object = new (exec) NumberObject(exec->globalData(), exec->lexicalGlobalObject()->numberObjectStructure()); + NumberObject* object = new (exec) NumberObject(exec->globalData(), asInternalFunction(exec->callee())->globalObject()->numberObjectStructure()); double n = exec->argumentCount() ? exec->argument(0).toNumber(exec) : 0; object->setInternalValue(exec->globalData(), jsNumber(n)); return JSValue::encode(object); diff --git a/Source/JavaScriptCore/runtime/NumberConstructor.h b/Source/JavaScriptCore/runtime/NumberConstructor.h index d8a2593..69aa8a1 100644 --- a/Source/JavaScriptCore/runtime/NumberConstructor.h +++ b/Source/JavaScriptCore/runtime/NumberConstructor.h @@ -29,17 +29,17 @@ namespace JSC { class NumberConstructor : public InternalFunction { public: - NumberConstructor(ExecState*, JSGlobalObject*, NonNullPassRefPtr<Structure>, NumberPrototype*); + NumberConstructor(ExecState*, JSGlobalObject*, Structure*, NumberPrototype*); virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); JSValue getValueProperty(ExecState*, int token) const; - static const ClassInfo info; + static const ClassInfo s_info; - static PassRefPtr<Structure> createStructure(JSValue proto) + static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { - return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, 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..6ee103b 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> structure) +NumberObject::NumberObject(JSGlobalData& globalData, Structure* structure) : JSWrapperObject(globalData, structure) { + ASSERT(inherits(&s_info)); } JSValue NumberObject::getJSNumber() @@ -41,9 +42,9 @@ JSValue NumberObject::getJSNumber() return internalValue(); } -NumberObject* constructNumber(ExecState* exec, JSValue number) +NumberObject* constructNumber(ExecState* exec, JSGlobalObject* globalObject, JSValue number) { - NumberObject* object = new (exec) NumberObject(exec->globalData(), exec->lexicalGlobalObject()->numberObjectStructure()); + NumberObject* object = new (exec) NumberObject(exec->globalData(), globalObject->numberObjectStructure()); object->setInternalValue(exec->globalData(), number); return object; } diff --git a/Source/JavaScriptCore/runtime/NumberObject.h b/Source/JavaScriptCore/runtime/NumberObject.h index 044f490..cba65dd 100644 --- a/Source/JavaScriptCore/runtime/NumberObject.h +++ b/Source/JavaScriptCore/runtime/NumberObject.h @@ -27,25 +27,20 @@ namespace JSC { class NumberObject : public JSWrapperObject { public: - explicit NumberObject(JSGlobalData&, NonNullPassRefPtr<Structure>); + explicit NumberObject(JSGlobalData&, Structure*); - static const ClassInfo info; + static const ClassInfo s_info; - static PassRefPtr<Structure> createStructure(JSValue prototype) + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, 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(); }; - NumberObject* constructNumber(ExecState*, JSValue); + NumberObject* constructNumber(ExecState*, JSGlobalObject*, JSValue); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/NumberPrototype.cpp b/Source/JavaScriptCore/runtime/NumberPrototype.cpp index fbe6992..24532dd 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 <wtf/Assertions.h> #include <wtf/DecimalNumber.h> @@ -46,19 +45,19 @@ static EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState*); // ECMA 15.7.4 -NumberPrototype::NumberPrototype(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) +NumberPrototype::NumberPrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* 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..45bdfe7 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>, Structure* prototypeFunctionStructure); + NumberPrototype(ExecState*, JSGlobalObject*, Structure*, Structure* functionStructure); }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp index f31da67..aed5e24 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,38 +42,71 @@ 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> 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, Structure* 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<JSObject>(exec, ExecState::objectConstructorTable(exec), this, propertyName, slot); +} + +bool ObjectConstructor::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + return getStaticFunctionDescriptor<JSObject>(exec, ExecState::objectConstructorTable(exec), this, propertyName, descriptor); } // ECMA 15.2.2 -static ALWAYS_INLINE JSObject* constructObject(ExecState* exec, const ArgList& args) +static ALWAYS_INLINE JSObject* constructObject(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args) { JSValue arg = args.at(0); if (arg.isUndefinedOrNull()) - return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure()); - return arg.toObject(exec); + return constructEmptyObject(exec, globalObject); + return arg.toObject(exec, globalObject); } static EncodedJSValue JSC_HOST_CALL constructWithObjectConstructor(ExecState* exec) { ArgList args(exec); - return JSValue::encode(constructObject(exec, args)); + return JSValue::encode(constructObject(exec, asInternalFunction(exec->callee())->globalObject(), args)); } ConstructType ObjectConstructor::getConstructData(ConstructData& constructData) @@ -85,7 +118,7 @@ ConstructType ObjectConstructor::getConstructData(ConstructData& constructData) static EncodedJSValue JSC_HOST_CALL callObjectConstructor(ExecState* exec) { ArgList args(exec); - return JSValue::encode(constructObject(exec, args)); + return JSValue::encode(constructObject(exec, asInternalFunction(exec->callee())->globalObject(), args)); } CallType ObjectConstructor::getCallData(CallData& callData) @@ -309,7 +342,7 @@ EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState* exec) if (!exec->argument(0).isObject() && !exec->argument(0).isNull()) return throwVMError(exec, createTypeError(exec, "Object prototype may only be an Object or null.")); JSObject* newObject = constructEmptyObject(exec); - newObject->setPrototype(exec->argument(0)); + newObject->setPrototype(exec->globalData(), exec->argument(0)); if (exec->argument(1).isUndefined()) return JSValue::encode(newObject); if (!exec->argument(1).isObject()) @@ -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(exec->globalData()); + 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(exec->globalData()); + 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(exec->globalData()); + 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(exec->globalData()))); +} + +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(exec->globalData()))); +} + +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..6ebafcd 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<Structure>, ObjectPrototype*, Structure* prototypeFunctionStructure); + ObjectConstructor(ExecState*, JSGlobalObject*, Structure*, ObjectPrototype*); + + virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); + + static const ClassInfo s_info; + + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) + { + return Structure::create(globalData, 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..7469172 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<Structure> stucture, Structure* prototypeFunctionStructure) - : JSObject(stucture) +ObjectPrototype::ObjectPrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* stucture, Structure* functionStructure) + : JSNonFinalObject(exec->globalData(), 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..9fb7fae 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>, Structure* prototypeFunctionStructure); + ObjectPrototype(ExecState*, JSGlobalObject*, Structure*, 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..c102eeb 100644 --- a/Source/JavaScriptCore/runtime/Operations.h +++ b/Source/JavaScriptCore/runtime/Operations.h @@ -24,9 +24,8 @@ #include "ExceptionHelpers.h" #include "Interpreter.h" -#include "JSImmediate.h" -#include "JSNumberCell.h" #include "JSString.h" +#include "JSValueInlineMethods.h" namespace JSC { @@ -431,7 +430,7 @@ namespace JSC { if (cell->structure()->isDictionary()) { asObject(cell)->flattenDictionaryObject(callFrame->globalData()); if (slotBase == cell) - slotOffset = cell->structure()->get(propertyName); + slotOffset = cell->structure()->get(callFrame->globalData(), propertyName); } ++count; @@ -472,8 +471,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..fc195cd 100644 --- a/Source/JavaScriptCore/runtime/PropertyMapHashTable.h +++ b/Source/JavaScriptCore/runtime/PropertyMapHashTable.h @@ -22,69 +22,536 @@ #define PropertyMapHashTable_h #include "UString.h" +#include "WriteBarrier.h" +#include <wtf/HashTable.h> +#include <wtf/PassOwnPtr.h> #include <wtf/Vector.h> + +#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; + WriteBarrier<JSCell> specificValue; + + PropertyMapEntry(JSGlobalData& globalData, JSCell* owner, StringImpl* key, unsigned offset, unsigned attributes, JSCell* specificValue) + : key(key) + , offset(offset) + , attributes(attributes) + , specificValue(globalData, owner, 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<typename T> + class ordered_iterator { + public: + ordered_iterator<T>& 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<T>& other) { + return m_valuePtr == other.m_valuePtr; + } + + bool operator!=(const ordered_iterator<T>& 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<unsigned>* 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<PropertyMapEntry*>(&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<ValueType> iterator; + typedef ordered_iterator<const ValueType> 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<ValueType*, unsigned> find_iterator; + + // Constructor is passed an initial capacity, a PropertyTable to copy, or both. + explicit PropertyTable(unsigned initialCapacity); + PropertyTable(JSGlobalData&, JSCell*, const PropertyTable&); + PropertyTable(JSGlobalData&, JSCell*, 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<find_iterator, bool> 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<PropertyTable> copy(JSGlobalData&, JSCell* owner, unsigned newCapacity); + +#ifndef NDEBUG + size_t sizeInMemory(); + void checkConsistency(); +#endif + +private: + PropertyTable(const PropertyTable&); + // 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<typename T> + 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<unsigned> > 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<unsigned*>(fastZeroedMalloc(dataSize()))) + , m_keyCount(0) + , m_deletedCount(0) +{ + ASSERT(isPowerOf2(m_indexSize)); +} + +inline PropertyTable::PropertyTable(JSGlobalData& globalData, JSCell* owner, const PropertyTable& other) + : m_indexSize(other.m_indexSize) + , m_indexMask(other.m_indexMask) + , m_index(static_cast<unsigned*>(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(); + writeBarrier(globalData, owner, iter->specificValue.get()); + } + + // Copy the m_deletedOffsets vector. + Vector<unsigned>* otherDeletedOffsets = other.m_deletedOffsets.get(); + if (otherDeletedOffsets) + m_deletedOffsets.set(new Vector<unsigned>(*otherDeletedOffsets)); +} + +inline PropertyTable::PropertyTable(JSGlobalData& globalData, JSCell* owner, unsigned initialCapacity, const PropertyTable& other) + : m_indexSize(sizeForCapacity(initialCapacity)) + , m_indexMask(m_indexSize - 1) + , m_index(static_cast<unsigned*>(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(); + writeBarrier(globalData, owner, iter->specificValue.get()); + } + + // Copy the m_deletedOffsets vector. + Vector<unsigned>* otherDeletedOffsets = other.m_deletedOffsets.get(); + if (otherDeletedOffsets) + m_deletedOffsets.set(new Vector<unsigned>(*otherDeletedOffsets)); +} + +inline PropertyTable::~PropertyTable() +{ + iterator end = this->end(); + for (iterator iter = begin(); iter != end; ++iter) + iter->key->deref(); + + 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::find_iterator, bool> 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<unsigned>); + m_deletedOffsets->append(offset); +} + +inline PassOwnPtr<PropertyTable> PropertyTable::copy(JSGlobalData& globalData, JSCell* owner, 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(globalData, owner, *this); + return new PropertyTable(globalData, owner, 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<unsigned*>(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<typename T> +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<ValueType*>(m_index + m_indexSize); +} + +inline const PropertyTable::ValueType* PropertyTable::table() const +{ + // The table of values lies after the hash index. + return reinterpret_cast<const ValueType*>(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..8efb406 100644 --- a/Source/JavaScriptCore/runtime/PropertyNameArray.cpp +++ b/Source/JavaScriptCore/runtime/PropertyNameArray.cpp @@ -21,6 +21,8 @@ #include "config.h" #include "PropertyNameArray.h" +#include "JSObject.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 T> class ProtectedPtr { - public: - ProtectedPtr() : m_ptr(0) {} - ProtectedPtr(T* ptr); - ProtectedPtr(const ProtectedPtr&); - ~ProtectedPtr(); - - template <class U> ProtectedPtr(const ProtectedPtr<U>&); - - 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 <class U> ProtectedJSValue(const ProtectedPtr<U>&); - - 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 <class T> inline ProtectedPtr<T>::ProtectedPtr(T* ptr) - : m_ptr(ptr) - { - gcProtectNullTolerant(m_ptr); - } - - template <class T> inline ProtectedPtr<T>::ProtectedPtr(const ProtectedPtr& o) - : m_ptr(o.get()) - { - gcProtectNullTolerant(m_ptr); - } - - template <class T> inline ProtectedPtr<T>::~ProtectedPtr() - { - gcUnprotectNullTolerant(m_ptr); - } - - template <class T> template <class U> inline ProtectedPtr<T>::ProtectedPtr(const ProtectedPtr<U>& o) - : m_ptr(o.get()) - { - gcProtectNullTolerant(m_ptr); - } - - template <class T> inline ProtectedPtr<T>& ProtectedPtr<T>::operator=(const ProtectedPtr<T>& o) - { - T* optr = o.m_ptr; - gcProtectNullTolerant(optr); - gcUnprotectNullTolerant(m_ptr); - m_ptr = optr; - return *this; - } - - template <class T> inline ProtectedPtr<T>& ProtectedPtr<T>::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 <class U> ProtectedJSValue::ProtectedJSValue(const ProtectedPtr<U>& 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 <class T> inline bool operator==(const ProtectedPtr<T>& a, const ProtectedPtr<T>& b) { return a.get() == b.get(); } - template <class T> inline bool operator==(const ProtectedPtr<T>& a, const T* b) { return a.get() == b; } - template <class T> inline bool operator==(const T* a, const ProtectedPtr<T>& b) { return a == b.get(); } - - template <class T> inline bool operator!=(const ProtectedPtr<T>& a, const ProtectedPtr<T>& b) { return a.get() != b.get(); } - template <class T> inline bool operator!=(const ProtectedPtr<T>& a, const T* b) { return a.get() != b; } - template <class T> inline bool operator!=(const T* a, const ProtectedPtr<T>& 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 <class T> inline bool operator==(const ProtectedJSValue& a, const ProtectedPtr<T>& b) { return a.get() == JSValue(b.get()); } - inline bool operator==(const JSValue a, const ProtectedJSValue& b) { return a == b.get(); } - template <class T> inline bool operator==(const ProtectedPtr<T>& 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 <class T> inline bool operator!=(const ProtectedJSValue& a, const ProtectedPtr<T>& b) { return a.get() != JSValue(b.get()); } - inline bool operator!=(const JSValue a, const ProtectedJSValue& b) { return a != b.get(); } - template <class T> inline bool operator!=(const ProtectedPtr<T>& 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 <wtf/Assertions.h> - -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<Structure> 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<Structure>, 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/PutPropertySlot.h b/Source/JavaScriptCore/runtime/PutPropertySlot.h index 4c9e0e6..69d1f8b 100644 --- a/Source/JavaScriptCore/runtime/PutPropertySlot.h +++ b/Source/JavaScriptCore/runtime/PutPropertySlot.h @@ -45,14 +45,14 @@ namespace JSC { { } - void setExistingProperty(DeprecatedPtr<JSObject> base, size_t offset) + void setExistingProperty(JSObject* base, size_t offset) { m_type = ExistingProperty; m_base = base; m_offset = offset; } - void setNewProperty(DeprecatedPtr<JSObject> base, size_t offset) + void setNewProperty(JSObject* base, size_t offset) { m_type = NewProperty; m_base = base; @@ -60,7 +60,7 @@ namespace JSC { } Type type() const { return m_type; } - JSObject* base() const { return m_base.get(); } + JSObject* base() const { return m_base; } bool isStrictMode() const { return m_isStrictMode; } bool isCacheable() const { return m_type != Uncachable; } @@ -68,9 +68,10 @@ namespace JSC { ASSERT(isCacheable()); return m_offset; } + private: Type m_type; - DeprecatedPtr<JSObject> m_base; + JSObject* m_base; size_t m_offset; bool m_isStrictMode; }; diff --git a/Source/JavaScriptCore/runtime/RegExp.cpp b/Source/JavaScriptCore/runtime/RegExp.cpp index 95ce5e9..25cb2d5 100644 --- a/Source/JavaScriptCore/runtime/RegExp.cpp +++ b/Source/JavaScriptCore/runtime/RegExp.cpp @@ -34,6 +34,38 @@ namespace JSC { +RegExpFlags regExpFlags(const UString& string) +{ + RegExpFlags flags = NoFlags; + + for (unsigned i = 0; i < string.length(); ++i) { + switch (string.characters()[i]) { + case 'g': + if (flags & FlagGlobal) + return InvalidFlags; + flags = static_cast<RegExpFlags>(flags | FlagGlobal); + break; + + case 'i': + if (flags & FlagIgnoreCase) + return InvalidFlags; + flags = static_cast<RegExpFlags>(flags | FlagIgnoreCase); + break; + + case 'm': + if (flags & FlagMultiline) + return InvalidFlags; + flags = static_cast<RegExpFlags>(flags | FlagMultiline); + break; + + default: + return InvalidFlags; + } + } + + return flags; +} + struct RegExpRepresentation { #if ENABLE(YARR_JIT) Yarr::YarrCodeBlock m_regExpJITCode; @@ -41,9 +73,9 @@ struct RegExpRepresentation { OwnPtr<Yarr::BytecodePattern> m_regExpBytecode; }; -inline RegExp::RegExp(JSGlobalData* globalData, const UString& patternString, const UString& flags) +inline RegExp::RegExp(JSGlobalData* globalData, const UString& patternString, RegExpFlags flags) : m_patternString(patternString) - , m_flagBits(0) + , m_flags(flags) , m_constructionError(0) , m_numSubpatterns(0) #if ENABLE(REGEXP_TRACING) @@ -52,17 +84,6 @@ inline RegExp::RegExp(JSGlobalData* globalData, const UString& patternString, co #endif , m_representation(adoptPtr(new RegExpRepresentation)) { - // NOTE: The global flag is handled on a case-by-case basis by functions like - // String::match and RegExpObject::match. - if (!flags.isNull()) { - if (flags.find('g') != notFound) - m_flagBits |= Global; - if (flags.find('i') != notFound) - m_flagBits |= IgnoreCase; - if (flags.find('m') != notFound) - m_flagBits |= Multiline; - } - m_state = compile(globalData); } @@ -70,7 +91,7 @@ RegExp::~RegExp() { } -PassRefPtr<RegExp> RegExp::create(JSGlobalData* globalData, const UString& patternString, const UString& flags) +PassRefPtr<RegExp> RegExp::create(JSGlobalData* globalData, const UString& patternString, RegExpFlags flags) { RefPtr<RegExp> res = adoptRef(new RegExp(globalData, patternString, flags)); #if ENABLE(REGEXP_TRACING) diff --git a/Source/JavaScriptCore/runtime/RegExp.h b/Source/JavaScriptCore/runtime/RegExp.h index d99befb..000c33a 100644 --- a/Source/JavaScriptCore/runtime/RegExp.h +++ b/Source/JavaScriptCore/runtime/RegExp.h @@ -24,6 +24,7 @@ #include "UString.h" #include "ExecutableAllocator.h" +#include "RegExpKey.h" #include <wtf/Forward.h> #include <wtf/RefCounted.h> @@ -32,18 +33,20 @@ namespace JSC { struct RegExpRepresentation; class JSGlobalData; + RegExpFlags regExpFlags(const UString&); + class RegExp : public RefCounted<RegExp> { public: - static PassRefPtr<RegExp> create(JSGlobalData* globalData, const UString& pattern, const UString& flags); + static PassRefPtr<RegExp> create(JSGlobalData* globalData, const UString& pattern, RegExpFlags); ~RegExp(); - bool global() const { return m_flagBits & Global; } - bool ignoreCase() const { return m_flagBits & IgnoreCase; } - bool multiline() const { return m_flagBits & Multiline; } + bool global() const { return m_flags & FlagGlobal; } + bool ignoreCase() const { return m_flags & FlagIgnoreCase; } + bool multiline() const { return m_flags & FlagMultiline; } const UString& pattern() const { return m_patternString; } - bool isValid() const { return !m_constructionError; } + bool isValid() const { return !m_constructionError && m_flags != InvalidFlags; } const char* errorMessage() const { return m_constructionError; } int match(const UString&, int startOffset, Vector<int, 32>* ovector = 0); @@ -54,7 +57,7 @@ namespace JSC { #endif private: - RegExp(JSGlobalData* globalData, const UString& pattern, const UString& flags); + RegExp(JSGlobalData* globalData, const UString& pattern, RegExpFlags); enum RegExpState { ParseError, @@ -68,9 +71,8 @@ namespace JSC { void matchCompareWithInterpreter(const UString&, int startOffset, int* offsetVector, int jitResult); #endif - enum FlagBits { Global = 1, IgnoreCase = 2, Multiline = 4 }; UString m_patternString; - int m_flagBits; + RegExpFlags m_flags; const char* m_constructionError; unsigned m_numSubpatterns; #if ENABLE(REGEXP_TRACING) diff --git a/Source/JavaScriptCore/runtime/RegExpCache.cpp b/Source/JavaScriptCore/runtime/RegExpCache.cpp index d101758..c96b047 100644 --- a/Source/JavaScriptCore/runtime/RegExpCache.cpp +++ b/Source/JavaScriptCore/runtime/RegExpCache.cpp @@ -31,7 +31,7 @@ namespace JSC { -PassRefPtr<RegExp> RegExpCache::lookupOrCreate(const UString& patternString, const UString& flags) +PassRefPtr<RegExp> RegExpCache::lookupOrCreate(const UString& patternString, RegExpFlags flags) { if (patternString.length() < maxCacheablePatternLength) { pair<RegExpCacheMap::iterator, bool> result = m_cacheMap.add(RegExpKey(flags, patternString), 0); @@ -43,7 +43,7 @@ PassRefPtr<RegExp> RegExpCache::lookupOrCreate(const UString& patternString, con return create(patternString, flags, m_cacheMap.end()); } -PassRefPtr<RegExp> RegExpCache::create(const UString& patternString, const UString& flags, RegExpCacheMap::iterator iterator) +PassRefPtr<RegExp> RegExpCache::create(const UString& patternString, RegExpFlags flags, RegExpCacheMap::iterator iterator) { RefPtr<RegExp> regExp = RegExp::create(m_globalData, patternString, flags); diff --git a/Source/JavaScriptCore/runtime/RegExpCache.h b/Source/JavaScriptCore/runtime/RegExpCache.h index b5b637f..b4a6ae5 100644 --- a/Source/JavaScriptCore/runtime/RegExpCache.h +++ b/Source/JavaScriptCore/runtime/RegExpCache.h @@ -41,8 +41,8 @@ class RegExpCache { typedef HashMap<RegExpKey, RefPtr<RegExp> > RegExpCacheMap; public: - PassRefPtr<RegExp> lookupOrCreate(const UString& patternString, const UString& flags); - PassRefPtr<RegExp> create(const UString& patternString, const UString& flags, RegExpCacheMap::iterator iterator); + PassRefPtr<RegExp> lookupOrCreate(const UString& patternString, RegExpFlags); + PassRefPtr<RegExp> create(const UString& patternString, RegExpFlags, RegExpCacheMap::iterator); RegExpCache(JSGlobalData* globalData); private: diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp index 1b30514..3da0198 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 @@ -95,10 +95,12 @@ const ClassInfo RegExpConstructor::info = { "Function", &InternalFunction::info, @end */ -RegExpConstructor::RegExpConstructor(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, RegExpPrototype* regExpPrototype) +RegExpConstructor::RegExpConstructor(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, RegExpPrototype* regExpPrototype) : 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); @@ -107,7 +109,7 @@ RegExpConstructor::RegExpConstructor(ExecState* exec, JSGlobalObject* globalObje } RegExpMatchesArray::RegExpMatchesArray(ExecState* exec, RegExpConstructorPrivate* data) - : JSArray(exec->lexicalGlobalObject()->regExpMatchesArrayStructure(), data->lastNumSubPatterns + 1, CreateInitialized) + : JSArray(exec->globalData(), exec->lexicalGlobalObject()->regExpMatchesArrayStructure(), data->lastNumSubPatterns + 1, CreateInitialized) { RegExpConstructorPrivate* d = new RegExpConstructorPrivate; d->input = data->lastInput; @@ -289,32 +291,42 @@ void setRegExpConstructorMultiline(ExecState* exec, JSObject* baseObject, JSValu { asRegExpConstructor(baseObject)->setMultiline(value.toBoolean(exec)); } - + // ECMA 15.10.4 -JSObject* constructRegExp(ExecState* exec, const ArgList& args) +JSObject* constructRegExp(ExecState* exec, JSGlobalObject* globalObject, 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); } UString pattern = arg0.isUndefined() ? UString("") : arg0.toString(exec); - UString flags = arg1.isUndefined() ? UString("") : arg1.toString(exec); + if (exec->hadException()) + return 0; + + RegExpFlags flags = NoFlags; + if (!arg1.isUndefined()) { + flags = regExpFlags(arg1.toString(exec)); + if (exec->hadException()) + return 0; + if (flags == InvalidFlags) + return throwError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor.")); + } RefPtr<RegExp> regExp = exec->globalData().regExpCache()->lookupOrCreate(pattern, flags); if (!regExp->isValid()) return throwError(exec, createSyntaxError(exec, regExp->errorMessage())); - return new (exec) RegExpObject(exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->regExpStructure(), regExp.release()); + return new (exec) RegExpObject(exec->lexicalGlobalObject(), globalObject->regExpStructure(), regExp.release()); } static EncodedJSValue JSC_HOST_CALL constructWithRegExpConstructor(ExecState* exec) { ArgList args(exec); - return JSValue::encode(constructRegExp(exec, args)); + return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args)); } ConstructType RegExpConstructor::getConstructData(ConstructData& constructData) @@ -327,7 +339,7 @@ ConstructType RegExpConstructor::getConstructData(ConstructData& constructData) static EncodedJSValue JSC_HOST_CALL callRegExpConstructor(ExecState* exec) { ArgList args(exec); - return JSValue::encode(constructRegExp(exec, args)); + return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args)); } CallType RegExpConstructor::getCallData(CallData& callData) diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.h b/Source/JavaScriptCore/runtime/RegExpConstructor.h index 1714bd3..548664e 100644 --- a/Source/JavaScriptCore/runtime/RegExpConstructor.h +++ b/Source/JavaScriptCore/runtime/RegExpConstructor.h @@ -57,18 +57,18 @@ namespace JSC { class RegExpConstructor : public InternalFunction { public: - RegExpConstructor(ExecState*, JSGlobalObject*, NonNullPassRefPtr<Structure>, RegExpPrototype*); + RegExpConstructor(ExecState*, JSGlobalObject*, Structure*, RegExpPrototype*); - static PassRefPtr<Structure> createStructure(JSValue prototype) + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, 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,18 +91,16 @@ namespace JSC { virtual ConstructType getConstructData(ConstructData&); virtual CallType getCallData(CallData&); - virtual const ClassInfo* classInfo() const { return &info; } - OwnPtr<RegExpConstructorPrivate> d; }; RegExpConstructor* asRegExpConstructor(JSValue); - JSObject* constructRegExp(ExecState*, const ArgList&); + JSObject* constructRegExp(ExecState*, JSGlobalObject*, const ArgList&); inline RegExpConstructor* asRegExpConstructor(JSValue value) { - ASSERT(asObject(value)->inherits(&RegExpConstructor::info)); + ASSERT(asObject(value)->inherits(&RegExpConstructor::s_info)); return static_cast<RegExpConstructor*>(asObject(value)); } diff --git a/Source/JavaScriptCore/runtime/RegExpKey.h b/Source/JavaScriptCore/runtime/RegExpKey.h index cd1368d..b4847f9 100644 --- a/Source/JavaScriptCore/runtime/RegExpKey.h +++ b/Source/JavaScriptCore/runtime/RegExpKey.h @@ -25,63 +25,54 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "UString.h" -#include <wtf/text/StringHash.h> - #ifndef RegExpKey_h #define RegExpKey_h +#include "UString.h" +#include <wtf/text/StringHash.h> + namespace JSC { +enum RegExpFlags { + NoFlags = 0, + FlagGlobal = 1, + FlagIgnoreCase = 2, + FlagMultiline = 4, + InvalidFlags = 8, + DeletedValueFlags = -1 +}; + struct RegExpKey { - int flagsValue; + RegExpFlags flagsValue; RefPtr<StringImpl> pattern; RegExpKey() - : flagsValue(0) + : flagsValue(NoFlags) { } - RegExpKey(int flags) + RegExpKey(RegExpFlags flags) : flagsValue(flags) { } - RegExpKey(int flags, const UString& pattern) + RegExpKey(RegExpFlags flags, const UString& pattern) : flagsValue(flags) , pattern(pattern.impl()) { } - RegExpKey(int flags, const PassRefPtr<StringImpl> pattern) + RegExpKey(RegExpFlags flags, const PassRefPtr<StringImpl> pattern) : flagsValue(flags) , pattern(pattern) { } - RegExpKey(int flags, const RefPtr<StringImpl>& pattern) + RegExpKey(RegExpFlags flags, const RefPtr<StringImpl>& pattern) : flagsValue(flags) , pattern(pattern) { } - - RegExpKey(const UString& flags, const UString& pattern) - : pattern(pattern.impl()) - { - flagsValue = getFlagsValue(flags); - } - - int getFlagsValue(const UString flags) - { - flagsValue = 0; - if (flags.find('g') != notFound) - flagsValue += 4; - if (flags.find('i') != notFound) - flagsValue += 2; - if (flags.find('m') != notFound) - flagsValue += 1; - return flagsValue; - } }; inline bool operator==(const RegExpKey& a, const RegExpKey& b) @@ -112,8 +103,8 @@ template<> struct DefaultHash<JSC::RegExpKey> { }; template<> struct HashTraits<JSC::RegExpKey> : GenericHashTraits<JSC::RegExpKey> { - static void constructDeletedValue(JSC::RegExpKey& slot) { slot.flagsValue = -1; } - static bool isDeletedValue(const JSC::RegExpKey& value) { return value.flagsValue == -1; } + static void constructDeletedValue(JSC::RegExpKey& slot) { slot.flagsValue = JSC::DeletedValueFlags; } + static bool isDeletedValue(const JSC::RegExpKey& value) { return value.flagsValue == JSC::DeletedValueFlags; } }; } // namespace WTF diff --git a/Source/JavaScriptCore/runtime/RegExpObject.cpp b/Source/JavaScriptCore/runtime/RegExpObject.cpp index b969e38..d824ecd 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 @@ -61,16 +61,24 @@ const ClassInfo RegExpObject::info = { "RegExp", 0, 0, ExecState::regExpTable }; @end */ -RegExpObject::RegExpObject(JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, NonNullPassRefPtr<RegExp> regExp) +RegExpObject::RegExpObject(JSGlobalObject* globalObject, Structure* structure, NonNullPassRefPtr<RegExp> regExp) : JSObjectWithGlobalObject(globalObject, structure) - , d(adoptPtr(new RegExpObjectData(regExp, 0))) + , d(adoptPtr(new RegExpObjectData(regExp))) { + ASSERT(inherits(&s_info)); } RegExpObject::~RegExpObject() { } +void RegExpObject::markChildren(MarkStack& markStack) +{ + Base::markChildren(markStack); + if (UNLIKELY(!d->lastIndex.get().isInt32())) + markStack.append(&d->lastIndex); +} + bool RegExpObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) { return getStaticValueSlot<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), this, propertyName, slot); @@ -103,7 +111,7 @@ JSValue regExpObjectSource(ExecState* exec, JSValue slotBase, const Identifier&) JSValue regExpObjectLastIndex(ExecState*, JSValue slotBase, const Identifier&) { - return jsNumber(asRegExpObject(slotBase)->lastIndex()); + return asRegExpObject(slotBase)->getLastIndex(); } void RegExpObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) @@ -113,7 +121,7 @@ void RegExpObject::put(ExecState* exec, const Identifier& propertyName, JSValue void setRegExpObjectLastIndex(ExecState* exec, JSObject* baseObject, JSValue value) { - asRegExpObject(baseObject)->setLastIndex(value.toInteger(exec)); + asRegExpObject(baseObject)->setLastIndex(exec->globalData(), value); } JSValue RegExpObject::test(ExecState* exec) @@ -132,12 +140,7 @@ JSValue RegExpObject::exec(ExecState* exec) bool RegExpObject::match(ExecState* exec) { RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); - - UString input = !exec->argumentCount() ? regExpConstructor->input() : exec->argument(0).toString(exec); - if (input.isNull()) { - throwError(exec, createError(exec, makeUString("No input to ", toString(exec), "."))); - return false; - } + UString input = exec->argument(0).toString(exec); if (!regExp()->global()) { int position; @@ -146,20 +149,32 @@ bool RegExpObject::match(ExecState* exec) return position >= 0; } - if (d->lastIndex < 0 || d->lastIndex > input.length()) { - d->lastIndex = 0; - return false; + JSValue jsLastIndex = getLastIndex(); + unsigned lastIndex; + if (LIKELY(jsLastIndex.isUInt32())) { + lastIndex = jsLastIndex.asUInt32(); + if (lastIndex > input.length()) { + setLastIndex(0); + return false; + } + } else { + double doubleLastIndex = jsLastIndex.toInteger(exec); + if (doubleLastIndex < 0 || doubleLastIndex > input.length()) { + setLastIndex(0); + return false; + } + lastIndex = static_cast<unsigned>(doubleLastIndex); } int position; int length = 0; - regExpConstructor->performMatch(d->regExp.get(), input, static_cast<int>(d->lastIndex), position, length); + regExpConstructor->performMatch(d->regExp.get(), input, lastIndex, position, length); if (position < 0) { - d->lastIndex = 0; + setLastIndex(0); return false; } - d->lastIndex = position + length; + setLastIndex(position + length); return true; } diff --git a/Source/JavaScriptCore/runtime/RegExpObject.h b/Source/JavaScriptCore/runtime/RegExpObject.h index 99c84da..4274fff 100644 --- a/Source/JavaScriptCore/runtime/RegExpObject.h +++ b/Source/JavaScriptCore/runtime/RegExpObject.h @@ -28,14 +28,26 @@ namespace JSC { class RegExpObject : public JSObjectWithGlobalObject { public: - RegExpObject(JSGlobalObject* globalObject, NonNullPassRefPtr<Structure>, NonNullPassRefPtr<RegExp>); + typedef JSObjectWithGlobalObject Base; + + RegExpObject(JSGlobalObject*, Structure*, NonNullPassRefPtr<RegExp>); virtual ~RegExpObject(); void setRegExp(PassRefPtr<RegExp> r) { d->regExp = r; } RegExp* regExp() const { return d->regExp.get(); } - void setLastIndex(double lastIndex) { d->lastIndex = lastIndex; } - double lastIndex() const { return d->lastIndex; } + void setLastIndex(size_t lastIndex) + { + d->lastIndex.setWithoutWriteBarrier(jsNumber(lastIndex)); + } + void setLastIndex(JSGlobalData& globalData, JSValue lastIndex) + { + d->lastIndex.set(globalData, this, lastIndex); + } + JSValue getLastIndex() const + { + return d->lastIndex.get(); + } JSValue test(ExecState*); JSValue exec(ExecState*); @@ -44,33 +56,34 @@ namespace JSC { virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); - virtual const ClassInfo* classInfo() const { return &info; } - static JS_EXPORTDATA const ClassInfo info; + static JS_EXPORTDATA const ClassInfo s_info; - static PassRefPtr<Structure> createStructure(JSValue prototype) + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: - static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSObjectWithGlobalObject::StructureFlags; - + static const unsigned StructureFlags = OverridesMarkChildren | OverridesGetOwnPropertySlot | JSObjectWithGlobalObject::StructureFlags; + private: + virtual void markChildren(MarkStack&); + bool match(ExecState*); struct RegExpObjectData { WTF_MAKE_FAST_ALLOCATED; public: - RegExpObjectData(NonNullPassRefPtr<RegExp> regExp, double lastIndex) + RegExpObjectData(NonNullPassRefPtr<RegExp> regExp) : regExp(regExp) - , lastIndex(lastIndex) { + lastIndex.setWithoutWriteBarrier(jsNumber(0)); } RefPtr<RegExp> regExp; - double lastIndex; + WriteBarrier<Unknown> lastIndex; }; -#if PLATFORM(WIN) +#if COMPILER(MSVC) friend void WTF::deleteOwnedPtr<RegExpObjectData>(RegExpObjectData*); #endif OwnPtr<RegExpObjectData> d; @@ -80,7 +93,7 @@ namespace JSC { inline RegExpObject* asRegExpObject(JSValue value) { - ASSERT(asObject(value)->inherits(&RegExpObject::info)); + ASSERT(asObject(value)->inherits(&RegExpObject::s_info)); return static_cast<RegExpObject*>(asObject(value)); } diff --git a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp index a7c447d..5bb8ad8 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, Structure* prototypeFunctionStructure) - : RegExpObject(globalObject, structure, RegExp::create(&exec->globalData(), "", "")) +RegExpPrototype::RegExpPrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, Structure* functionStructure) + : RegExpObject(globalObject, structure, RegExp::create(&exec->globalData(), "", NoFlags)) { - 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, 2, exec->propertyNames().compile, regExpProtoFuncCompile), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().exec, regExpProtoFuncExec), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, 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,20 +77,30 @@ 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> 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(); } else { UString pattern = !exec->argumentCount() ? UString("") : arg0.toString(exec); - UString flags = arg1.isUndefined() ? UString("") : arg1.toString(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + RegExpFlags flags = NoFlags; + if (!arg1.isUndefined()) { + flags = regExpFlags(arg1.toString(exec)); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + if (flags == InvalidFlags) + return throwVMError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor.")); + } regExp = exec->globalData().regExpCache()->lookupOrCreate(pattern, flags); } @@ -106,8 +115,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..2cc5405 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>, Structure* prototypeFunctionStructure); + RegExpPrototype(ExecState*, JSGlobalObject*, Structure*, Structure* functionStructure); }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ScopeChain.cpp b/Source/JavaScriptCore/runtime/ScopeChain.cpp index 976cff6..026d729 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<JSObject> 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,14 @@ void ScopeChainNode::print() const #endif -int ScopeChain::localDepth() const +const ClassInfo ScopeChainNode::s_info = { "ScopeChainNode", 0, 0, 0 }; + +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 +67,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..d0a2672 100644 --- a/Source/JavaScriptCore/runtime/ScopeChain.h +++ b/Source/JavaScriptCore/runtime/ScopeChain.h @@ -21,7 +21,8 @@ #ifndef ScopeChain_h #define ScopeChain_h -#include "WriteBarrier.h" +#include "JSCell.h" +#include "Structure.h" #include <wtf/FastAllocBase.h> namespace JSC { @@ -32,109 +33,68 @@ 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, 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<JSObject> 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<ScopeChainNode> next; + WriteBarrier<JSObject> object; + WriteBarrier<JSGlobalObject> globalObject; + WriteBarrier<JSObject> 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 Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info); } + virtual void markChildren(MarkStack&); + private: + static const unsigned StructureFlags = OverridesMarkChildren; + static const ClassInfo s_info; }; 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<JSObject> const & operator*() const { return m_node->object; } - DeprecatedPtr<JSObject> const * operator->() const { return &(operator*()); } + WriteBarrier<JSObject> const & operator*() const { return m_node->object; } + WriteBarrier<JSObject> 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,99 +102,43 @@ namespace JSC { bool operator!=(const ScopeChainIterator& other) const { return m_node != other.m_node; } private: - const ScopeChainNode* m_node; + ScopeChainNode* 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 + { + return scopeChain()->globalThis.get(); + } + + ALWAYS_INLINE ScopeChainNode* Register::scopeChain() const + { + return static_cast<ScopeChainNode*>(jsValue().asCell()); + } + + ALWAYS_INLINE Register& Register::operator=(ScopeChainNode* scopeChain) { - ScopeChain tmp(c); - swap(tmp); + *this = JSValue(scopeChain); return *this; } 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.cpp b/Source/JavaScriptCore/runtime/SmallStrings.cpp index 9b193f5..ac67020 100644 --- a/Source/JavaScriptCore/runtime/SmallStrings.cpp +++ b/Source/JavaScriptCore/runtime/SmallStrings.cpp @@ -33,8 +33,6 @@ namespace JSC { -static const unsigned numCharactersToStore = 0x100; - static inline bool isMarked(JSCell* string) { return string && Heap::isMarked(string); @@ -45,17 +43,22 @@ class SmallStringsStorage { public: SmallStringsStorage(); - StringImpl* rep(unsigned char character) { return m_reps[character].get(); } + StringImpl* rep(unsigned char character) + { + return m_reps[character].get(); + } private: - RefPtr<StringImpl> m_reps[numCharactersToStore]; + static const unsigned singleCharacterStringCount = maxSingleCharacterString + 1; + + RefPtr<StringImpl> m_reps[singleCharacterStringCount]; }; SmallStringsStorage::SmallStringsStorage() { UChar* characterBuffer = 0; - RefPtr<StringImpl> baseString = StringImpl::createUninitialized(numCharactersToStore, characterBuffer); - for (unsigned i = 0; i < numCharactersToStore; ++i) { + RefPtr<StringImpl> baseString = StringImpl::createUninitialized(singleCharacterStringCount, characterBuffer); + for (unsigned i = 0; i < singleCharacterStringCount; ++i) { characterBuffer[i] = i; m_reps[i] = StringImpl::create(baseString, i, 1); } @@ -63,7 +66,7 @@ SmallStringsStorage::SmallStringsStorage() SmallStrings::SmallStrings() { - COMPILE_ASSERT(numCharactersToStore == sizeof(m_singleCharacterStrings) / sizeof(m_singleCharacterStrings[0]), IsNumCharactersConstInSyncWithClassUsage); + COMPILE_ASSERT(singleCharacterStringCount == sizeof(m_singleCharacterStrings) / sizeof(m_singleCharacterStrings[0]), IsNumCharactersConstInSyncWithClassUsage); clear(); } @@ -71,7 +74,7 @@ SmallStrings::~SmallStrings() { } -void SmallStrings::markChildren(MarkStack& markStack) +void SmallStrings::markChildren(HeapRootMarker& heapRootMarker) { /* Our hypothesis is that small strings are very common. So, we cache them @@ -83,9 +86,9 @@ void SmallStrings::markChildren(MarkStack& markStack) so, it's probably reasonable to mark the rest. If not, we clear the cache. */ - bool isAnyStringMarked = isMarked(m_emptyString.get()); - for (unsigned i = 0; i < numCharactersToStore && !isAnyStringMarked; ++i) - isAnyStringMarked = isMarked(m_singleCharacterStrings[i].get()); + bool isAnyStringMarked = isMarked(m_emptyString); + for (unsigned i = 0; i < singleCharacterStringCount && !isAnyStringMarked; ++i) + isAnyStringMarked = isMarked(m_singleCharacterStrings[i]); if (!isAnyStringMarked) { clear(); @@ -93,17 +96,17 @@ void SmallStrings::markChildren(MarkStack& markStack) } if (m_emptyString) - markStack.append(&m_emptyString); - for (unsigned i = 0; i < numCharactersToStore; ++i) { + heapRootMarker.mark(&m_emptyString); + for (unsigned i = 0; i < singleCharacterStringCount; ++i) { if (m_singleCharacterStrings[i]) - markStack.append(&m_singleCharacterStrings[i]); + heapRootMarker.mark(&m_singleCharacterStrings[i]); } } void SmallStrings::clear() { m_emptyString = 0; - for (unsigned i = 0; i < numCharactersToStore; ++i) + for (unsigned i = 0; i < singleCharacterStringCount; ++i) m_singleCharacterStrings[i] = 0; } @@ -112,7 +115,7 @@ unsigned SmallStrings::count() const unsigned count = 0; if (m_emptyString) ++count; - for (unsigned i = 0; i < numCharactersToStore; ++i) { + for (unsigned i = 0; i < singleCharacterStringCount; ++i) { if (m_singleCharacterStrings[i]) ++count; } diff --git a/Source/JavaScriptCore/runtime/SmallStrings.h b/Source/JavaScriptCore/runtime/SmallStrings.h index ee795b6..b54d020 100644 --- a/Source/JavaScriptCore/runtime/SmallStrings.h +++ b/Source/JavaScriptCore/runtime/SmallStrings.h @@ -33,13 +33,16 @@ namespace JSC { + class HeapRootMarker; class JSGlobalData; class JSString; class MarkStack; class SmallStringsStorage; + static const unsigned maxSingleCharacterString = 0xFF; + class SmallStrings { - WTF_MAKE_NONCOPYABLE(SmallStrings); WTF_MAKE_FAST_ALLOCATED; + WTF_MAKE_NONCOPYABLE(SmallStrings); public: SmallStrings(); ~SmallStrings(); @@ -48,30 +51,33 @@ namespace JSC { { if (!m_emptyString) createEmptyString(globalData); - return m_emptyString.get(); + return m_emptyString; } + JSString* singleCharacterString(JSGlobalData* globalData, unsigned char character) { if (!m_singleCharacterStrings[character]) createSingleCharacterString(globalData, character); - return m_singleCharacterStrings[character].get(); + return m_singleCharacterStrings[character]; } StringImpl* singleCharacterStringRep(unsigned char character); - void markChildren(MarkStack&); + void markChildren(HeapRootMarker&); void clear(); unsigned count() const; -#if ENABLE(JIT) - JSCell** singleCharacterStrings() { return m_singleCharacterStrings[0].slot(); } -#endif + + JSString** singleCharacterStrings() { return &m_singleCharacterStrings[0]; } + private: + static const unsigned singleCharacterStringCount = maxSingleCharacterString + 1; + void createEmptyString(JSGlobalData*); void createSingleCharacterString(JSGlobalData*, unsigned char); - DeprecatedPtr<JSString> m_emptyString; - FixedArray<DeprecatedPtr<JSString>, 0x100> m_singleCharacterStrings; + JSString* m_emptyString; + JSString* m_singleCharacterStrings[singleCharacterStringCount]; OwnPtr<SmallStringsStorage> m_storage; }; diff --git a/Source/JavaScriptCore/runtime/StrictEvalActivation.cpp b/Source/JavaScriptCore/runtime/StrictEvalActivation.cpp index 5bb013b..e666dee 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(), exec->globalData().strictEvalActivationStructure.get()) { } 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..560202a 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, Structure* prototypeFunctionStructure, StringPrototype* stringPrototype) +StringConstructor::StringConstructor(ExecState* exec, JSGlobalObject* globalObject, Structure* 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); @@ -68,9 +67,10 @@ StringConstructor::StringConstructor(ExecState* exec, JSGlobalObject* globalObje // ECMA 15.5.2 static EncodedJSValue JSC_HOST_CALL constructWithStringConstructor(ExecState* exec) { + JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject(); if (!exec->argumentCount()) - return JSValue::encode(new (exec) StringObject(exec, exec->lexicalGlobalObject()->stringObjectStructure())); - return JSValue::encode(new (exec) StringObject(exec, exec->lexicalGlobalObject()->stringObjectStructure(), exec->argument(0).toString(exec))); + return JSValue::encode(new (exec) StringObject(exec, globalObject->stringObjectStructure())); + return JSValue::encode(new (exec) StringObject(exec, globalObject->stringObjectStructure(), exec->argument(0).toString(exec))); } ConstructType StringConstructor::getConstructData(ConstructData& constructData) diff --git a/Source/JavaScriptCore/runtime/StringConstructor.h b/Source/JavaScriptCore/runtime/StringConstructor.h index 20f3a52..117cce8 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>, Structure* prototypeFunctionStructure, StringPrototype*); + StringConstructor(ExecState*, JSGlobalObject*, Structure*, 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..67dc291 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> structure) +StringObject::StringObject(ExecState* exec, Structure* structure) : JSWrapperObject(exec->globalData(), structure) { + ASSERT(inherits(&s_info)); setInternalValue(exec->globalData(), jsEmptyString(exec)); } -StringObject::StringObject(JSGlobalData& globalData, NonNullPassRefPtr<Structure> structure, JSString* string) +StringObject::StringObject(JSGlobalData& globalData, Structure* structure, JSString* string) : JSWrapperObject(globalData, structure) { + ASSERT(inherits(&s_info)); setInternalValue(globalData, string); } -StringObject::StringObject(ExecState* exec, NonNullPassRefPtr<Structure> structure, const UString& string) +StringObject::StringObject(ExecState* exec, Structure* 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..4c16044 100644 --- a/Source/JavaScriptCore/runtime/StringObject.h +++ b/Source/JavaScriptCore/runtime/StringObject.h @@ -28,10 +28,10 @@ namespace JSC { class StringObject : public JSWrapperObject { public: - StringObject(ExecState*, NonNullPassRefPtr<Structure>); - StringObject(ExecState*, NonNullPassRefPtr<Structure>, const UString&); + StringObject(ExecState*, Structure*); + StringObject(ExecState*, Structure*, const UString&); - static StringObject* create(ExecState*, JSString*); + static StringObject* create(ExecState*, JSGlobalObject*, JSString*); virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); @@ -41,26 +41,25 @@ 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<Structure> createStructure(JSValue prototype) + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: - static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSWrapperObject::StructureFlags; - StringObject(JSGlobalData&, NonNullPassRefPtr<Structure>, JSString*); - }; + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSWrapperObject::StructureFlags; + StringObject(JSGlobalData&, Structure*, JSString*); + }; StringObject* asStringObject(JSValue); inline StringObject* asStringObject(JSValue value) { - ASSERT(asObject(value)->inherits(&StringObject::info)); + ASSERT(asObject(value)->inherits(&StringObject::s_info)); return static_cast<StringObject*>(asObject(value)); } diff --git a/Source/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h b/Source/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h index 43c3e38..3133944 100644 --- a/Source/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h +++ b/Source/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h @@ -33,18 +33,18 @@ namespace JSC { static StringObjectThatMasqueradesAsUndefined* create(ExecState* exec, const UString& string) { return new (exec) StringObjectThatMasqueradesAsUndefined(exec, - createStructure(exec->lexicalGlobalObject()->stringPrototype()), string); + createStructure(exec->globalData(), exec->lexicalGlobalObject()->stringPrototype()), string); } private: - StringObjectThatMasqueradesAsUndefined(ExecState* exec, NonNullPassRefPtr<Structure> structure, const UString& string) + StringObjectThatMasqueradesAsUndefined(ExecState* exec, Structure* structure, const UString& string) : StringObject(exec, structure, string) { } - static PassRefPtr<Structure> createStructure(JSValue proto) + static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { - return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, 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..91112a5 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 @@ -131,9 +131,11 @@ const ClassInfo StringPrototype::info = { "String", &StringObject::info, 0, Exec */ // ECMA 15.5.4 -StringPrototype::StringPrototype(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure) +StringPrototype::StringPrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* 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); @@ -602,10 +604,8 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec) JSValue a0 = exec->argument(0); - UString u = s; RefPtr<RegExp> reg; - RegExpObject* imp = 0; - if (a0.inherits(&RegExpObject::info)) + if (a0.inherits(&RegExpObject::s_info)) reg = asRegExpObject(a0)->regExp(); else { /* @@ -613,12 +613,12 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec) * If regexp is not an object whose [[Class]] property is "RegExp", it is * replaced with the result of the expression new RegExp(regexp). */ - reg = exec->globalData().regExpCache()->lookupOrCreate(a0.toString(exec), UString()); + reg = exec->globalData().regExpCache()->lookupOrCreate(a0.toString(exec), NoFlags); } RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); int pos; int matchLength = 0; - regExpConstructor->performMatch(reg.get(), u, 0, pos, matchLength); + regExpConstructor->performMatch(reg.get(), s, 0, pos, matchLength); if (!(reg->global())) { // case without 'g' flag is handled like RegExp.prototype.exec if (pos < 0) @@ -628,15 +628,13 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec) // return array of matches MarkedArgumentBuffer list; - int lastIndex = 0; + unsigned lastIndex = 0; while (pos >= 0) { - list.append(jsSubstring(exec, u, pos, matchLength)); + list.append(jsSubstring(exec, s, pos, matchLength)); lastIndex = pos; pos += matchLength == 0 ? 1 : matchLength; - regExpConstructor->performMatch(reg.get(), u, pos, pos, matchLength); + regExpConstructor->performMatch(reg.get(), s, pos, pos, matchLength); } - if (imp) - imp->setLastIndex(lastIndex); if (list.isEmpty()) { // if there are no matches at all, it's important to return // Null instead of an empty array, because this matches @@ -656,9 +654,8 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec) JSValue a0 = exec->argument(0); - UString u = s; RefPtr<RegExp> reg; - if (a0.inherits(&RegExpObject::info)) + if (a0.inherits(&RegExpObject::s_info)) reg = asRegExpObject(a0)->regExp(); else { /* @@ -666,12 +663,12 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec) * If regexp is not an object whose [[Class]] property is "RegExp", it is * replaced with the result of the expression new RegExp(regexp). */ - reg = exec->globalData().regExpCache()->lookupOrCreate(a0.toString(exec), UString()); + reg = exec->globalData().regExpCache()->lookupOrCreate(a0.toString(exec), NoFlags); } RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); int pos; int matchLength = 0; - regExpConstructor->performMatch(reg.get(), u, 0, pos, matchLength); + regExpConstructor->performMatch(reg.get(), s, 0, pos, matchLength); return JSValue::encode(jsNumber(pos)); } @@ -716,7 +713,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..6c4b475 100644 --- a/Source/JavaScriptCore/runtime/StringPrototype.h +++ b/Source/JavaScriptCore/runtime/StringPrototype.h @@ -29,13 +29,23 @@ namespace JSC { class StringPrototype : public StringObject { public: - StringPrototype(ExecState*, JSGlobalObject*, NonNullPassRefPtr<Structure>); + StringPrototype(ExecState*, JSGlobalObject*, Structure*); 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 Structure* createStructure(JSGlobalData& globalData, JSValue prototype) + { + return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); + } + + static const ClassInfo s_info; + + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | StringObject::StructureFlags; + + COMPILE_ASSERT(!StringObject::AnonymousSlotCount, StringPrototype_stomps_on_your_anonymous_slot); + static const unsigned AnonymousSlotCount = 1; }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp index e8f5d7a..dcc8e7c 100644 --- a/Source/JavaScriptCore/runtime/Structure.cpp +++ b/Source/JavaScriptCore/runtime/Structure.cpp @@ -50,132 +50,82 @@ using namespace std; using namespace WTF; -namespace JSC { - -// 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; - -// 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; - -static const unsigned newTableSize = 16; +#if DUMP_PROPERTYMAP_STATS -#ifndef NDEBUG -static WTF::RefCountedLeakCounter structureCounter("Structure"); +int numProbes; +int numCollisions; +int numRehashes; +int numRemoves; -#if ENABLE(JSC_MULTIPLE_THREADS) -static Mutex& ignoreSetMutex = *(new Mutex); #endif -static bool shouldIgnoreLeaks; -static HashSet<Structure*>& ignoreSet = *(new HashSet<Structure*>); -#endif +namespace JSC { #if DUMP_STRUCTURE_ID_STATISTICS static HashSet<Structure*>& liveStructureSet = *(new HashSet<Structure*>); #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) -{ - 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 +bool StructureTransitionTable::contains(StringImpl* rep, unsigned attributes) 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)); - setSingleTransition(0); - return; + 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); + clearSingleTransition(); + } 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.get().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(JSGlobalData& globalData, Structure* structure) { - if (m_isUsingSingleSlot) { - if (!singleTransition()) { - setSingleTransition(structure); + if (isUsingSingleSlot()) { + Structure* existingTransition = singleTransition(); + + // This handles the first transition being added. + if (!existingTransition) { + setSingleTransition(globalData, 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(globalData, existingTransition); } - if (!specificValue) { - TransitionTable::iterator find = transitionTable()->find(key); - if (find == transitionTable()->end()) - transitionTable()->add(key, Transition(structure, static_cast<Structure*>(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<Structure*>(0), structure)); + + // Add the structure to the map. + std::pair<TransitionMap::iterator, bool> result = map()->add(globalData, 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.get().second->m_specificValueInPrevious); + ASSERT(!structure->m_specificValueInPrevious); + map()->set(result.first, structure); } } @@ -191,21 +141,22 @@ void Structure::dumpStatistics() HashSet<Structure*>::const_iterator end = liveStructureSet.end(); for (HashSet<Structure*>::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 +174,12 @@ void Structure::dumpStatistics() #endif } -Structure::Structure(JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount) - : m_typeInfo(typeInfo) - , m_prototype(prototype) - , m_specificValueInPrevious(0) - , m_propertyTable(0) - , m_propertyStorageCapacity(JSObject::inlineStorageCapacity) +Structure::Structure(JSGlobalData& globalData, JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount, const ClassInfo* classInfo) + : JSCell(globalData, globalData.structureStructure.get()) + , m_typeInfo(typeInfo) + , m_prototype(globalData, this, prototype) + , m_classInfo(classInfo) + , m_propertyStorageCapacity(typeInfo.isFinal() ? JSFinalObject_inlineStorageCapacity : JSNonFinalObject_inlineStorageCapacity) , m_offset(noOffset) , m_dictionaryKind(NoneDictionaryKind) , m_isPinnedPropertyTable(false) @@ -237,119 +188,60 @@ 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() -{ - 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); - } - - if (!m_isUsingSingleSlot) - delete transitionTable(); - -#ifndef NDEBUG -#if ENABLE(JSC_MULTIPLE_THREADS) - MutexLocker protect(ignoreSetMutex); -#endif - HashSet<Structure*>::iterator it = ignoreSet.find(this); - if (it != ignoreSet.end()) - ignoreSet.remove(it); - else - structureCounter.decrement(); -#endif - -#if DUMP_STRUCTURE_ID_STATISTICS - liveStructureSet.remove(this); -#endif -} - -void Structure::startIgnoringLeaks() -{ -#ifndef NDEBUG - shouldIgnoreLeaks = true; -#endif + ASSERT(m_prototype.isObject() || m_prototype.isNull()); } -void Structure::stopIgnoringLeaks() -{ -#ifndef NDEBUG - shouldIgnoreLeaks = false; -#endif -} +const ClassInfo Structure::s_info = { "Structure", 0, 0, 0 }; -static bool isPowerOf2(unsigned v) +Structure::Structure(JSGlobalData& globalData) + : JSCell(globalData, this) + , m_typeInfo(CompoundType, OverridesMarkChildren) + , m_prototype(globalData, this, jsNull()) + , m_classInfo(&s_info) + , m_propertyStorageCapacity(0) + , m_offset(noOffset) + , m_dictionaryKind(NoneDictionaryKind) + , m_isPinnedPropertyTable(false) + , m_hasGetterSetterProperties(false) + , m_hasNonEnumerableProperties(false) + , m_attributesInPrevious(0) + , m_specificFunctionThrashCount(0) + , m_anonymousSlotCount(0) + , m_preventExtensions(false) { - // Taken from http://www.cs.utk.edu/~vose/c-stuff/bithacks.html - - return !(v & (v - 1)) && v; + ASSERT(m_prototype); + ASSERT(m_prototype.isNull()); + ASSERT(!globalData.structureStructure); } -static unsigned nextPowerOf2(unsigned v) +Structure::Structure(JSGlobalData& globalData, const Structure* previous) + : JSCell(globalData, globalData.structureStructure.get()) + , m_typeInfo(previous->typeInfo()) + , m_prototype(globalData, this, previous->storedPrototype()) + , 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) { - // 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; + ASSERT(m_prototype); + ASSERT(m_prototype.isObject() || m_prototype.isNull()); } -static unsigned sizeForKeyCount(size_t keyCount) +Structure::~Structure() { - if (keyCount == notFound) - return newTableSize; - - if (keyCount < 8) - return newTableSize; - - if (isPowerOf2(keyCount)) - return keyCount * 4; - - return nextPowerOf2(keyCount) * 2; } -void Structure::materializePropertyMap() +void Structure::materializePropertyMap(JSGlobalData& globalData) { ASSERT(!m_propertyTable); @@ -358,13 +250,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(globalData, 0, m_offset + 1); break; } @@ -372,80 +264,46 @@ 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(globalData, this, structure->m_nameInPrevious.get(), m_anonymousSlotCount + structure->m_offset, structure->m_attributesInPrevious, structure->m_specificValueInPrevious.get()); + 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) +void Structure::despecifyDictionaryFunction(JSGlobalData& globalData, const Identifier& propertyName) { - const StringImpl* rep = propertyName.impl(); + StringImpl* rep = propertyName.impl(); - materializePropertyMapIfNecessary(); + materializePropertyMapIfNecessary(globalData); 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.clear(); } -PassRefPtr<Structure> Structure::addPropertyTransitionToExistingStructure(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset) +Structure* Structure::addPropertyTransitionToExistingStructure(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset) { 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.get(); + if (specificValueInPrevious && specificValueInPrevious != specificValue) + return 0; ASSERT(existingTransition->m_offset != noOffset); offset = existingTransition->m_offset + existingTransition->m_anonymousSlotCount; ASSERT(offset >= structure->m_anonymousSlotCount); @@ -456,8 +314,18 @@ PassRefPtr<Structure> Structure::addPropertyTransitionToExistingStructure(Struct return 0; } -PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset) +Structure* Structure::addPropertyTransition(JSGlobalData& globalData, 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)); @@ -466,43 +334,37 @@ PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, con specificValue = 0; if (structure->transitionCount() > s_maxTransitionLength) { - RefPtr<Structure> transition = toCacheableDictionaryTransition(structure); + Structure* transition = toCacheableDictionaryTransition(globalData, structure); ASSERT(structure != transition); - offset = transition->put(propertyName, attributes, specificValue); + offset = transition->putSpecificValue(globalData, propertyName, attributes, specificValue); ASSERT(offset >= structure->m_anonymousSlotCount); ASSERT(structure->m_anonymousSlotCount == transition->m_anonymousSlotCount); if (transition->propertyStorageSize() > transition->propertyStorageCapacity()) transition->growPropertyStorageCapacity(); - return transition.release(); + return transition; } - RefPtr<Structure> transition = create(structure->m_prototype.get(), structure->typeInfo(), structure->anonymousSlotCount()); + Structure* transition = create(globalData, structure); - transition->m_cachedPrototypeChain = structure->m_cachedPrototypeChain; - transition->m_previous = structure; + transition->m_cachedPrototypeChain.set(globalData, transition, structure->m_cachedPrototypeChain.get()); + transition->m_previous.set(globalData, transition, 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; + transition->m_specificValueInPrevious.set(globalData, transition, specificValue); 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(globalData, 0, structure->m_propertyTable->size() + 1); + else + transition->m_propertyTable = structure->m_propertyTable.release(); } else { if (structure->m_previous) - transition->materializePropertyMap(); + transition->materializePropertyMap(globalData); else - transition->createPropertyMapHashTable(); + transition->createPropertyMap(); } - offset = transition->put(propertyName, attributes, specificValue); + offset = transition->putSpecificValue(globalData, propertyName, attributes, specificValue); ASSERT(offset >= structure->m_anonymousSlotCount); ASSERT(structure->m_anonymousSlotCount == transition->m_anonymousSlotCount); if (transition->propertyStorageSize() > transition->propertyStorageCapacity()) @@ -510,183 +372,235 @@ PassRefPtr<Structure> 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); - return transition.release(); + structure->m_transitionTable.add(globalData, transition); + return transition; } -PassRefPtr<Structure> Structure::removePropertyTransition(Structure* structure, const Identifier& propertyName, size_t& offset) +Structure* Structure::removePropertyTransition(JSGlobalData& globalData, Structure* structure, const Identifier& propertyName, size_t& offset) { ASSERT(!structure->isUncacheableDictionary()); - RefPtr<Structure> transition = toUncacheableDictionaryTransition(structure); + Structure* transition = toUncacheableDictionaryTransition(globalData, structure); offset = transition->remove(propertyName); ASSERT(offset >= structure->m_anonymousSlotCount); ASSERT(structure->m_anonymousSlotCount == transition->m_anonymousSlotCount); - return transition.release(); + return transition; } -PassRefPtr<Structure> Structure::changePrototypeTransition(Structure* structure, JSValue prototype) +Structure* Structure::changePrototypeTransition(JSGlobalData& globalData, Structure* structure, JSValue prototype) { - RefPtr<Structure> transition = create(prototype, structure->typeInfo(), structure->anonymousSlotCount()); + Structure* transition = create(globalData, 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.set(globalData, transition, prototype); // Don't set m_offset, as one can not transition to this. - structure->materializePropertyMapIfNecessary(); - transition->m_propertyTable = structure->copyPropertyTable(); + structure->materializePropertyMapIfNecessary(globalData); + transition->m_propertyTable = structure->copyPropertyTable(globalData, transition); transition->m_isPinnedPropertyTable = true; ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount()); - return transition.release(); + return transition; } -PassRefPtr<Structure> Structure::despecifyFunctionTransition(Structure* structure, const Identifier& replaceFunction) +Structure* Structure::despecifyFunctionTransition(JSGlobalData& globalData, Structure* structure, const Identifier& replaceFunction) { ASSERT(structure->m_specificFunctionThrashCount < maxSpecificFunctionThrashCount); - RefPtr<Structure> transition = create(structure->storedPrototype(), structure->typeInfo(), structure->anonymousSlotCount()); + Structure* transition = create(globalData, 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. - structure->materializePropertyMapIfNecessary(); - transition->m_propertyTable = structure->copyPropertyTable(); + structure->materializePropertyMapIfNecessary(globalData); + transition->m_propertyTable = structure->copyPropertyTable(globalData, transition); transition->m_isPinnedPropertyTable = true; if (transition->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount) - transition->despecifyAllFunctions(); + transition->despecifyAllFunctions(globalData); else { - bool removed = transition->despecifyFunction(replaceFunction); + bool removed = transition->despecifyFunction(globalData, replaceFunction); ASSERT_UNUSED(removed, removed); } ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount()); - return transition.release(); + return transition; } -PassRefPtr<Structure> Structure::getterSetterTransition(Structure* structure) +Structure* Structure::getterSetterTransition(JSGlobalData& globalData, Structure* structure) { - RefPtr<Structure> 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; + Structure* transition = create(globalData, structure); // Don't set m_offset, as one can not transition to this. - structure->materializePropertyMapIfNecessary(); - transition->m_propertyTable = structure->copyPropertyTable(); + structure->materializePropertyMapIfNecessary(globalData); + transition->m_propertyTable = structure->copyPropertyTable(globalData, transition); transition->m_isPinnedPropertyTable = true; ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount()); - return transition.release(); + return transition; } -PassRefPtr<Structure> Structure::toDictionaryTransition(Structure* structure, DictionaryKind kind) +Structure* Structure::toDictionaryTransition(JSGlobalData& globalData, Structure* structure, DictionaryKind kind) { ASSERT(!structure->isUncacheableDictionary()); - RefPtr<Structure> transition = create(structure->m_prototype.get(), structure->typeInfo(), structure->anonymousSlotCount()); + Structure* transition = create(globalData, structure); + + structure->materializePropertyMapIfNecessary(globalData); + transition->m_propertyTable = structure->copyPropertyTable(globalData, transition); + transition->m_isPinnedPropertyTable = true; 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; - structure->materializePropertyMapIfNecessary(); - transition->m_propertyTable = structure->copyPropertyTable(); + ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount()); + return transition; +} + +Structure* Structure::toCacheableDictionaryTransition(JSGlobalData& globalData, Structure* structure) +{ + return toDictionaryTransition(globalData, structure, CachedDictionaryKind); +} + +Structure* Structure::toUncacheableDictionaryTransition(JSGlobalData& globalData, Structure* structure) +{ + return toDictionaryTransition(globalData, structure, UncachedDictionaryKind); +} + +// In future we may want to cache this transition. +Structure* Structure::sealTransition(JSGlobalData& globalData, Structure* structure) +{ + Structure* transition = preventExtensionsTransition(globalData, 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; +} + +// In future we may want to cache this transition. +Structure* Structure::freezeTransition(JSGlobalData& globalData, Structure* structure) +{ + Structure* transition = preventExtensionsTransition(globalData, 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; +} + +// In future we may want to cache this transition. +Structure* Structure::preventExtensionsTransition(JSGlobalData& globalData, Structure* structure) +{ + Structure* transition = create(globalData, structure); + + // Don't set m_offset, as one can not transition to this. + + structure->materializePropertyMapIfNecessary(globalData); + transition->m_propertyTable = structure->copyPropertyTable(globalData, transition); transition->m_isPinnedPropertyTable = true; - + transition->m_preventExtensions = true; + ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount()); - return transition.release(); + return transition; } -PassRefPtr<Structure> Structure::toCacheableDictionaryTransition(Structure* structure) +// In future we may want to cache this property. +bool Structure::isSealed(JSGlobalData& globalData) { - return toDictionaryTransition(structure, CachedDictionaryKind); + if (isExtensible()) + return false; + + materializePropertyMapIfNecessary(globalData); + 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; } -PassRefPtr<Structure> Structure::toUncacheableDictionaryTransition(Structure* structure) +// In future we may want to cache this property. +bool Structure::isFrozen(JSGlobalData& globalData) { - return toDictionaryTransition(structure, UncachedDictionaryKind); + if (isExtensible()) + return false; + + materializePropertyMapIfNecessary(globalData); + 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> Structure::flattenDictionaryStructure(JSGlobalData& globalData, JSObject* object) +Structure* Structure::flattenDictionaryStructure(JSGlobalData& globalData, JSObject* object) { ASSERT(isDictionary()); if (isUncacheableDictionary()) { ASSERT(m_propertyTable); - Vector<PropertyMapEntry*> 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<JSValue> 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<JSValue> 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; return this; } -size_t Structure::addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue) +size_t Structure::addPropertyWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, unsigned attributes, JSCell* specificValue) { ASSERT(!m_enumerationCache); if (m_specificFunctionThrashCount == maxSpecificFunctionThrashCount) specificValue = 0; - materializePropertyMapIfNecessary(); + materializePropertyMapIfNecessary(globalData); m_isPinnedPropertyTable = true; - size_t offset = put(propertyName, attributes, specificValue); + size_t offset = putSpecificValue(globalData, propertyName, attributes, specificValue); ASSERT(offset >= m_anonymousSlotCount); if (propertyStorageSize() > propertyStorageCapacity()) growPropertyStorageCapacity(); return offset; } -size_t Structure::removePropertyWithoutTransition(const Identifier& propertyName) +size_t Structure::removePropertyWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName) { ASSERT(isUncacheableDictionary()); ASSERT(!m_enumerationCache); - materializePropertyMapIfNecessary(); + materializePropertyMapIfNecessary(globalData); m_isPinnedPropertyTable = true; size_t offset = remove(propertyName); @@ -696,11 +610,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 +627,6 @@ PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger() #endif -static const unsigned deletedSentinelIndex = 1; - #if !DO_PROPERTYMAP_CONSTENCY_CHECK inline void Structure::checkConsistency() @@ -728,238 +635,82 @@ inline void Structure::checkConsistency() #endif -PropertyMapHashTable* Structure::copyPropertyTable() +PropertyTable* Structure::copyPropertyTable(JSGlobalData& globalData, Structure* owner) { - if (!m_propertyTable) - return 0; - - size_t tableSize = PropertyMapHashTable::allocationSize(m_propertyTable->size); - PropertyMapHashTable* newTable = static_cast<PropertyMapHashTable*>(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<unsigned>(*m_propertyTable->deletedOffsets); - - return newTable; + return m_propertyTable ? new PropertyTable(globalData, owner, *m_propertyTable) : 0; } -size_t Structure::get(const StringImpl* rep, unsigned& attributes, JSCell*& specificValue) +size_t Structure::get(JSGlobalData& globalData, StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue) { - materializePropertyMapIfNecessary(); + materializePropertyMapIfNecessary(globalData); if (!m_propertyTable) - return notFound; - - unsigned i = rep->existingHash(); - -#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 + return WTF::notFound; - entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; - if (entryIndex == emptyEntryIndex) - return notFound; + PropertyMapEntry* entry = m_propertyTable->find(propertyName).first; + if (!entry) + return WTF::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.get(); + ASSERT(entry->offset >= m_anonymousSlotCount); + return entry->offset; } -bool Structure::despecifyFunction(const Identifier& propertyName) +bool Structure::despecifyFunction(JSGlobalData& globalData, const Identifier& propertyName) { - ASSERT(!propertyName.isNull()); - - materializePropertyMapIfNecessary(); + materializePropertyMapIfNecessary(globalData); 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.clear(); + return true; } -void Structure::despecifyAllFunctions() +void Structure::despecifyAllFunctions(JSGlobalData& globalData) { - materializePropertyMapIfNecessary(); + materializePropertyMapIfNecessary(globalData); 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.clear(); } -size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue) +size_t Structure::putSpecificValue(JSGlobalData& globalData, const Identifier& propertyName, unsigned attributes, JSCell* specificValue) { ASSERT(!propertyName.isNull()); - ASSERT(get(propertyName) == notFound); + ASSERT(get(globalData, 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(globalData, this, 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 +722,119 @@ 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<unsigned>; - 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<PropertyMapHashTable*>(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) +void Structure::getPropertyNames(JSGlobalData& globalData, PropertyNameArray& propertyNames, EnumerationMode mode) { - ASSERT(m_propertyTable); - ASSERT(isPowerOf2(newTableSize)); - - checkConsistency(); - - PropertyMapHashTable* oldTable = m_propertyTable; + materializePropertyMapIfNecessary(globalData); + if (!m_propertyTable) + return; - m_propertyTable = static_cast<PropertyMapHashTable*>(fastZeroedMalloc(PropertyMapHashTable::allocationSize(newTableSize))); - m_propertyTable->size = newTableSize; - m_propertyTable->sizeMask = newTableSize - 1; + bool knownUnique = !propertyNames.size(); - 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]); + 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); } } - m_propertyTable->lastIndexUsed = lastIndexUsed; - m_propertyTable->deletedOffsets = oldTable->deletedOffsets; - - fastFree(oldTable); - - checkConsistency(); -} - -int comparePropertyMapEntryIndices(const void* a, const void* b) -{ - unsigned ia = static_cast<PropertyMapEntry* const*>(a)[0]->index; - unsigned ib = static_cast<PropertyMapEntry* const*>(b)[0]->index; - if (ia < ib) - return -1; - if (ia > ib) - return +1; - return 0; } -void Structure::getPropertyNames(PropertyNameArray& propertyNames, EnumerationMode mode) +void Structure::markChildren(MarkStack& markStack) { - 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); + JSCell::markChildren(markStack); + if (m_prototype) + markStack.append(&m_prototype); + if (m_cachedPrototypeChain) + markStack.append(&m_cachedPrototypeChain); + if (m_previous) + markStack.append(&m_previous); + if (m_specificValueInPrevious) + markStack.append(&m_specificValueInPrevious); + if (m_enumerationCache) + markStack.append(&m_enumerationCache); + if (m_propertyTable) { + PropertyTable::iterator end = m_propertyTable->end(); + for (PropertyTable::iterator ptr = m_propertyTable->begin(); ptr != end; ++ptr) { + if (ptr->specificValue) + markStack.append(&ptr->specificValue); } - - return; - } - - // Allocate a buffer to use to sort the keys. - Vector<PropertyMapEntry*, smallMapThreshold> sortedEnumerables(m_propertyTable->keyCount); - - // 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]; - } - - 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); } } #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 +843,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..fe9ce6b 100644 --- a/Source/JavaScriptCore/runtime/Structure.h +++ b/Source/JavaScriptCore/runtime/Structure.h @@ -27,67 +27,69 @@ #define Structure_h #include "Identifier.h" +#include "JSCell.h" #include "JSType.h" #include "JSValue.h" #include "PropertyMapHashTable.h" #include "PropertyNameArray.h" #include "Protect.h" -#include "StructureChain.h" #include "StructureTransitionTable.h" #include "JSTypeInfo.h" #include "UString.h" -#include "WeakGCPtr.h" +#include "Weak.h" #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> -#ifndef NDEBUG -#define DUMP_PROPERTYMAP_STATS 0 -#else -#define DUMP_PROPERTYMAP_STATS 0 -#endif namespace JSC { class MarkStack; class PropertyNameArray; class PropertyNameArrayData; + class StructureChain; + + struct ClassInfo; enum EnumerationMode { ExcludeDontEnumProperties, IncludeDontEnumProperties }; - class Structure : public RefCounted<Structure> { + class Structure : public JSCell { public: - friend class JIT; friend class StructureTransitionTable; - static PassRefPtr<Structure> create(JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount) + static Structure* create(JSGlobalData& globalData, JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount, const ClassInfo* classInfo) { - return adoptRef(new Structure(prototype, typeInfo, anonymousSlotCount)); + ASSERT(globalData.structureStructure); + return new (&globalData) Structure(globalData, prototype, typeInfo, anonymousSlotCount, classInfo); } - static void startIgnoringLeaks(); - static void stopIgnoringLeaks(); - static void dumpStatistics(); - static PassRefPtr<Structure> addPropertyTransition(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset); - static PassRefPtr<Structure> addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset); - static PassRefPtr<Structure> removePropertyTransition(Structure*, const Identifier& propertyName, size_t& offset); - static PassRefPtr<Structure> changePrototypeTransition(Structure*, JSValue prototype); - static PassRefPtr<Structure> despecifyFunctionTransition(Structure*, const Identifier&); - static PassRefPtr<Structure> getterSetterTransition(Structure*); - static PassRefPtr<Structure> toCacheableDictionaryTransition(Structure*); - static PassRefPtr<Structure> toUncacheableDictionaryTransition(Structure*); + static Structure* addPropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset); + static Structure* addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset); + static Structure* removePropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, size_t& offset); + static Structure* changePrototypeTransition(JSGlobalData&, Structure*, JSValue prototype); + static Structure* despecifyFunctionTransition(JSGlobalData&, Structure*, const Identifier&); + static Structure* getterSetterTransition(JSGlobalData&, Structure*); + static Structure* toCacheableDictionaryTransition(JSGlobalData&, Structure*); + static Structure* toUncacheableDictionaryTransition(JSGlobalData&, Structure*); + static Structure* sealTransition(JSGlobalData&, Structure*); + static Structure* freezeTransition(JSGlobalData&, Structure*); + static Structure* preventExtensionsTransition(JSGlobalData&, Structure*); - PassRefPtr<Structure> flattenDictionaryStructure(JSGlobalData&, JSObject*); + bool isSealed(JSGlobalData&); + bool isFrozen(JSGlobalData&); + bool isExtensible() const { return !m_preventExtensions; } + + Structure* flattenDictionaryStructure(JSGlobalData&, JSObject*); ~Structure(); // These should be used with caution. - size_t addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue); - size_t removePropertyWithoutTransition(const Identifier& propertyName); - void setPrototypeWithoutTransition(JSValue prototype) { m_prototype = prototype; } + size_t addPropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName, unsigned attributes, JSCell* specificValue); + size_t removePropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName); + void setPrototypeWithoutTransition(JSGlobalData& globalData, JSValue prototype) { m_prototype.set(globalData, this, prototype); } bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; } bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; } @@ -95,32 +97,23 @@ namespace JSC { const TypeInfo& typeInfo() const { return m_typeInfo; } JSValue storedPrototype() const { return m_prototype.get(); } - DeprecatedPtr<Unknown>* storedPrototypeSlot() { return &m_prototype; } JSValue prototypeForLookup(ExecState*) const; StructureChain* prototypeChain(ExecState*) const; + void markChildren(MarkStack&); Structure* previousID() const { return m_previous.get(); } 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<unsigned>(m_offset + 1)); } + unsigned propertyStorageSize() const { return m_anonymousSlotCount + (m_propertyTable ? m_propertyTable->propertyStorageSize() : static_cast<unsigned>(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(const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue) + size_t get(JSGlobalData&, const Identifier& propertyName); + size_t get(JSGlobalData&, StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue); + size_t get(JSGlobalData& globalData, 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); + return get(globalData, propertyName.impl(), attributes, specificValue); } bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; } @@ -131,48 +124,73 @@ 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 despecifyDictionaryFunction(JSGlobalData&, 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. JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h. - void getPropertyNames(PropertyNameArray&, EnumerationMode mode); - + void getPropertyNames(JSGlobalData&, PropertyNameArray&, EnumerationMode mode); + + const ClassInfo* classInfo() const { return m_classInfo; } + + static ptrdiff_t prototypeOffset() + { + return OBJECT_OFFSETOF(Structure, m_prototype); + } + + static ptrdiff_t typeInfoFlagsOffset() + { + return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::flagsOffset(); + } + + static ptrdiff_t typeInfoTypeOffset() + { + return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::typeOffset(); + } + + static Structure* createStructure(JSGlobalData& globalData) + { + ASSERT(!globalData.structureStructure); + return new (&globalData) Structure(globalData); + } + private: + Structure(JSGlobalData&, JSValue prototype, const TypeInfo&, unsigned anonymousSlotCount, const ClassInfo*); + Structure(JSGlobalData&); + Structure(JSGlobalData&, const Structure*); + + static Structure* create(JSGlobalData& globalData, const Structure* structure) + { + ASSERT(globalData.structureStructure); + return new (&globalData) Structure(globalData, structure); + } + + static const ClassInfo s_info; - Structure(JSValue prototype, const TypeInfo&, unsigned anonymousSlotCount); - typedef enum { NoneDictionaryKind = 0, CachedDictionaryKind = 1, UncachedDictionaryKind = 2 } DictionaryKind; - static PassRefPtr<Structure> toDictionaryTransition(Structure*, DictionaryKind); + static Structure* toDictionaryTransition(JSGlobalData&, Structure*, DictionaryKind); - size_t put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue); + size_t putSpecificValue(JSGlobalData&, 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(); + bool despecifyFunction(JSGlobalData&, const Identifier&); + void despecifyAllFunctions(JSGlobalData&); - PropertyMapHashTable* copyPropertyTable(); - void materializePropertyMap(); - void materializePropertyMapIfNecessary() + PropertyTable* copyPropertyTable(JSGlobalData&, Structure* owner); + void materializePropertyMap(JSGlobalData&); + void materializePropertyMapIfNecessary(JSGlobalData& globalData) { - if (m_propertyTable || !m_previous) - return; - materializePropertyMap(); + if (!m_propertyTable && m_previous) + materializePropertyMap(globalData); } signed char transitionCount() const @@ -181,24 +199,8 @@ namespace JSC { return m_offset == noOffset ? 0 : m_offset + 1; } - typedef std::pair<Structure*, Structure*> Transition; - typedef HashMap<StructureTransitionTableHash::Key, Transition, StructureTransitionTableHash, StructureTransitionTableHashTraits> 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; @@ -207,22 +209,20 @@ namespace JSC { TypeInfo m_typeInfo; - DeprecatedPtr<Unknown> m_prototype; - mutable RefPtr<StructureChain> m_cachedPrototypeChain; + WriteBarrier<Unknown> m_prototype; + mutable WriteBarrier<StructureChain> m_cachedPrototypeChain; - RefPtr<Structure> m_previous; + WriteBarrier<Structure> m_previous; RefPtr<StringImpl> m_nameInPrevious; - JSCell* m_specificValueInPrevious; + WriteBarrier<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; - WeakGCPtr<JSPropertyNameIterator> m_enumerationCache; + StructureTransitionTable m_transitionTable; - PropertyMapHashTable* m_propertyTable; + WriteBarrier<JSPropertyNameIterator> m_enumerationCache; + + OwnPtr<PropertyTable> m_propertyTable; uint32_t m_propertyStorageCapacity; @@ -243,53 +243,61 @@ 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) + inline size_t Structure::get(JSGlobalData& globalData, const Identifier& propertyName) { - ASSERT(!propertyName.isNull()); - - materializePropertyMapIfNecessary(); + materializePropertyMapIfNecessary(globalData); if (!m_propertyTable) - return WTF::notFound; - - StringImpl* rep = propertyName.impl(); + return notFound; - 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; + PropertyMapEntry* entry = m_propertyTable->find(propertyName.impl()).first; + ASSERT(!entry || entry->offset >= m_anonymousSlotCount); + return entry ? entry->offset : notFound; + } - if (rep == m_propertyTable->entries()[entryIndex - 1].key) - return m_propertyTable->entries()[entryIndex - 1].offset; + inline bool JSCell::isObject() const + { + return m_structure->typeInfo().type() == ObjectType; + } -#if DUMP_PROPERTYMAP_STATS - ++numCollisions; -#endif + inline bool JSCell::isString() const + { + return m_structure->typeInfo().type() == StringType; + } - unsigned k = 1 | WTF::doubleHash(rep->existingHash()); + inline const ClassInfo* JSCell::classInfo() const + { + return m_structure->classInfo(); + } - while (1) { - i += k; + inline Structure* JSCell::createDummyStructure(JSGlobalData& globalData) + { + return Structure::create(globalData, jsNull(), TypeInfo(UnspecifiedType), AnonymousSlotCount, 0); + } -#if DUMP_PROPERTYMAP_STATS - ++numRehashes; -#endif + inline bool JSValue::needsThisConversion() const + { + if (UNLIKELY(!isCell())) + return true; + return asCell()->structure()->typeInfo().needsThisConversion(); + } - entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; - if (entryIndex == emptyEntryIndex) - return WTF::notFound; + ALWAYS_INLINE void MarkStack::internalAppend(JSCell* cell) + { + ASSERT(!m_isCheckingForDefaultMarkViolation); + ASSERT(cell); + if (Heap::testAndSetMarked(cell)) + return; + if (cell->structure()->typeInfo().type() >= CompoundType) + m_values.append(cell); + } - if (rep == m_propertyTable->entries()[entryIndex - 1].key) - return m_propertyTable->entries()[entryIndex - 1].offset; - } + inline StructureTransitionTable::Hash::Key StructureTransitionTable::keyForWeakGCMapFinalizer(void*, Structure* structure) + { + return Hash::Key(structure->m_nameInPrevious.get(), structure->m_attributesInPrevious); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/StructureChain.cpp b/Source/JavaScriptCore/runtime/StructureChain.cpp index e4523c3..ad6abff 100644 --- a/Source/JavaScriptCore/runtime/StructureChain.cpp +++ b/Source/JavaScriptCore/runtime/StructureChain.cpp @@ -31,19 +31,33 @@ #include <wtf/RefPtr.h> namespace JSC { + +ClassInfo StructureChain::s_info = { "StructureChain", 0, 0, 0 }; -StructureChain::StructureChain(Structure* head) +StructureChain::StructureChain(JSGlobalData& globalData, Structure* structure, Structure* head) + : JSCell(globalData, structure) { size_t size = 0; for (Structure* current = head; current; current = current->storedPrototype().isNull() ? 0 : asObject(current->storedPrototype())->structure()) ++size; - m_vector = adoptArrayPtr(new RefPtr<Structure>[size + 1]); + m_vector = adoptArrayPtr(new WriteBarrier<Structure>[size + 1]); size_t i = 0; for (Structure* current = head; current; current = current->storedPrototype().isNull() ? 0 : asObject(current->storedPrototype())->structure()) - m_vector[i++] = current; - m_vector[i] = 0; + m_vector[i++].set(globalData, this, current); + m_vector[i].clear(); +} + +StructureChain::~StructureChain() +{ +} + +void StructureChain::markChildren(MarkStack& markStack) +{ + size_t i = 0; + while (m_vector[i]) + markStack.append(&m_vector[i++]); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/StructureChain.h b/Source/JavaScriptCore/runtime/StructureChain.h index 816b66d..b984be6 100644 --- a/Source/JavaScriptCore/runtime/StructureChain.h +++ b/Source/JavaScriptCore/runtime/StructureChain.h @@ -26,6 +26,9 @@ #ifndef StructureChain_h #define StructureChain_h +#include "JSCell.h" +#include "Structure.h" + #include <wtf/OwnArrayPtr.h> #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> @@ -35,17 +38,21 @@ namespace JSC { class Structure; - class StructureChain : public RefCounted<StructureChain> { + class StructureChain : public JSCell { friend class JIT; public: - static PassRefPtr<StructureChain> create(Structure* head) { return adoptRef(new StructureChain(head)); } - RefPtr<Structure>* head() { return m_vector.get(); } + static StructureChain* create(JSGlobalData& globalData, Structure* head) { return new (&globalData) StructureChain(globalData, globalData.structureChainStructure.get(), head); } + WriteBarrier<Structure>* head() { return m_vector.get(); } + void markChildren(MarkStack&); - private: - StructureChain(Structure* head); + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { return Structure::create(globalData, prototype, TypeInfo(CompoundType, OverridesMarkChildren), 0, &s_info); } - OwnArrayPtr<RefPtr<Structure> > m_vector; + private: + StructureChain(JSGlobalData&, Structure*, Structure* head); + ~StructureChain(); + OwnArrayPtr<WriteBarrier<Structure> > m_vector; + static ClassInfo s_info; }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/StructureTransitionTable.h b/Source/JavaScriptCore/runtime/StructureTransitionTable.h index 7e9d7ff..adebad2 100644 --- a/Source/JavaScriptCore/runtime/StructureTransitionTable.h +++ b/Source/JavaScriptCore/runtime/StructureTransitionTable.h @@ -27,17 +27,20 @@ #define StructureTransitionTable_h #include "UString.h" +#include "WeakGCMap.h" #include <wtf/HashFunctions.h> -#include <wtf/HashMap.h> #include <wtf/HashTraits.h> #include <wtf/OwnPtr.h> #include <wtf/RefPtr.h> namespace JSC { - class Structure; +class Structure; - struct StructureTransitionTableHash { +class StructureTransitionTable { + static const intptr_t UsingSingleSlotFlag = 1; + + struct Hash { typedef std::pair<RefPtr<StringImpl>, 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<RefPtr<StringImpl> > FirstTraits; typedef WTF::GenericHashTraits<unsigned> SecondTraits; typedef std::pair<FirstTraits::TraitType, SecondTraits::TraitType > TraitType; @@ -66,6 +69,105 @@ namespace JSC { static bool isDeletedValue(const TraitType& value) { return FirstTraits::isDeletedValue(value.first); } }; + struct WeakGCMapFinalizerCallback { + static void* finalizerContextFor(Hash::Key) + { + return 0; + } + + static inline Hash::Key keyForFinalizer(void* context, Structure* structure) + { + return keyForWeakGCMapFinalizer(context, structure); + } + }; + + typedef WeakGCMap<Hash::Key, Structure, WeakGCMapFinalizerCallback, Hash, HashTraits> TransitionMap; + + static Hash::Key keyForWeakGCMapFinalizer(void* context, Structure*); + +public: + StructureTransitionTable() + : m_data(UsingSingleSlotFlag) + { + } + + ~StructureTransitionTable() + { + if (!isUsingSingleSlot()) + delete map(); + else + clearSingleTransition(); + } + + inline void add(JSGlobalData&, 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<TransitionMap*>(m_data); + } + + HandleSlot slot() const + { + ASSERT(isUsingSingleSlot()); + return reinterpret_cast<HandleSlot>(m_data & ~UsingSingleSlotFlag); + } + + void setMap(TransitionMap* map) + { + ASSERT(isUsingSingleSlot()); + + if (HandleSlot slot = this->slot()) + HandleHeap::heapFor(slot)->deallocate(slot); + + // This implicitly clears the flag that indicates we're using a single transition + m_data = reinterpret_cast<intptr_t>(map); + + ASSERT(!isUsingSingleSlot()); + } + + Structure* singleTransition() const + { + ASSERT(isUsingSingleSlot()); + if (HandleSlot slot = this->slot()) { + if (*slot) + return reinterpret_cast<Structure*>(slot->asCell()); + } + return 0; + } + + void clearSingleTransition() + { + ASSERT(isUsingSingleSlot()); + if (HandleSlot slot = this->slot()) + HandleHeap::heapFor(slot)->deallocate(slot); + } + + void setSingleTransition(JSGlobalData& globalData, Structure* structure) + { + ASSERT(isUsingSingleSlot()); + HandleSlot slot = this->slot(); + if (!slot) { + slot = globalData.allocateGlobalHandle(); + HandleHeap::heapFor(slot)->makeWeak(slot, 0, 0); + m_data = reinterpret_cast<intptr_t>(slot) | UsingSingleSlotFlag; + } + HandleHeap::heapFor(slot)->writeBarrier(slot, reinterpret_cast<JSCell*>(structure)); + *slot = reinterpret_cast<JSCell*>(structure); + } + + intptr_t m_data; +}; + } // namespace JSC #endif // StructureTransitionTable_h diff --git a/Source/JavaScriptCore/runtime/TimeoutChecker.cpp b/Source/JavaScriptCore/runtime/TimeoutChecker.cpp index 04d904d..d3867d4 100644 --- a/Source/JavaScriptCore/runtime/TimeoutChecker.cpp +++ b/Source/JavaScriptCore/runtime/TimeoutChecker.cpp @@ -101,7 +101,7 @@ static inline unsigned getCPUTime() // use a relative time from first call in order to avoid an overflow static double firstTime = currentTime(); - return (currentTime() - firstTime) * 1000; + return static_cast<unsigned> ((currentTime() - firstTime) * 1000); #endif } diff --git a/Source/JavaScriptCore/runtime/UString.h b/Source/JavaScriptCore/runtime/UString.h index 8f6c083..b98e7b4 100644 --- a/Source/JavaScriptCore/runtime/UString.h +++ b/Source/JavaScriptCore/runtime/UString.h @@ -252,10 +252,7 @@ template<> struct DefaultHash<JSC::UString> { typedef JSC::UStringHash Hash; }; -template <> struct VectorTraits<JSC::UString> : SimpleClassVectorTraits -{ - static const bool canInitializeWithMemset = true; -}; +template <> struct VectorTraits<JSC::UString> : SimpleClassVectorTraits { }; } // namespace WTF diff --git a/Source/JavaScriptCore/runtime/WeakGCMap.h b/Source/JavaScriptCore/runtime/WeakGCMap.h index 7bf4503..5ad1c62 100644 --- a/Source/JavaScriptCore/runtime/WeakGCMap.h +++ b/Source/JavaScriptCore/runtime/WeakGCMap.h @@ -26,110 +26,165 @@ #ifndef WeakGCMap_h #define WeakGCMap_h -#include "Heap.h" +#include "Handle.h" +#include "JSGlobalData.h" #include <wtf/HashMap.h> namespace JSC { -class JSCell; +// A HashMap for GC'd values that removes entries when the associated value +// dies. +template <typename KeyType, typename MappedType> struct DefaultWeakGCMapFinalizerCallback { + static void* finalizerContextFor(KeyType key) + { + return reinterpret_cast<void*>(key); + } + + static KeyType keyForFinalizer(void* context, typename HandleTypes<MappedType>::ExternalType) + { + return reinterpret_cast<KeyType>(context); + } +}; -// A HashMap whose get() function returns emptyValue() for cells awaiting destruction. -template<typename KeyType, typename MappedType> -class WeakGCMap { +template<typename KeyType, typename MappedType, typename FinalizerCallback = DefaultWeakGCMapFinalizerCallback<KeyType, MappedType>, typename HashArg = typename DefaultHash<KeyType>::Hash, typename KeyTraitsArg = HashTraits<KeyType> > +class WeakGCMap : private WeakHandleOwner { 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<KeyType, HandleSlot, HashArg, KeyTraitsArg> MapType; + typedef typename HandleTypes<MappedType>::ExternalType ExternalType; + typedef typename MapType::iterator map_iterator; public: - typedef typename HashMap<KeyType, DeprecatedPtr<MappedType> >::iterator iterator; - typedef typename HashMap<KeyType, DeprecatedPtr<MappedType> >::const_iterator const_iterator; - + + struct iterator { + friend class WeakGCMap; + iterator(map_iterator iter) + : m_iterator(iter) + { + } + + std::pair<KeyType, ExternalType> get() const { return std::make_pair(m_iterator->first, HandleTypes<MappedType>::getFromSlot(m_iterator->second)); } + std::pair<KeyType, HandleSlot> 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<iterator, bool> set(const KeyType&, MappedType*); - MappedType* take(const KeyType&); + bool contains(const KeyType& key) const + { + return m_map.contains(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(); } + iterator find(const KeyType& key) + { + return m_map.find(key); + } - MappedType* uncheckedGet(const KeyType& key) const { return m_map.get(key).get(); } - DeprecatedPtr<MappedType>* uncheckedGetSlot(const KeyType& key) + void remove(iterator iter) { - iterator iter = m_map.find(key); - if (iter == m_map.end()) - return 0; - return &iter->second; + ASSERT(iter.m_iterator != m_map.end()); + HandleSlot slot = iter.m_iterator->second; + ASSERT(slot); + HandleHeap::heapFor(slot)->deallocate(slot); + m_map.remove(iter.m_iterator); } - bool uncheckedRemove(const KeyType&, MappedType*); - iterator uncheckedBegin() { return m_map.begin(); } - iterator uncheckedEnd() { return m_map.end(); } + ExternalType get(const KeyType& key) const + { + return HandleTypes<MappedType>::getFromSlot(m_map.get(key)); + } - const_iterator uncheckedBegin() const { return m_map.begin(); } - const_iterator uncheckedEnd() const { return m_map.end(); } + HandleSlot getSlot(const KeyType& key) const + { + return m_map.get(key); + } - bool isValid(iterator it) const { return Heap::isMarked(it->second.get()); } - bool isValid(const_iterator it) const { return Heap::isMarked(it->second.get()); } + pair<iterator, bool> add(JSGlobalData& globalData, const KeyType& key, ExternalType value) + { + pair<typename MapType::iterator, bool> iter = m_map.add(key, 0); + if (iter.second) { + HandleSlot slot = globalData.allocateGlobalHandle(); + iter.first->second = slot; + HandleHeap::heapFor(slot)->makeWeak(slot, this, FinalizerCallback::finalizerContextFor(key)); + HandleHeap::heapFor(slot)->writeBarrier(slot, value); + *slot = value; + } + return iter; + } + + void set(iterator iter, ExternalType value) + { + HandleSlot slot = iter.m_iterator->second; + ASSERT(slot); + HandleHeap::heapFor(slot)->writeBarrier(slot, value); + *slot = value; + } -private: - HashMap<KeyType, DeprecatedPtr<MappedType> > m_map; -}; + void set(JSGlobalData& globalData, const KeyType& key, ExternalType value) + { + pair<typename MapType::iterator, bool> iter = m_map.add(key, 0); + HandleSlot slot = iter.first->second; + if (iter.second) { + slot = globalData.allocateGlobalHandle(); + HandleHeap::heapFor(slot)->makeWeak(slot, this, key); + iter.first->second = slot; + } + HandleHeap::heapFor(slot)->writeBarrier(slot, value); + *slot = value; + } -template<typename KeyType, typename MappedType> -inline MappedType* WeakGCMap<KeyType, MappedType>::get(const KeyType& key) const -{ - MappedType* result = m_map.get(key).get(); - if (result == HashTraits<MappedType*>::emptyValue()) - return result; - if (!Heap::isMarked(result)) - return HashTraits<MappedType*>::emptyValue(); - return result; -} - -template<typename KeyType, typename MappedType> -MappedType* WeakGCMap<KeyType, MappedType>::take(const KeyType& key) -{ - MappedType* result = m_map.take(key).get(); - if (result == HashTraits<MappedType*>::emptyValue()) + ExternalType take(const KeyType& key) + { + HandleSlot slot = m_map.take(key); + if (!slot) + return HashTraits<ExternalType>::emptyValue(); + ExternalType result = HandleTypes<MappedType>::getFromSlot(slot); + HandleHeap::heapFor(slot)->deallocate(slot); return result; - if (!Heap::isMarked(result)) - return HashTraits<MappedType*>::emptyValue(); - return result; -} - -template<typename KeyType, typename MappedType> -pair<typename WeakGCMap<KeyType, MappedType>::iterator, bool> WeakGCMap<KeyType, MappedType>::set(const KeyType& key, MappedType* value) -{ - Heap::setMarked(value); // If value is newly allocated, it's not marked, so mark it now. - pair<iterator, bool> result = m_map.add(key, value); - if (!result.second) { // pre-existing entry - result.second = !Heap::isMarked(result.first->second.get()); - result.first->second = value; } - return result; -} - -template<typename KeyType, typename MappedType> -bool WeakGCMap<KeyType, MappedType>::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; -} + + size_t size() { return m_map.size(); } + + iterator begin() { return iterator(m_map.begin()); } + iterator end() { return iterator(m_map.end()); } + + ~WeakGCMap() + { + clear(); + } + +private: + virtual void finalize(Handle<Unknown> handle, void* context) + { + HandleSlot slot = m_map.take(FinalizerCallback::keyForFinalizer(context, HandleTypes<MappedType>::getFromSlot(handle.slot()))); + ASSERT(slot); + HandleHeap::heapFor(slot)->deallocate(slot); + } + + MapType m_map; +}; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/WeakGCPtr.h b/Source/JavaScriptCore/runtime/WeakGCPtr.h deleted file mode 100644 index 4946ee7..0000000 --- a/Source/JavaScriptCore/runtime/WeakGCPtr.h +++ /dev/null @@ -1,153 +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. 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 WeakGCPtr_h -#define WeakGCPtr_h - -#include "Heap.h" -#include "GCHandle.h" - -namespace JSC { - -// A smart pointer whose get() function returns 0 for cells awaiting destruction. -template <typename T> class WeakGCPtr { - WTF_MAKE_NONCOPYABLE(WeakGCPtr); -public: - WeakGCPtr() - : m_ptr(0) - { - } - - WeakGCPtr(T* ptr) { assign(ptr); } - - ~WeakGCPtr() - { - if (m_ptr) - m_ptr->pool()->free(m_ptr); - } - - T* get() const - { - if (m_ptr && m_ptr->isValidPtr()) - return static_cast<T*>(m_ptr->get()); - return 0; - } - - bool clear(JSCell* p) - { - if (!m_ptr || m_ptr->get() != p) - return false; - - m_ptr->pool()->free(m_ptr); - m_ptr = 0; - return true; - } - - T& operator*() const { return *get(); } - T* operator->() const { return get(); } - - bool operator!() const { return !get(); } - - // 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 - - WeakGCPtr& operator=(T*); - -#if !ASSERT_DISABLED - bool hasDeadObject() const { return !!m_ptr; } -#endif - -private: - void assign(JSCell* ptr) - { - ASSERT(ptr); - if (m_ptr) - m_ptr->set(ptr); - else - m_ptr = Heap::heap(ptr)->addWeakGCHandle(ptr); - } - - WeakGCHandle* m_ptr; -}; - -template <typename T> inline WeakGCPtr<T>& WeakGCPtr<T>::operator=(T* optr) -{ - assign(optr); - return *this; -} - -template <typename T, typename U> inline bool operator==(const WeakGCPtr<T>& a, const WeakGCPtr<U>& b) -{ - return a.get() == b.get(); -} - -template <typename T, typename U> inline bool operator==(const WeakGCPtr<T>& a, U* b) -{ - return a.get() == b; -} - -template <typename T, typename U> inline bool operator==(T* a, const WeakGCPtr<U>& b) -{ - return a == b.get(); -} - -template <typename T, typename U> inline bool operator!=(const WeakGCPtr<T>& a, const WeakGCPtr<U>& b) -{ - return a.get() != b.get(); -} - -template <typename T, typename U> inline bool operator!=(const WeakGCPtr<T>& a, U* b) -{ - return a.get() != b; -} - -template <typename T, typename U> inline bool operator!=(T* a, const WeakGCPtr<U>& b) -{ - return a != b.get(); -} - -template <typename T, typename U> inline WeakGCPtr<T> static_pointer_cast(const WeakGCPtr<U>& p) -{ - return WeakGCPtr<T>(static_cast<T*>(p.get())); -} - -template <typename T, typename U> inline WeakGCPtr<T> const_pointer_cast(const WeakGCPtr<U>& p) -{ - return WeakGCPtr<T>(const_cast<T*>(p.get())); -} - -template <typename T> inline T* get(const WeakGCPtr<T>& 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..32cb968 100644 --- a/Source/JavaScriptCore/runtime/WriteBarrier.h +++ b/Source/JavaScriptCore/runtime/WriteBarrier.h @@ -32,62 +32,59 @@ namespace JSC { class JSCell; class JSGlobalData; -typedef enum { } Unknown; - -template <class T> class DeprecatedPtr { -public: - DeprecatedPtr() : m_cell(0) { } - DeprecatedPtr(T* cell) : m_cell(reinterpret_cast<JSCell*>(cell)) { } - T* get() const { return reinterpret_cast<T*>(m_cell); } - T* operator*() const { return static_cast<T*>(m_cell); } - T* operator->() const { return static_cast<T*>(m_cell); } - - JSCell** slot() { return &m_cell; } - - typedef T* (DeprecatedPtr::*UnspecifiedBoolType); - operator UnspecifiedBoolType*() const { return m_cell ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; } - - bool operator!() const { return !m_cell; } +inline void writeBarrier(JSGlobalData&, const JSCell*, JSValue) +{ +} -protected: - JSCell* m_cell; -}; +inline void writeBarrier(JSGlobalData&, const JSCell*, JSCell*) +{ +} -template <> class DeprecatedPtr<Unknown> { -public: - DeprecatedPtr() { } - DeprecatedPtr(JSValue value) : m_value(value) { } - DeprecatedPtr(JSCell* value) : m_value(value) { } - const JSValue& get() const { return m_value; } - const JSValue* operator*() const { return &m_value; } - const JSValue* operator->() const { return &m_value; } - - JSValue* slot() { return &m_value; } - - typedef JSValue (DeprecatedPtr::*UnspecifiedBoolType); - operator UnspecifiedBoolType*() const { return m_value ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; } - bool operator!() const { return !m_value; } - -private: - JSValue m_value; -}; +typedef enum { } Unknown; +typedef JSValue* HandleSlot; -template <typename T> struct WriteBarrierCheck { +template <typename T> struct JSValueChecker { static const bool IsJSValue = false; }; -template <> struct WriteBarrierCheck<JSValue> { +template <> struct JSValueChecker<JSValue> { static const bool IsJSValue = true; }; +// We have a separate base class with no constructors for use in Unions. template <typename T> class WriteBarrierBase { public: - COMPILE_ASSERT(!WriteBarrierCheck<T>::IsJSValue, WriteBarrier_JSValue_is_invalid__use_unknown); - void set(JSGlobalData&, const JSCell*, T* value) { this->m_cell = reinterpret_cast<JSCell*>(value); } + COMPILE_ASSERT(!JSValueChecker<T>::IsJSValue, WriteBarrier_JSValue_is_invalid__use_unknown); + void set(JSGlobalData& globalData, const JSCell* owner, T* value) + { + this->m_cell = reinterpret_cast<JSCell*>(value); + writeBarrier(globalData, owner, this->m_cell); +#if ENABLE(JSC_ZOMBIES) + ASSERT(!isZombie(owner)); + ASSERT(!isZombie(m_cell)); +#endif + } - T* get() const { return reinterpret_cast<T*>(m_cell); } - T* operator*() const { return static_cast<T*>(m_cell); } - T* operator->() const { return static_cast<T*>(m_cell); } + T* get() const + { + return reinterpret_cast<T*>(m_cell); + } + + T* operator*() const + { + ASSERT(m_cell); +#if ENABLE(JSC_ZOMBIES) + ASSERT(!isZombie(m_cell)); +#endif + return static_cast<T*>(m_cell); + } + + T* operator->() const + { + ASSERT(m_cell); + return static_cast<T*>(m_cell); + } + void clear() { m_cell = 0; } JSCell** slot() { return &m_cell; } @@ -97,30 +94,46 @@ public: bool operator!() const { return !m_cell; } - void setWithoutWriteBarrier(T* value) { this->m_cell = reinterpret_cast<JSCell*>(value); } + void setWithoutWriteBarrier(T* value) + { + this->m_cell = reinterpret_cast<JSCell*>(value); +#if ENABLE(JSC_ZOMBIES) + ASSERT(!m_cell || !isZombie(m_cell)); +#endif + } -protected: +private: JSCell* m_cell; }; -template <typename T> class WriteBarrier : public WriteBarrierBase<T> { +template <> class WriteBarrierBase<Unknown> { public: - WriteBarrier() { this->m_cell = 0; } - WriteBarrier(JSGlobalData& globalData, const JSCell* owner, T* value) + void set(JSGlobalData& globalData, const JSCell* owner, JSValue value) { - this->set(globalData, owner, value); +#if ENABLE(JSC_ZOMBIES) + ASSERT(!isZombie(owner)); + ASSERT(!value.isZombie()); +#endif + m_value = JSValue::encode(value); + writeBarrier(globalData, owner, value); + } + void setWithoutWriteBarrier(JSValue value) + { +#if ENABLE(JSC_ZOMBIES) + ASSERT(!value.isZombie()); +#endif + m_value = JSValue::encode(value); } -}; - -template <> class WriteBarrierBase<Unknown> { -public: - void set(JSGlobalData&, const JSCell*, JSValue value) { m_value = JSValue::encode(value); } - void setWithoutWriteBarrier(JSValue value) { m_value = JSValue::encode(value); } - JSValue get() const { return JSValue::decode(m_value); } + JSValue get() const + { + return JSValue::decode(m_value); + } void clear() { m_value = JSValue::encode(JSValue()); } void setUndefined() { m_value = JSValue::encode(jsUndefined()); } bool isNumber() const { return get().isNumber(); } + bool isObject() const { return get().isObject(); } + bool isNull() const { return get().isNull(); } bool isGetterSetter() const { return get().isGetterSetter(); } JSValue* slot() @@ -137,29 +150,41 @@ public: operator UnspecifiedBoolType*() const { return get() ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; } bool operator!() const { return !get(); } -protected: +private: EncodedJSValue m_value; }; +template <typename T> class WriteBarrier : public WriteBarrierBase<T> { +public: + WriteBarrier() + { + this->setWithoutWriteBarrier(0); + } + + WriteBarrier(JSGlobalData& globalData, const JSCell* owner, T* value) + { + this->set(globalData, owner, value); + } +}; + template <> class WriteBarrier<Unknown> : public WriteBarrierBase<Unknown> { public: - WriteBarrier() { m_value = JSValue::encode(JSValue()); } + WriteBarrier() + { + this->setWithoutWriteBarrier(JSValue()); + } + WriteBarrier(JSGlobalData& globalData, const JSCell* owner, JSValue value) { this->set(globalData, owner, value); } }; -template <typename U, typename V> inline bool operator==(const DeprecatedPtr<U>& lhs, const DeprecatedPtr<V>& rhs) -{ - return lhs.get() == rhs.get(); -} - template <typename U, typename V> inline bool operator==(const WriteBarrierBase<U>& lhs, const WriteBarrierBase<V>& rhs) { return lhs.get() == rhs.get(); } -} +} // namespace JSC #endif // WriteBarrier_h |