diff options
author | Allan Sandfeld Jensen <allan.jensen@digia.com> | 2013-09-13 12:51:20 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-09-19 20:50:05 +0200 |
commit | d441d6f39bb846989d95bcf5caf387b42414718d (patch) | |
tree | e367e64a75991c554930278175d403c072de6bb8 /Source/JavaScriptCore/runtime | |
parent | 0060b2994c07842f4c59de64b5e3e430525c4b90 (diff) | |
download | qtwebkit-d441d6f39bb846989d95bcf5caf387b42414718d.tar.gz |
Import Qt5x2 branch of QtWebkit for Qt 5.2
Importing a new snapshot of webkit.
Change-Id: I2d01ad12cdc8af8cb015387641120a9d7ea5f10c
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
Diffstat (limited to 'Source/JavaScriptCore/runtime')
219 files changed, 8101 insertions, 6420 deletions
diff --git a/Source/JavaScriptCore/runtime/ArgList.cpp b/Source/JavaScriptCore/runtime/ArgList.cpp index 301abd530..74240418c 100644 --- a/Source/JavaScriptCore/runtime/ArgList.cpp +++ b/Source/JavaScriptCore/runtime/ArgList.cpp @@ -22,9 +22,9 @@ #include "ArgList.h" #include "HeapRootVisitor.h" -#include "JSValue.h" +#include "JSCJSValue.h" #include "JSObject.h" - +#include "Operations.h" using std::min; diff --git a/Source/JavaScriptCore/runtime/ArgList.h b/Source/JavaScriptCore/runtime/ArgList.h index 1fb1ce911..84a0cdd8b 100644 --- a/Source/JavaScriptCore/runtime/ArgList.h +++ b/Source/JavaScriptCore/runtime/ArgList.h @@ -33,12 +33,11 @@ class SlotVisitor; class MarkedArgumentBuffer { WTF_MAKE_NONCOPYABLE(MarkedArgumentBuffer); - friend class JSGlobalData; + friend class VM; friend class ArgList; private: static const size_t inlineCapacity = 8; - typedef Vector<Register, inlineCapacity> VectorType; typedef HashSet<MarkedArgumentBuffer*> ListSet; public: diff --git a/Source/JavaScriptCore/runtime/Arguments.cpp b/Source/JavaScriptCore/runtime/Arguments.cpp index ba73b2cf2..a188885e6 100644 --- a/Source/JavaScriptCore/runtime/Arguments.cpp +++ b/Source/JavaScriptCore/runtime/Arguments.cpp @@ -28,6 +28,7 @@ #include "JSActivation.h" #include "JSFunction.h" #include "JSGlobalObject.h" +#include "Operations.h" using namespace std; @@ -126,7 +127,7 @@ bool Arguments::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName p Arguments* thisObject = jsCast<Arguments*>(cell); unsigned i = propertyName.asIndex(); if (JSValue value = thisObject->tryGetArgument(i)) { - ASSERT(i < PropertyName::NotAnIndex); + RELEASE_ASSERT(i < PropertyName::NotAnIndex); slot.setValue(value); return true; } @@ -155,7 +156,7 @@ bool Arguments::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Prop Arguments* thisObject = jsCast<Arguments*>(object); unsigned i = propertyName.asIndex(); if (JSValue value = thisObject->tryGetArgument(i)) { - ASSERT(i < PropertyName::NotAnIndex); + RELEASE_ASSERT(i < PropertyName::NotAnIndex); descriptor.setDescriptor(value, None); return true; } @@ -197,7 +198,7 @@ void Arguments::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyN void Arguments::putByIndex(JSCell* cell, ExecState* exec, unsigned i, JSValue value, bool shouldThrow) { Arguments* thisObject = jsCast<Arguments*>(cell); - if (thisObject->trySetArgument(exec->globalData(), i, value)) + if (thisObject->trySetArgument(exec->vm(), i, value)) return; PutPropertySlot slot(shouldThrow); @@ -208,19 +209,19 @@ void Arguments::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JS { Arguments* thisObject = jsCast<Arguments*>(cell); unsigned i = propertyName.asIndex(); - if (thisObject->trySetArgument(exec->globalData(), i, value)) + if (thisObject->trySetArgument(exec->vm(), i, value)) return; if (propertyName == exec->propertyNames().length && !thisObject->m_overrodeLength) { thisObject->m_overrodeLength = true; - thisObject->putDirect(exec->globalData(), propertyName, value, DontEnum); + thisObject->putDirect(exec->vm(), propertyName, value, DontEnum); return; } if (propertyName == exec->propertyNames().callee && !thisObject->m_overrodeCallee) { if (!thisObject->m_isStrictMode) { thisObject->m_overrodeCallee = true; - thisObject->putDirect(exec->globalData(), propertyName, value, DontEnum); + thisObject->putDirect(exec->vm(), propertyName, value, DontEnum); return; } thisObject->createStrictModeCalleeIfNecessary(exec); @@ -246,13 +247,13 @@ bool Arguments::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i) bool Arguments::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) { - if (exec->globalData().isInDefineOwnProperty()) + if (exec->vm().isInDefineOwnProperty()) return Base::deleteProperty(cell, exec, propertyName); Arguments* thisObject = jsCast<Arguments*>(cell); unsigned i = propertyName.asIndex(); if (i < thisObject->m_numArguments) { - ASSERT(i < PropertyName::NotAnIndex); + RELEASE_ASSERT(i < PropertyName::NotAnIndex); if (!Base::deleteProperty(cell, exec, propertyName)) return false; if (thisObject->tryDeleteArgument(i)) @@ -283,7 +284,7 @@ bool Arguments::defineOwnProperty(JSObject* object, ExecState* exec, PropertyNam Arguments* thisObject = jsCast<Arguments*>(object); unsigned i = propertyName.asIndex(); if (i < thisObject->m_numArguments) { - ASSERT(i < PropertyName::NotAnIndex); + RELEASE_ASSERT(i < PropertyName::NotAnIndex); // If the property is not yet present on the object, and is not yet marked as deleted, then add it now. PropertySlot slot; if (!thisObject->isDeletedArgument(i) && !JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot)) { @@ -305,7 +306,7 @@ bool Arguments::defineOwnProperty(JSObject* object, ExecState* exec, PropertyNam // i. If Desc.[[Value]] is present, then // 1. Call the [[Put]] internal method of map passing P, Desc.[[Value]], and Throw as the arguments. if (descriptor.value()) - thisObject->trySetArgument(exec->globalData(), i, descriptor.value()); + thisObject->trySetArgument(exec->vm(), i, descriptor.value()); // ii. If Desc.[[Writable]] is present and its value is false, then // 1. Call the [[Delete]] internal method of map passing P and false as arguments. if (descriptor.writablePresent() && !descriptor.writable()) @@ -316,10 +317,10 @@ bool Arguments::defineOwnProperty(JSObject* object, ExecState* exec, PropertyNam } if (propertyName == exec->propertyNames().length && !thisObject->m_overrodeLength) { - thisObject->putDirect(exec->globalData(), propertyName, jsNumber(thisObject->m_numArguments), DontEnum); + thisObject->putDirect(exec->vm(), propertyName, jsNumber(thisObject->m_numArguments), DontEnum); thisObject->m_overrodeLength = true; } else if (propertyName == exec->propertyNames().callee && !thisObject->m_overrodeCallee) { - thisObject->putDirect(exec->globalData(), propertyName, thisObject->m_callee.get(), DontEnum); + thisObject->putDirect(exec->vm(), propertyName, thisObject->m_callee.get(), DontEnum); thisObject->m_overrodeCallee = true; } else if (propertyName == exec->propertyNames().caller && thisObject->m_isStrictMode) thisObject->createStrictModeCallerIfNecessary(exec); @@ -355,24 +356,24 @@ void Arguments::tearOff(CallFrame* callFrame) if (!callFrame->isInlineCallFrame()) { for (size_t i = 0; i < m_numArguments; ++i) - trySetArgument(callFrame->globalData(), i, callFrame->argumentAfterCapture(i)); + trySetArgument(callFrame->vm(), i, callFrame->argumentAfterCapture(i)); return; } tearOffForInlineCallFrame( - callFrame->globalData(), callFrame->registers(), callFrame->inlineCallFrame()); + callFrame->vm(), callFrame->registers(), callFrame->inlineCallFrame()); } void Arguments::didTearOffActivation(ExecState* exec, JSActivation* activation) { - ASSERT(activation); + RELEASE_ASSERT(activation); if (isTornOff()) return; if (!m_numArguments) return; - m_activation.set(exec->globalData(), this, activation); + m_activation.set(exec->vm(), this, activation); tearOff(exec); } @@ -388,11 +389,11 @@ void Arguments::tearOff(CallFrame* callFrame, InlineCallFrame* inlineCallFrame) m_registers = m_registerArray.get() + CallFrame::offsetFor(m_numArguments + 1); tearOffForInlineCallFrame( - callFrame->globalData(), callFrame->registers() + inlineCallFrame->stackOffset, + callFrame->vm(), callFrame->registers() + inlineCallFrame->stackOffset, inlineCallFrame); } -void Arguments::tearOffForInlineCallFrame(JSGlobalData& globalData, Register* registers, InlineCallFrame* inlineCallFrame) +void Arguments::tearOffForInlineCallFrame(VM& vm, Register* registers, InlineCallFrame* inlineCallFrame) { for (size_t i = 0; i < m_numArguments; ++i) { ValueRecovery& recovery = inlineCallFrame->arguments[i + 1]; @@ -427,10 +428,10 @@ void Arguments::tearOffForInlineCallFrame(JSGlobalData& globalData, Register* re value = recovery.constant(); break; default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); break; } - trySetArgument(globalData, i, value); + trySetArgument(vm, i, value); } } diff --git a/Source/JavaScriptCore/runtime/Arguments.h b/Source/JavaScriptCore/runtime/Arguments.h index 8ae991422..58ac782b6 100644 --- a/Source/JavaScriptCore/runtime/Arguments.h +++ b/Source/JavaScriptCore/runtime/Arguments.h @@ -40,16 +40,16 @@ class Arguments : public JSDestructibleObject { public: typedef JSDestructibleObject Base; - static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame) + static Arguments* create(VM& vm, CallFrame* callFrame) { - Arguments* arguments = new (NotNull, allocateCell<Arguments>(globalData.heap)) Arguments(callFrame); + Arguments* arguments = new (NotNull, allocateCell<Arguments>(vm.heap)) Arguments(callFrame); arguments->finishCreation(callFrame); return arguments; } - static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame, InlineCallFrame* inlineCallFrame) + static Arguments* create(VM& vm, CallFrame* callFrame, InlineCallFrame* inlineCallFrame) { - Arguments* arguments = new (NotNull, allocateCell<Arguments>(globalData.heap)) Arguments(callFrame); + Arguments* arguments = new (NotNull, allocateCell<Arguments>(vm.heap)) Arguments(callFrame); arguments->finishCreation(callFrame, inlineCallFrame); return arguments; } @@ -62,7 +62,7 @@ private: Arguments(CallFrame*); Arguments(CallFrame*, NoParametersType); - void tearOffForInlineCallFrame(JSGlobalData& globalData, Register*, InlineCallFrame*); + void tearOffForInlineCallFrame(VM& vm, Register*, InlineCallFrame*); public: static const ClassInfo s_info; @@ -84,9 +84,9 @@ public: bool isTornOff() const { return m_registerArray; } void didTearOffActivation(ExecState*, JSActivation*); - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } protected: @@ -110,7 +110,7 @@ private: void createStrictModeCalleeIfNecessary(ExecState*); bool isArgument(size_t); - bool trySetArgument(JSGlobalData&, size_t argument, JSValue); + bool trySetArgument(VM&, size_t argument, JSValue); JSValue tryGetArgument(size_t argument); bool isDeletedArgument(size_t); bool tryDeleteArgument(size_t); @@ -148,12 +148,12 @@ inline Arguments* asArguments(JSValue value) } inline Arguments::Arguments(CallFrame* callFrame) - : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure()) + : JSDestructibleObject(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure()) { } inline Arguments::Arguments(CallFrame* callFrame, NoParametersType) - : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure()) + : JSDestructibleObject(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure()) { } @@ -177,11 +177,11 @@ inline bool Arguments::tryDeleteArgument(size_t argument) return true; } -inline bool Arguments::trySetArgument(JSGlobalData& globalData, size_t argument, JSValue value) +inline bool Arguments::trySetArgument(VM& vm, size_t argument, JSValue value) { if (!isArgument(argument)) return false; - this->argument(argument).set(globalData, this, value); + this->argument(argument).set(vm, this, value); return true; } @@ -227,13 +227,13 @@ inline WriteBarrierBase<Unknown>& Arguments::argument(size_t argument) inline void Arguments::finishCreation(CallFrame* callFrame) { - Base::finishCreation(callFrame->globalData()); + Base::finishCreation(callFrame->vm()); ASSERT(inherits(&s_info)); JSFunction* callee = jsCast<JSFunction*>(callFrame->callee()); m_numArguments = callFrame->argumentCount(); m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers()); - m_callee.set(callFrame->globalData(), this, callee); + m_callee.set(callFrame->vm(), this, callee); m_overrodeLength = false; m_overrodeCallee = false; m_overrodeCaller = false; @@ -256,13 +256,13 @@ inline void Arguments::finishCreation(CallFrame* callFrame) inline void Arguments::finishCreation(CallFrame* callFrame, InlineCallFrame* inlineCallFrame) { - Base::finishCreation(callFrame->globalData()); + Base::finishCreation(callFrame->vm()); ASSERT(inherits(&s_info)); - JSFunction* callee = inlineCallFrame->callee.get(); + JSFunction* callee = inlineCallFrame->calleeForCallFrame(callFrame); m_numArguments = inlineCallFrame->arguments.size() - 1; m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers()) + inlineCallFrame->stackOffset; - m_callee.set(callFrame->globalData(), this, callee); + m_callee.set(callFrame->vm(), this, callee); m_overrodeLength = false; m_overrodeCallee = false; m_overrodeCaller = false; diff --git a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp index a3fce45f2..752055716 100644 --- a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp @@ -32,6 +32,7 @@ #include "JSArray.h" #include "JSFunction.h" #include "Lookup.h" +#include "Operations.h" namespace JSC { @@ -60,9 +61,9 @@ ArrayConstructor::ArrayConstructor(JSGlobalObject* globalObject, Structure* stru void ArrayConstructor::finishCreation(ExecState* exec, ArrayPrototype* arrayPrototype) { - Base::finishCreation(exec->globalData(), arrayPrototype->classInfo()->className); - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, arrayPrototype, DontEnum | DontDelete | ReadOnly); - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontEnum | DontDelete); + Base::finishCreation(exec->vm(), arrayPrototype->classInfo()->className); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().prototype, arrayPrototype, DontEnum | DontDelete | ReadOnly); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontEnum | DontDelete); } bool ArrayConstructor::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot &slot) diff --git a/Source/JavaScriptCore/runtime/ArrayConstructor.h b/Source/JavaScriptCore/runtime/ArrayConstructor.h index f9f35c491..727475b47 100644 --- a/Source/JavaScriptCore/runtime/ArrayConstructor.h +++ b/Source/JavaScriptCore/runtime/ArrayConstructor.h @@ -42,9 +42,9 @@ public: static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } protected: diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp index e6d37fb02..ba1c7b725 100644 --- a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2007, 2008, 2009, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2007, 2008, 2009, 2011, 2013 Apple Inc. All rights reserved. * Copyright (C) 2003 Peter Kelly (pmk@post.com) * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) * @@ -28,6 +28,7 @@ #include "CachedCall.h" #include "CodeBlock.h" #include "CopiedSpaceInlines.h" +#include "Error.h" #include "Interpreter.h" #include "JIT.h" #include "JSStringBuilder.h" @@ -123,16 +124,16 @@ ArrayPrototype* ArrayPrototype::create(ExecState* exec, JSGlobalObject* globalOb // ECMA 15.4.4 ArrayPrototype::ArrayPrototype(JSGlobalObject* globalObject, Structure* structure) - : JSArray(globalObject->globalData(), structure, 0) + : JSArray(globalObject->vm(), structure, 0) { } void ArrayPrototype::finishCreation(JSGlobalObject* globalObject) { - JSGlobalData& globalData = globalObject->globalData(); - Base::finishCreation(globalData); + VM& vm = globalObject->vm(); + Base::finishCreation(vm); ASSERT(inherits(&s_info)); - notifyUsedAsPrototype(globalData); + vm.prototypeMap.addPrototype(this); } bool ArrayPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot) @@ -194,11 +195,11 @@ static unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument template<JSArray::ShiftCountMode shiftCountMode> void shift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length) { - ASSERT(currentCount > resultCount); + RELEASE_ASSERT(currentCount > resultCount); unsigned count = currentCount - resultCount; - ASSERT(header <= length); - ASSERT(currentCount <= (length - header)); + RELEASE_ASSERT(header <= length); + RELEASE_ASSERT(currentCount <= (length - header)); if (isJSArray(thisObj)) { JSArray* array = asArray(thisObj); @@ -232,11 +233,11 @@ void shift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned current template<JSArray::ShiftCountMode shiftCountMode> void unshift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length) { - ASSERT(resultCount > currentCount); + RELEASE_ASSERT(resultCount > currentCount); unsigned count = resultCount - currentCount; - ASSERT(header <= length); - ASSERT(currentCount <= (length - header)); + RELEASE_ASSERT(header <= length); + RELEASE_ASSERT(currentCount <= (length - header)); // Guard against overflow. if (count > (UINT_MAX - length)) { @@ -303,64 +304,27 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec) if (JSValue earlyReturnValue = checker.earlyReturnValue()) return JSValue::encode(earlyReturnValue); - unsigned totalSize = length ? length - 1 : 0; - Vector<RefPtr<StringImpl>, 256> strBuffer(length); - bool allStrings8Bit = true; - + String separator(",", String::ConstructFromLiteral); + JSStringJoiner stringJoiner(separator, length); for (unsigned k = 0; k < length; k++) { JSValue element; if (thisObj->canGetIndexQuickly(k)) element = thisObj->getIndexQuickly(k); - else + else { element = thisObj->get(exec, k); - - if (element.isUndefinedOrNull()) - continue; - - String str = element.toWTFString(exec); - strBuffer[k] = str.impl(); - totalSize += str.length(); - allStrings8Bit = allStrings8Bit && str.is8Bit(); - - if (!strBuffer.data()) { - throwOutOfMemoryError(exec); - } - - if (exec->hadException()) - break; - } - if (!totalSize) - return JSValue::encode(jsEmptyString(exec)); - - if (allStrings8Bit) { - Vector<LChar> buffer; - buffer.reserveCapacity(totalSize); - if (!buffer.data()) - return JSValue::encode(throwOutOfMemoryError(exec)); - - for (unsigned i = 0; i < length; i++) { - if (i) - buffer.append(','); - if (RefPtr<StringImpl> rep = strBuffer[i]) - buffer.append(rep->characters8(), rep->length()); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); } - ASSERT(buffer.size() == totalSize); - return JSValue::encode(jsString(exec, String::adopt(buffer))); - } - Vector<UChar> buffer; - buffer.reserveCapacity(totalSize); - if (!buffer.data()) - return JSValue::encode(throwOutOfMemoryError(exec)); - - for (unsigned i = 0; i < length; i++) { - if (i) - buffer.append(','); - if (RefPtr<StringImpl> rep = strBuffer[i]) - buffer.append(rep->characters(), rep->length()); + if (element.isUndefinedOrNull()) + stringJoiner.append(String()); + else + stringJoiner.append(element.toWTFString(exec)); + + if (exec->hadException()) + return JSValue::encode(jsUndefined()); } - ASSERT(buffer.size() == totalSize); - return JSValue::encode(jsString(exec, String::adopt(buffer))); + return JSValue::encode(stringJoiner.join(exec)); } EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec) @@ -403,7 +367,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec) } } - return JSValue::encode(stringJoiner.build(exec)); + return JSValue::encode(stringJoiner.join(exec)); } EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec) @@ -449,7 +413,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec) stringJoiner.append(String()); } - return JSValue::encode(stringJoiner.build(exec)); + return JSValue::encode(stringJoiner.join(exec)); } EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec) @@ -644,39 +608,36 @@ inline JSValue getOrHole(JSObject* obj, ExecState* exec, unsigned propertyName) return JSValue(); } -EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec) +static bool attemptFastSort(ExecState* exec, JSObject* thisObj, JSValue function, CallData& callData, CallType& callType) { - JSObject* thisObj = exec->hostThisValue().toObject(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::s_info && !asArray(thisObj)->hasSparseMap() && !shouldUseSlowPut(thisObj->structure()->indexingType())) { - if (isNumericCompareFunction(exec, callType, callData)) - asArray(thisObj)->sortNumeric(exec, function, callType, callData); - else if (callType != CallTypeNone) - asArray(thisObj)->sort(exec, function, callType, callData); - else - asArray(thisObj)->sort(exec); - return JSValue::encode(thisObj); - } + if (thisObj->classInfo() != &JSArray::s_info + || asArray(thisObj)->hasSparseMap() + || shouldUseSlowPut(thisObj->structure()->indexingType())) + return false; + + if (isNumericCompareFunction(exec, callType, callData)) + asArray(thisObj)->sortNumeric(exec, function, callType, callData); + else if (callType != CallTypeNone) + asArray(thisObj)->sort(exec, function, callType, callData); + else + asArray(thisObj)->sort(exec); + return true; +} +static bool performSlowSort(ExecState* exec, JSObject* thisObj, unsigned length, JSValue function, CallData& callData, CallType& callType) +{ // "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 = getOrHole(thisObj, exec, i); if (exec->hadException()) - return JSValue::encode(jsUndefined()); + return false; unsigned themin = i; JSValue minObj = iObj; for (unsigned j = i + 1; j < length; ++j) { JSValue jObj = getOrHole(thisObj, exec, j); if (exec->hadException()) - return JSValue::encode(jsUndefined()); + return false; double compareResult; if (!jObj) compareResult = 1; @@ -704,21 +665,94 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec) if (minObj) { thisObj->methodTable()->putByIndex(thisObj, exec, i, minObj, true); if (exec->hadException()) - return JSValue::encode(jsUndefined()); + return false; } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, i)) { throwTypeError(exec, "Unable to delete property."); - return JSValue::encode(jsUndefined()); + return false; } if (iObj) { thisObj->methodTable()->putByIndex(thisObj, exec, themin, iObj, true); if (exec->hadException()) - return JSValue::encode(jsUndefined()); + return false; } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, themin)) { throwTypeError(exec, "Unable to delete property."); - return JSValue::encode(jsUndefined()); + return false; } } } + return true; +} + +EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec) +{ + JSObject* thisObj = exec->hostThisValue().toObject(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 (attemptFastSort(exec, thisObj, function, callData, callType)) + return JSValue::encode(thisObj); + + // Assume that for small-ish arrays, doing the slow sort directly is better. + if (length < 1000) + return performSlowSort(exec, thisObj, length, function, callData, callType) ? JSValue::encode(thisObj) : JSValue::encode(jsUndefined()); + + JSGlobalObject* globalObject = JSGlobalObject::create( + exec->vm(), JSGlobalObject::createStructure(exec->vm(), jsNull())); + JSArray* flatArray = constructEmptyArray(globalObject->globalExec(), 0); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + PropertyNameArray nameArray(exec); + thisObj->methodTable()->getPropertyNames(thisObj, exec, nameArray, IncludeDontEnumProperties); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + Vector<uint32_t, 0, UnsafeVectorOverflow> keys; + for (size_t i = 0; i < nameArray.size(); ++i) { + PropertyName name = nameArray[i]; + uint32_t index = name.asIndex(); + if (index == PropertyName::NotAnIndex) + continue; + + JSValue value = getOrHole(thisObj, exec, index); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + if (!value) + continue; + keys.append(index); + flatArray->push(exec, value); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + } + + if (!attemptFastSort(exec, flatArray, function, callData, callType) + && !performSlowSort(exec, flatArray, flatArray->length(), function, callData, callType)) + return JSValue::encode(jsUndefined()); + + for (size_t i = 0; i < keys.size(); ++i) { + size_t index = keys[i]; + if (index < flatArray->length()) + continue; + + if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, index)) { + throwTypeError(exec, "Unable to delete property."); + return JSValue::encode(jsUndefined()); + } + } + + for (size_t i = flatArray->length(); i--;) { + JSValue value = getOrHole(flatArray, exec, i); + RELEASE_ASSERT(value); + thisObj->methodTable()->putByIndex(thisObj, exec, i, value, true); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + } + return JSValue::encode(thisObj); } @@ -747,17 +781,17 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec) deleteCount = static_cast<unsigned>(deleteDouble); } - JSArray* resObj = JSArray::tryCreateUninitialized(exec->globalData(), exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), deleteCount); + JSArray* resObj = JSArray::tryCreateUninitialized(exec->vm(), exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), deleteCount); if (!resObj) return JSValue::encode(throwOutOfMemoryError(exec)); JSValue result = resObj; - JSGlobalData& globalData = exec->globalData(); + VM& vm = exec->vm(); for (unsigned k = 0; k < deleteCount; k++) { JSValue v = getProperty(exec, thisObj, k + begin); if (exec->hadException()) return JSValue::encode(jsUndefined()); - resObj->initializeIndex(globalData, k, v); + resObj->initializeIndex(vm, k, v); } unsigned additionalArgs = std::max<int>(exec->argumentCount() - 2, 0); @@ -1290,7 +1324,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState* exec) JSValue searchElement = exec->argument(0); do { - ASSERT(index < length); + RELEASE_ASSERT(index < length); JSValue e = getProperty(exec, thisObj, index); if (exec->hadException()) return JSValue::encode(jsUndefined()); diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.h b/Source/JavaScriptCore/runtime/ArrayPrototype.h index c23bcdec1..37ba6eb7e 100644 --- a/Source/JavaScriptCore/runtime/ArrayPrototype.h +++ b/Source/JavaScriptCore/runtime/ArrayPrototype.h @@ -40,9 +40,9 @@ public: static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info, ArrayClass); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info, ArrayClass); } protected: diff --git a/Source/JavaScriptCore/runtime/ArrayStorage.h b/Source/JavaScriptCore/runtime/ArrayStorage.h index ffd84b281..a0287c921 100644 --- a/Source/JavaScriptCore/runtime/ArrayStorage.h +++ b/Source/JavaScriptCore/runtime/ArrayStorage.h @@ -49,7 +49,7 @@ private: ArrayStorage() { } // Not directly instantiable. Can only be created as part of a Butterfly. public: - static ArrayStorage* from(Butterfly* butterfly) { return reinterpret_cast<ArrayStorage*>(butterfly); } + static ArrayStorage* from(Butterfly* butterfly) { return reinterpret_cast_ptr<ArrayStorage*>(butterfly); } static ArrayStorage* from(IndexingHeader* indexingHeader) { return indexingHeader->arrayStorage(); } Butterfly* butterfly() { return reinterpret_cast<Butterfly*>(this); } @@ -72,7 +72,9 @@ public: { return m_sparseMap && m_sparseMap->sparseMode(); } - + + ContiguousJSValues vector() { return ContiguousJSValues(m_vector, vectorLength()); } + WriteBarrier<SparseArrayValueMap> m_sparseMap; unsigned m_indexBias; unsigned m_numValuesInVector; diff --git a/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h b/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h index 178bf3fe9..76def7138 100644 --- a/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h +++ b/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h @@ -34,8 +34,8 @@ namespace JSC { class BatchedTransitionOptimizer { WTF_MAKE_NONCOPYABLE(BatchedTransitionOptimizer); public: - BatchedTransitionOptimizer(JSGlobalData& globalData, JSObject* object) - : m_globalData(&globalData) + BatchedTransitionOptimizer(VM& vm, JSObject* object) + : m_vm(&vm) , m_object(object) { } @@ -43,11 +43,11 @@ public: ~BatchedTransitionOptimizer() { if (m_object->structure()->isDictionary()) - m_object->flattenDictionaryObject(*m_globalData); + m_object->flattenDictionaryObject(*m_vm); } private: - JSGlobalData* m_globalData; + VM* m_vm; JSObject* m_object; }; diff --git a/Source/JavaScriptCore/runtime/BigInteger.h b/Source/JavaScriptCore/runtime/BigInteger.h index 833829df6..0a0c477c2 100644 --- a/Source/JavaScriptCore/runtime/BigInteger.h +++ b/Source/JavaScriptCore/runtime/BigInteger.h @@ -35,7 +35,7 @@ class BigInteger { public: BigInteger(double number) { - ASSERT(isfinite(number) && !signbit(number)); + ASSERT(std::isfinite(number) && !std::signbit(number)); ASSERT(number == floor(number)); bool sign; diff --git a/Source/JavaScriptCore/runtime/BooleanConstructor.cpp b/Source/JavaScriptCore/runtime/BooleanConstructor.cpp index 0485350ce..453983b7a 100644 --- a/Source/JavaScriptCore/runtime/BooleanConstructor.cpp +++ b/Source/JavaScriptCore/runtime/BooleanConstructor.cpp @@ -23,6 +23,7 @@ #include "BooleanPrototype.h" #include "JSGlobalObject.h" +#include "Operations.h" namespace JSC { @@ -37,18 +38,18 @@ BooleanConstructor::BooleanConstructor(JSGlobalObject* globalObject, Structure* void BooleanConstructor::finishCreation(ExecState* exec, BooleanPrototype* booleanPrototype) { - Base::finishCreation(exec->globalData(), booleanPrototype->classInfo()->className); - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, booleanPrototype, DontEnum | DontDelete | ReadOnly); + Base::finishCreation(exec->vm(), booleanPrototype->classInfo()->className); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().prototype, booleanPrototype, DontEnum | DontDelete | ReadOnly); // no. of arguments for constructor - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontDelete | DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontDelete | DontEnum); } // ECMA 15.6.2 JSObject* constructBoolean(ExecState* exec, const ArgList& args) { - BooleanObject* obj = BooleanObject::create(exec->globalData(), asInternalFunction(exec->callee())->globalObject()->booleanObjectStructure()); - obj->setInternalValue(exec->globalData(), jsBoolean(args.at(0).toBoolean(exec))); + BooleanObject* obj = BooleanObject::create(exec->vm(), asInternalFunction(exec->callee())->globalObject()->booleanObjectStructure()); + obj->setInternalValue(exec->vm(), jsBoolean(args.at(0).toBoolean(exec))); return obj; } @@ -78,8 +79,8 @@ CallType BooleanConstructor::getCallData(JSCell*, CallData& callData) JSObject* constructBooleanFromImmediateBoolean(ExecState* exec, JSGlobalObject* globalObject, JSValue immediateBooleanValue) { - BooleanObject* obj = BooleanObject::create(exec->globalData(), globalObject->booleanObjectStructure()); - obj->setInternalValue(exec->globalData(), immediateBooleanValue); + BooleanObject* obj = BooleanObject::create(exec->vm(), globalObject->booleanObjectStructure()); + obj->setInternalValue(exec->vm(), immediateBooleanValue); return obj; } diff --git a/Source/JavaScriptCore/runtime/BooleanConstructor.h b/Source/JavaScriptCore/runtime/BooleanConstructor.h index f395374ae..760d5d3b1 100644 --- a/Source/JavaScriptCore/runtime/BooleanConstructor.h +++ b/Source/JavaScriptCore/runtime/BooleanConstructor.h @@ -40,9 +40,9 @@ public: static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } protected: diff --git a/Source/JavaScriptCore/runtime/BooleanObject.cpp b/Source/JavaScriptCore/runtime/BooleanObject.cpp index 355993864..3f7f2f621 100644 --- a/Source/JavaScriptCore/runtime/BooleanObject.cpp +++ b/Source/JavaScriptCore/runtime/BooleanObject.cpp @@ -22,6 +22,7 @@ #include "BooleanObject.h" #include "JSScope.h" +#include "Operations.h" namespace JSC { @@ -29,14 +30,14 @@ ASSERT_HAS_TRIVIAL_DESTRUCTOR(BooleanObject); const ClassInfo BooleanObject::s_info = { "Boolean", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(BooleanObject) }; -BooleanObject::BooleanObject(JSGlobalData& globalData, Structure* structure) - : JSWrapperObject(globalData, structure) +BooleanObject::BooleanObject(VM& vm, Structure* structure) + : JSWrapperObject(vm, structure) { } -void BooleanObject::finishCreation(JSGlobalData& globalData) +void BooleanObject::finishCreation(VM& vm) { - Base::finishCreation(globalData); + Base::finishCreation(vm); ASSERT(inherits(&s_info)); } diff --git a/Source/JavaScriptCore/runtime/BooleanObject.h b/Source/JavaScriptCore/runtime/BooleanObject.h index b6fcccdcf..299f34174 100644 --- a/Source/JavaScriptCore/runtime/BooleanObject.h +++ b/Source/JavaScriptCore/runtime/BooleanObject.h @@ -27,24 +27,24 @@ namespace JSC { class BooleanObject : public JSWrapperObject { protected: - JS_EXPORT_PRIVATE BooleanObject(JSGlobalData&, Structure*); - JS_EXPORT_PRIVATE void finishCreation(JSGlobalData&); + JS_EXPORT_PRIVATE BooleanObject(VM&, Structure*); + JS_EXPORT_PRIVATE void finishCreation(VM&); public: typedef JSWrapperObject Base; - static BooleanObject* create(JSGlobalData& globalData, Structure* structure) + static BooleanObject* create(VM& vm, Structure* structure) { - BooleanObject* boolean = new (NotNull, allocateCell<BooleanObject>(globalData.heap)) BooleanObject(globalData, structure); - boolean->finishCreation(globalData); + BooleanObject* boolean = new (NotNull, allocateCell<BooleanObject>(vm.heap)) BooleanObject(vm, structure); + boolean->finishCreation(vm); return boolean; } static JS_EXPORTDATA const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } }; diff --git a/Source/JavaScriptCore/runtime/BooleanPrototype.cpp b/Source/JavaScriptCore/runtime/BooleanPrototype.cpp index a331c6c15..a5b8390a8 100644 --- a/Source/JavaScriptCore/runtime/BooleanPrototype.cpp +++ b/Source/JavaScriptCore/runtime/BooleanPrototype.cpp @@ -26,6 +26,7 @@ #include "JSFunction.h" #include "JSString.h" #include "ObjectPrototype.h" +#include "Operations.h" namespace JSC { @@ -50,14 +51,14 @@ const ClassInfo BooleanPrototype::s_info = { "Boolean", &BooleanObject::s_info, ASSERT_HAS_TRIVIAL_DESTRUCTOR(BooleanPrototype); BooleanPrototype::BooleanPrototype(ExecState* exec, Structure* structure) - : BooleanObject(exec->globalData(), structure) + : BooleanObject(exec->vm(), structure) { } void BooleanPrototype::finishCreation(ExecState* exec, JSGlobalObject*) { - Base::finishCreation(exec->globalData()); - setInternalValue(exec->globalData(), jsBoolean(false)); + Base::finishCreation(exec->vm()); + setInternalValue(exec->vm(), jsBoolean(false)); ASSERT(inherits(&s_info)); } @@ -76,22 +77,22 @@ bool BooleanPrototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exe EncodedJSValue JSC_HOST_CALL booleanProtoFuncToString(ExecState* exec) { - JSGlobalData* globalData = &exec->globalData(); + VM* vm = &exec->vm(); JSValue thisValue = exec->hostThisValue(); if (thisValue == jsBoolean(false)) - return JSValue::encode(globalData->smallStrings.falseString(globalData)); + return JSValue::encode(vm->smallStrings.falseString()); if (thisValue == jsBoolean(true)) - return JSValue::encode(globalData->smallStrings.trueString(globalData)); + return JSValue::encode(vm->smallStrings.trueString()); if (!thisValue.inherits(&BooleanObject::s_info)) return throwVMTypeError(exec); if (asBooleanObject(thisValue)->internalValue() == jsBoolean(false)) - return JSValue::encode(globalData->smallStrings.falseString(globalData)); + return JSValue::encode(vm->smallStrings.falseString()); ASSERT(asBooleanObject(thisValue)->internalValue() == jsBoolean(true)); - return JSValue::encode(globalData->smallStrings.trueString(globalData)); + return JSValue::encode(vm->smallStrings.trueString()); } EncodedJSValue JSC_HOST_CALL booleanProtoFuncValueOf(ExecState* exec) diff --git a/Source/JavaScriptCore/runtime/BooleanPrototype.h b/Source/JavaScriptCore/runtime/BooleanPrototype.h index 05790a755..43b81cb61 100644 --- a/Source/JavaScriptCore/runtime/BooleanPrototype.h +++ b/Source/JavaScriptCore/runtime/BooleanPrototype.h @@ -38,9 +38,9 @@ public: static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } protected: diff --git a/Source/JavaScriptCore/runtime/Butterfly.h b/Source/JavaScriptCore/runtime/Butterfly.h index bbbda9461..eb6d82a76 100644 --- a/Source/JavaScriptCore/runtime/Butterfly.h +++ b/Source/JavaScriptCore/runtime/Butterfly.h @@ -34,10 +34,45 @@ namespace JSC { -class JSGlobalData; +class VM; class CopyVisitor; struct ArrayStorage; +template <typename T> struct ContiguousData { + ContiguousData() + : m_data(0) +#if !ASSERT_DISABLED + , m_length(0) +#endif + { + } + ContiguousData(T* data, size_t length) + : m_data(data) +#if !ASSERT_DISABLED + , m_length(length) +#endif + { + UNUSED_PARAM(length); + } + + const T& operator[](size_t index) const { ASSERT(index < m_length); return m_data[index]; } + T& operator[](size_t index) { ASSERT(index < m_length); return m_data[index]; } + + T* data() const { return m_data; } +#if !ASSERT_DISABLED + size_t length() const { return m_length; } +#endif + +private: + T* m_data; +#if !ASSERT_DISABLED + size_t m_length; +#endif +}; + +typedef ContiguousData<double> ContiguousDoubles; +typedef ContiguousData<WriteBarrier<Unknown> > ContiguousJSValues; + class Butterfly { WTF_MAKE_NONCOPYABLE(Butterfly); private: @@ -69,10 +104,10 @@ public: static ptrdiff_t offsetOfPublicLength() { return offsetOfIndexingHeader() + IndexingHeader::offsetOfPublicLength(); } static ptrdiff_t offsetOfVectorLength() { return offsetOfIndexingHeader() + IndexingHeader::offsetOfVectorLength(); } - static Butterfly* createUninitialized(JSGlobalData&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes); + static Butterfly* createUninitialized(VM&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes); - static Butterfly* create(JSGlobalData&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader&, size_t indexingPayloadSizeInBytes); - static Butterfly* create(JSGlobalData&, Structure*); + static Butterfly* create(VM&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader&, size_t indexingPayloadSizeInBytes); + static Butterfly* create(VM&, Structure*); static Butterfly* createUninitializedDuringCollection(CopyVisitor&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes); IndexingHeader* indexingHeader() { return IndexingHeader::from(this); } @@ -86,11 +121,12 @@ public: void setVectorLength(uint32_t value) { indexingHeader()->setVectorLength(value); } template<typename T> - T* indexingPayload() { return reinterpret_cast<T*>(this); } + T* indexingPayload() { return reinterpret_cast_ptr<T*>(this); } ArrayStorage* arrayStorage() { return indexingPayload<ArrayStorage>(); } - WriteBarrier<Unknown>* contiguousInt32() { return indexingPayload<WriteBarrier<Unknown> >(); } - double* contiguousDouble() { return indexingPayload<double>(); } - WriteBarrier<Unknown>* contiguous() { return indexingPayload<WriteBarrier<Unknown> >(); } + ContiguousJSValues contiguousInt32() { return ContiguousJSValues(indexingPayload<WriteBarrier<Unknown> >(), vectorLength()); } + + ContiguousDoubles contiguousDouble() { return ContiguousDoubles(indexingPayload<double>(), vectorLength()); } + ContiguousJSValues contiguous() { return ContiguousJSValues(indexingPayload<WriteBarrier<Unknown> >(), vectorLength()); } static Butterfly* fromContiguous(WriteBarrier<Unknown>* contiguous) { @@ -111,20 +147,20 @@ public: void* base(size_t preCapacity, size_t propertyCapacity) { return propertyStorage() - propertyCapacity - preCapacity; } void* base(Structure*); - static Butterfly* createOrGrowArrayRight(Butterfly*, JSGlobalData&, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes); + static Butterfly* createOrGrowArrayRight(Butterfly*, VM&, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes); // The butterfly reallocation methods perform the reallocation itself but do not change any // of the meta-data to reflect that the reallocation occurred. Note that this set of // methods is not exhaustive and is not intended to encapsulate all possible allocation // modes of butterflies - there are code paths that allocate butterflies by calling // directly into Heap::tryAllocateStorage. - Butterfly* growPropertyStorage(JSGlobalData&, size_t preCapacity, size_t oldPropertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes, size_t newPropertyCapacity); - Butterfly* growPropertyStorage(JSGlobalData&, Structure* oldStructure, size_t oldPropertyCapacity, size_t newPropertyCapacity); - Butterfly* growPropertyStorage(JSGlobalData&, Structure* oldStructure, size_t newPropertyCapacity); - Butterfly* growArrayRight(JSGlobalData&, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes); // Assumes that preCapacity is zero, and asserts as much. - Butterfly* growArrayRight(JSGlobalData&, Structure*, size_t newIndexingPayloadSizeInBytes); - Butterfly* resizeArray(JSGlobalData&, size_t propertyCapacity, bool oldHasIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader, size_t newIndexingPayloadSizeInBytes); - Butterfly* resizeArray(JSGlobalData&, Structure*, size_t newPreCapacity, size_t newIndexingPayloadSizeInBytes); // Assumes that you're not changing whether or not the object has an indexing header. + Butterfly* growPropertyStorage(VM&, size_t preCapacity, size_t oldPropertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes, size_t newPropertyCapacity); + Butterfly* growPropertyStorage(VM&, Structure* oldStructure, size_t oldPropertyCapacity, size_t newPropertyCapacity); + Butterfly* growPropertyStorage(VM&, Structure* oldStructure, size_t newPropertyCapacity); + Butterfly* growArrayRight(VM&, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes); // Assumes that preCapacity is zero, and asserts as much. + Butterfly* growArrayRight(VM&, Structure*, size_t newIndexingPayloadSizeInBytes); + Butterfly* resizeArray(VM&, size_t propertyCapacity, bool oldHasIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader, size_t newIndexingPayloadSizeInBytes); + Butterfly* resizeArray(VM&, Structure*, size_t newPreCapacity, size_t newIndexingPayloadSizeInBytes); // Assumes that you're not changing whether or not the object has an indexing header. Butterfly* unshift(Structure*, size_t numberOfSlots); Butterfly* shift(Structure*, size_t numberOfSlots); }; diff --git a/Source/JavaScriptCore/runtime/ButterflyInlines.h b/Source/JavaScriptCore/runtime/ButterflyInlines.h index f01458950..a0e2af19d 100644 --- a/Source/JavaScriptCore/runtime/ButterflyInlines.h +++ b/Source/JavaScriptCore/runtime/ButterflyInlines.h @@ -30,33 +30,32 @@ #include "Butterfly.h" #include "CopiedSpaceInlines.h" #include "CopyVisitor.h" -#include "JSGlobalData.h" +#include "VM.h" #include "Structure.h" namespace JSC { -inline Butterfly* Butterfly::createUninitialized(JSGlobalData& globalData, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes) +inline Butterfly* Butterfly::createUninitialized(VM& vm, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes) { void* temp; size_t size = totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); - if (!globalData.heap.tryAllocateStorage(size, &temp)) - CRASH(); + RELEASE_ASSERT(vm.heap.tryAllocateStorage(size, &temp)); Butterfly* result = fromBase(temp, preCapacity, propertyCapacity); return result; } -inline Butterfly* Butterfly::create(JSGlobalData& globalData, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader& indexingHeader, size_t indexingPayloadSizeInBytes) +inline Butterfly* Butterfly::create(VM& vm, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader& indexingHeader, size_t indexingPayloadSizeInBytes) { Butterfly* result = createUninitialized( - globalData, preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); + vm, preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); if (hasIndexingHeader) *result->indexingHeader() = indexingHeader; return result; } -inline Butterfly* Butterfly::create(JSGlobalData& globalData, Structure* structure) +inline Butterfly* Butterfly::create(VM& vm, Structure* structure) { - return create(globalData, 0, structure->outOfLineCapacity(), hasIndexingHeader(structure->indexingType()), IndexingHeader(), 0); + return create(vm, 0, structure->outOfLineCapacity(), hasIndexingHeader(structure->indexingType()), IndexingHeader(), 0); } inline Butterfly* Butterfly::createUninitializedDuringCollection(CopyVisitor& visitor, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes) @@ -73,11 +72,11 @@ inline void* Butterfly::base(Structure* structure) return base(indexingHeader()->preCapacity(structure), structure->outOfLineCapacity()); } -inline Butterfly* Butterfly::growPropertyStorage(JSGlobalData& globalData, size_t preCapacity, size_t oldPropertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes, size_t newPropertyCapacity) +inline Butterfly* Butterfly::growPropertyStorage(VM& vm, size_t preCapacity, size_t oldPropertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes, size_t newPropertyCapacity) { - ASSERT(newPropertyCapacity > oldPropertyCapacity); + RELEASE_ASSERT(newPropertyCapacity > oldPropertyCapacity); Butterfly* result = createUninitialized( - globalData, preCapacity, newPropertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); + vm, preCapacity, newPropertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); memcpy( result->propertyStorage() - oldPropertyCapacity, propertyStorage() - oldPropertyCapacity, @@ -85,51 +84,51 @@ inline Butterfly* Butterfly::growPropertyStorage(JSGlobalData& globalData, size_ return result; } -inline Butterfly* Butterfly::growPropertyStorage(JSGlobalData& globalData, Structure* structure, size_t oldPropertyCapacity, size_t newPropertyCapacity) +inline Butterfly* Butterfly::growPropertyStorage(VM& vm, Structure* structure, size_t oldPropertyCapacity, size_t newPropertyCapacity) { return growPropertyStorage( - globalData, indexingHeader()->preCapacity(structure), oldPropertyCapacity, + vm, indexingHeader()->preCapacity(structure), oldPropertyCapacity, hasIndexingHeader(structure->indexingType()), indexingHeader()->indexingPayloadSizeInBytes(structure), newPropertyCapacity); } -inline Butterfly* Butterfly::growPropertyStorage(JSGlobalData& globalData, Structure* oldStructure, size_t newPropertyCapacity) +inline Butterfly* Butterfly::growPropertyStorage(VM& vm, Structure* oldStructure, size_t newPropertyCapacity) { return growPropertyStorage( - globalData, oldStructure, oldStructure->outOfLineCapacity(), newPropertyCapacity); + vm, oldStructure, oldStructure->outOfLineCapacity(), newPropertyCapacity); } -inline Butterfly* Butterfly::createOrGrowArrayRight(Butterfly* oldButterfly, JSGlobalData& globalData, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes) +inline Butterfly* Butterfly::createOrGrowArrayRight(Butterfly* oldButterfly, VM& vm, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes) { if (!oldButterfly) - return create(globalData, 0, propertyCapacity, true, IndexingHeader(), newIndexingPayloadSizeInBytes); - return oldButterfly->growArrayRight(globalData, oldStructure, propertyCapacity, hadIndexingHeader, oldIndexingPayloadSizeInBytes, newIndexingPayloadSizeInBytes); + return create(vm, 0, propertyCapacity, true, IndexingHeader(), newIndexingPayloadSizeInBytes); + return oldButterfly->growArrayRight(vm, oldStructure, propertyCapacity, hadIndexingHeader, oldIndexingPayloadSizeInBytes, newIndexingPayloadSizeInBytes); } -inline Butterfly* Butterfly::growArrayRight(JSGlobalData& globalData, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes) +inline Butterfly* Butterfly::growArrayRight(VM& vm, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes) { ASSERT_UNUSED(oldStructure, !indexingHeader()->preCapacity(oldStructure)); ASSERT_UNUSED(oldStructure, hadIndexingHeader == hasIndexingHeader(oldStructure->indexingType())); void* theBase = base(0, propertyCapacity); size_t oldSize = totalSize(0, propertyCapacity, hadIndexingHeader, oldIndexingPayloadSizeInBytes); size_t newSize = totalSize(0, propertyCapacity, true, newIndexingPayloadSizeInBytes); - if (!globalData.heap.tryReallocateStorage(&theBase, oldSize, newSize)) + if (!vm.heap.tryReallocateStorage(&theBase, oldSize, newSize)) return 0; return fromBase(theBase, 0, propertyCapacity); } -inline Butterfly* Butterfly::growArrayRight(JSGlobalData& globalData, Structure* oldStructure, size_t newIndexingPayloadSizeInBytes) +inline Butterfly* Butterfly::growArrayRight(VM& vm, Structure* oldStructure, size_t newIndexingPayloadSizeInBytes) { return growArrayRight( - globalData, oldStructure, oldStructure->outOfLineCapacity(), + vm, oldStructure, oldStructure->outOfLineCapacity(), hasIndexingHeader(oldStructure->indexingType()), indexingHeader()->indexingPayloadSizeInBytes(oldStructure), newIndexingPayloadSizeInBytes); } -inline Butterfly* Butterfly::resizeArray(JSGlobalData& globalData, size_t propertyCapacity, bool oldHasIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader, size_t newIndexingPayloadSizeInBytes) +inline Butterfly* Butterfly::resizeArray(VM& vm, size_t propertyCapacity, bool oldHasIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader, size_t newIndexingPayloadSizeInBytes) { Butterfly* result = createUninitialized( - globalData, newPreCapacity, propertyCapacity, newHasIndexingHeader, newIndexingPayloadSizeInBytes); + vm, newPreCapacity, propertyCapacity, newHasIndexingHeader, newIndexingPayloadSizeInBytes); // FIXME: This could be made much more efficient if we used the property size, // not the capacity. void* to = result->propertyStorage() - propertyCapacity; @@ -141,11 +140,11 @@ inline Butterfly* Butterfly::resizeArray(JSGlobalData& globalData, size_t proper return result; } -inline Butterfly* Butterfly::resizeArray(JSGlobalData& globalData, Structure* structure, size_t newPreCapacity, size_t newIndexingPayloadSizeInBytes) +inline Butterfly* Butterfly::resizeArray(VM& vm, Structure* structure, size_t newPreCapacity, size_t newIndexingPayloadSizeInBytes) { bool hasIndexingHeader = JSC::hasIndexingHeader(structure->indexingType()); return resizeArray( - globalData, structure->outOfLineCapacity(), hasIndexingHeader, + vm, structure->outOfLineCapacity(), hasIndexingHeader, indexingHeader()->indexingPayloadSizeInBytes(structure), newPreCapacity, hasIndexingHeader, newIndexingPayloadSizeInBytes); } diff --git a/Source/JavaScriptCore/runtime/CachedTranscendentalFunction.h b/Source/JavaScriptCore/runtime/CachedTranscendentalFunction.h index 62a01dbcb..392d64fa5 100644 --- a/Source/JavaScriptCore/runtime/CachedTranscendentalFunction.h +++ b/Source/JavaScriptCore/runtime/CachedTranscendentalFunction.h @@ -26,7 +26,7 @@ #ifndef CachedTranscendentalFunction_h #define CachedTranscendentalFunction_h -#include "JSValue.h" +#include "JSCJSValue.h" namespace JSC { diff --git a/Source/JavaScriptCore/runtime/CallData.cpp b/Source/JavaScriptCore/runtime/CallData.cpp index ff71fa0cb..8e1d19486 100644 --- a/Source/JavaScriptCore/runtime/CallData.cpp +++ b/Source/JavaScriptCore/runtime/CallData.cpp @@ -29,6 +29,7 @@ #include "Executable.h" #include "Interpreter.h" #include "JSFunction.h" +#include "Operations.h" namespace JSC { diff --git a/Source/JavaScriptCore/runtime/CallData.h b/Source/JavaScriptCore/runtime/CallData.h index 7df36c72a..3bbac734f 100644 --- a/Source/JavaScriptCore/runtime/CallData.h +++ b/Source/JavaScriptCore/runtime/CallData.h @@ -29,7 +29,7 @@ #ifndef CallData_h #define CallData_h -#include "JSValue.h" +#include "JSCJSValue.h" namespace JSC { diff --git a/Source/JavaScriptCore/runtime/CodeCache.cpp b/Source/JavaScriptCore/runtime/CodeCache.cpp index 068919528..de904ae71 100644 --- a/Source/JavaScriptCore/runtime/CodeCache.cpp +++ b/Source/JavaScriptCore/runtime/CodeCache.cpp @@ -29,127 +29,129 @@ #include "BytecodeGenerator.h" #include "CodeSpecializationKind.h" +#include "Operations.h" #include "Parser.h" #include "StrongInlines.h" #include "UnlinkedCodeBlock.h" namespace JSC { -CodeCache::CodeCache() +const double CodeCacheMap::workingSetTime = 10.0; +const int64_t CodeCacheMap::globalWorkingSetMaxBytes = 16000000; +const size_t CodeCacheMap::globalWorkingSetMaxEntries = 2000; +const unsigned CodeCacheMap::nonGlobalWorkingSetScale = 20; +const int64_t CodeCacheMap::nonGlobalWorkingSetMaxBytes = CodeCacheMap::globalWorkingSetMaxBytes / CodeCacheMap::nonGlobalWorkingSetScale; +const size_t CodeCacheMap::nonGlobalWorkingSetMaxEntries = CodeCacheMap::globalWorkingSetMaxEntries / CodeCacheMap::nonGlobalWorkingSetScale; + +void CodeCacheMap::pruneSlowCase() { + m_minCapacity = std::max(m_size - m_sizeAtLastPrune, static_cast<int64_t>(0)); + m_sizeAtLastPrune = m_size; + m_timeAtLastPrune = monotonicallyIncreasingTime(); + + if (m_capacity < m_minCapacity) + m_capacity = m_minCapacity; + + while (m_size > m_capacity || !canPruneQuickly()) { + MapType::iterator it = m_map.begin(); + m_size -= it->key.length(); + m_map.remove(it); + } } -CodeCache::~CodeCache() +CodeCache::CodeCache(CodeCacheKind kind) +: m_sourceCode(kind == GlobalCodeCache ? CodeCacheMap::globalWorkingSetMaxBytes : CodeCacheMap::nonGlobalWorkingSetMaxBytes, + kind == GlobalCodeCache ? CodeCacheMap::globalWorkingSetMaxEntries : CodeCacheMap::nonGlobalWorkingSetMaxEntries) { } -CodeCache::CodeBlockKey CodeCache::makeCodeBlockKey(const SourceCode& source, CodeCache::CodeType type, JSParserStrictness strictness) +CodeCache::~CodeCache() { - return std::make_pair(source.toString(), (type << 1) | strictness); } template <typename T> struct CacheTypes { }; template <> struct CacheTypes<UnlinkedProgramCodeBlock> { typedef JSC::ProgramNode RootNode; - static const CodeCache::CodeType codeType = CodeCache::ProgramType; + static const SourceCodeKey::CodeType codeType = SourceCodeKey::ProgramType; }; template <> struct CacheTypes<UnlinkedEvalCodeBlock> { typedef JSC::EvalNode RootNode; - static const CodeCache::CodeType codeType = CodeCache::EvalType; + static const SourceCodeKey::CodeType codeType = SourceCodeKey::EvalType; }; template <class UnlinkedCodeBlockType, class ExecutableType> -UnlinkedCodeBlockType* CodeCache::getCodeBlock(JSGlobalData& globalData, ExecutableType* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) +UnlinkedCodeBlockType* CodeCache::generateBytecode(VM& vm, JSScope* scope, ExecutableType* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) { - CodeBlockKey key = makeCodeBlockKey(source, CacheTypes<UnlinkedCodeBlockType>::codeType, strictness); - bool storeInCache = false; - if (debuggerMode == DebuggerOff && profilerMode == ProfilerOff) { - const Strong<UnlinkedCodeBlock>* result = m_cachedCodeBlocks.find(key); - if (result) { - UnlinkedCodeBlockType* unlinkedCode = jsCast<UnlinkedCodeBlockType*>(result->get()); - unsigned firstLine = source.firstLine() + unlinkedCode->firstLine(); - executable->recordParse(unlinkedCode->codeFeatures(), unlinkedCode->hasCapturedVariables(), firstLine, firstLine + unlinkedCode->lineCount()); - return unlinkedCode; - } - storeInCache = true; - } - typedef typename CacheTypes<UnlinkedCodeBlockType>::RootNode RootNode; - RefPtr<RootNode> rootNode = parse<RootNode>(&globalData, source, 0, Identifier(), strictness, JSParseProgramCode, error); + RefPtr<RootNode> rootNode = parse<RootNode>(&vm, source, 0, Identifier(), strictness, JSParseProgramCode, error); if (!rootNode) return 0; - executable->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->lineNo(), rootNode->lastLine()); + executable->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->lineNo(), rootNode->lastLine(), rootNode->startColumn()); - UnlinkedCodeBlockType* unlinkedCode = UnlinkedCodeBlockType::create(&globalData, executable->executableInfo()); + UnlinkedCodeBlockType* unlinkedCode = UnlinkedCodeBlockType::create(&vm, executable->executableInfo()); unlinkedCode->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->lineNo() - source.firstLine(), rootNode->lastLine() - rootNode->lineNo()); - OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(globalData, rootNode.get(), unlinkedCode, debuggerMode, profilerMode))); + OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(vm, scope, rootNode.get(), unlinkedCode, debuggerMode, profilerMode))); error = generator->generate(); rootNode->destroyData(); if (error.m_type != ParserError::ErrorNone) return 0; - - if (storeInCache) - m_cachedCodeBlocks.add(key, Strong<UnlinkedCodeBlock>(globalData, unlinkedCode)); - return unlinkedCode; } -UnlinkedProgramCodeBlock* CodeCache::getProgramCodeBlock(JSGlobalData& globalData, ProgramExecutable* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) +template <class UnlinkedCodeBlockType, class ExecutableType> +UnlinkedCodeBlockType* CodeCache::getCodeBlock(VM& vm, JSScope* scope, ExecutableType* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) { - return getCodeBlock<UnlinkedProgramCodeBlock>(globalData, executable, source, strictness, debuggerMode, profilerMode, error); -} + // We completely skip the cache if we're an eval that isn't at the top of the scope chain. + if (CacheTypes<UnlinkedCodeBlockType>::codeType == SourceCodeKey::EvalType) { + if (scope->next() && !scope->isActivationObject()) + return generateBytecode<UnlinkedCodeBlockType, ExecutableType>(vm, scope, executable, source, strictness, debuggerMode, profilerMode, error); + } -UnlinkedEvalCodeBlock* CodeCache::getEvalCodeBlock(JSGlobalData& globalData, EvalExecutable* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) -{ - return getCodeBlock<UnlinkedEvalCodeBlock>(globalData, executable, source, strictness, debuggerMode, profilerMode, error); -} + SourceCodeKey key = SourceCodeKey(source, String(), CacheTypes<UnlinkedCodeBlockType>::codeType, strictness); + CodeCacheMap::AddResult addResult = m_sourceCode.add(key, SourceCodeValue()); + bool canCache = debuggerMode == DebuggerOff && profilerMode == ProfilerOff; -UnlinkedFunctionCodeBlock* CodeCache::generateFunctionCodeBlock(JSGlobalData& globalData, UnlinkedFunctionExecutable* executable, const SourceCode& source, CodeSpecializationKind kind, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) -{ - RefPtr<FunctionBodyNode> body = parse<FunctionBodyNode>(&globalData, source, executable->parameters(), executable->name(), executable->isInStrictContext() ? JSParseStrict : JSParseNormal, JSParseFunctionCode, error); + if (!addResult.isNewEntry && canCache) { + UnlinkedCodeBlockType* unlinkedCode = jsCast<UnlinkedCodeBlockType*>(addResult.iterator->value.cell.get()); + unsigned firstLine = source.firstLine() + unlinkedCode->firstLine(); + unsigned startColumn = source.firstLine() ? source.startColumn() : 0; + executable->recordParse(unlinkedCode->codeFeatures(), unlinkedCode->hasCapturedVariables(), firstLine, firstLine + unlinkedCode->lineCount(), startColumn); + return unlinkedCode; + } + UnlinkedCodeBlockType* unlinkedCode = generateBytecode<UnlinkedCodeBlockType, ExecutableType>(vm, scope, executable, source, strictness, debuggerMode, profilerMode, error); - if (!body) { - ASSERT(error.m_type != ParserError::ErrorNone); - return 0; + if (!canCache || !unlinkedCode) { + m_sourceCode.remove(addResult.iterator); + return unlinkedCode; } - if (executable->forceUsesArguments()) - body->setUsesArguments(); - body->finishParsing(executable->parameters(), executable->name(), executable->functionNameIsInScopeToggle()); - executable->recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine()); - - UnlinkedFunctionCodeBlock* result = UnlinkedFunctionCodeBlock::create(&globalData, FunctionCode, ExecutableInfo(body->needsActivation(), body->usesEval(), body->isStrictMode(), kind == CodeForConstruct)); - OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(globalData, body.get(), result, debuggerMode, profilerMode))); - error = generator->generate(); - body->destroyData(); - if (error.m_type != ParserError::ErrorNone) - return 0; - m_cachedFunctionCode.add(result, Strong<UnlinkedFunctionCodeBlock>(globalData, result)); - return result; + addResult.iterator->value = SourceCodeValue(vm, unlinkedCode, m_sourceCode.age()); + return unlinkedCode; } -UnlinkedFunctionCodeBlock* CodeCache::getFunctionCodeBlock(JSGlobalData& globalData, UnlinkedFunctionExecutable* executable, const SourceCode& source, CodeSpecializationKind kind, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) +UnlinkedProgramCodeBlock* CodeCache::getProgramCodeBlock(VM& vm, ProgramExecutable* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) { - return generateFunctionCodeBlock(globalData, executable, source, kind, debuggerMode, profilerMode, error); + return getCodeBlock<UnlinkedProgramCodeBlock>(vm, 0, executable, source, strictness, debuggerMode, profilerMode, error); } -CodeCache::GlobalFunctionKey CodeCache::makeGlobalFunctionKey(const SourceCode& source, const String& name) +UnlinkedEvalCodeBlock* CodeCache::getEvalCodeBlock(VM& vm, JSScope* scope, EvalExecutable* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) { - return GlobalFunctionKey(source.toString(), name); + return getCodeBlock<UnlinkedEvalCodeBlock>(vm, scope, executable, source, strictness, debuggerMode, profilerMode, error); } -UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(JSGlobalData& globalData, const Identifier& name, const SourceCode& source, ParserError& error) +UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(VM& vm, const Identifier& name, const SourceCode& source, ParserError& error) { - GlobalFunctionKey key = makeGlobalFunctionKey(source, name.string()); - const Strong<UnlinkedFunctionExecutable>* result = m_cachedGlobalFunctions.find(key); - if (result) - return result->get(); + SourceCodeKey key = SourceCodeKey(source, name.string(), SourceCodeKey::FunctionType, JSParseNormal); + CodeCacheMap::AddResult addResult = m_sourceCode.add(key, SourceCodeValue()); + if (!addResult.isNewEntry) + return jsCast<UnlinkedFunctionExecutable*>(addResult.iterator->value.cell.get()); - RefPtr<ProgramNode> program = parse<ProgramNode>(&globalData, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error); + RefPtr<ProgramNode> program = parse<ProgramNode>(&vm, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error); if (!program) { ASSERT(error.m_type != ParserError::ErrorNone); + m_sourceCode.remove(addResult.iterator); return 0; } @@ -159,21 +161,16 @@ UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(JSGlo ASSERT(exprStatement->isExprStatement()); ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr(); ASSERT(funcExpr); - ASSERT(funcExpr->isFuncExprNode()); + RELEASE_ASSERT(funcExpr->isFuncExprNode()); FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body(); ASSERT(body); ASSERT(body->ident().isNull()); - UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&globalData, source, body); - functionExecutable->m_nameValue.set(globalData, functionExecutable, jsString(&globalData, name.string())); + UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, body); + functionExecutable->m_nameValue.set(vm, functionExecutable, jsString(&vm, name.string())); - m_cachedGlobalFunctions.add(key, Strong<UnlinkedFunctionExecutable>(globalData, functionExecutable)); + addResult.iterator->value = SourceCodeValue(vm, functionExecutable, m_sourceCode.age()); return functionExecutable; } -void CodeCache::usedFunctionCode(JSGlobalData& globalData, UnlinkedFunctionCodeBlock* codeBlock) -{ - m_cachedFunctionCode.add(codeBlock, Strong<UnlinkedFunctionCodeBlock>(globalData, codeBlock)); -} - } diff --git a/Source/JavaScriptCore/runtime/CodeCache.h b/Source/JavaScriptCore/runtime/CodeCache.h index 733de42d6..986b266c2 100644 --- a/Source/JavaScriptCore/runtime/CodeCache.h +++ b/Source/JavaScriptCore/runtime/CodeCache.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All Rights Reserved. + * Copyright (C) 2012, 2013 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,9 +28,10 @@ #include "CodeSpecializationKind.h" #include "ParserModes.h" +#include "SourceCode.h" #include "Strong.h" #include "WeakRandom.h" - +#include <wtf/CurrentTime.h> #include <wtf/FixedArray.h> #include <wtf/Forward.h> #include <wtf/PassOwnPtr.h> @@ -40,88 +41,239 @@ namespace JSC { class EvalExecutable; +class FunctionBodyNode; class Identifier; +class JSScope; class ProgramExecutable; class UnlinkedCodeBlock; class UnlinkedEvalCodeBlock; class UnlinkedFunctionCodeBlock; class UnlinkedFunctionExecutable; class UnlinkedProgramCodeBlock; -class JSGlobalData; +class VM; struct ParserError; class SourceCode; class SourceProvider; -template <typename KeyType, typename EntryType, int CacheSize> class CacheMap { - typedef typename HashMap<KeyType, unsigned>::iterator iterator; +class SourceCodeKey { public: - CacheMap() - : m_randomGenerator((static_cast<uint32_t>(randomNumber() * std::numeric_limits<uint32_t>::max()))) + enum CodeType { EvalType, ProgramType, FunctionType }; + + SourceCodeKey() { } - const EntryType* find(const KeyType& key) + + SourceCodeKey(const SourceCode& sourceCode, const String& name, CodeType codeType, JSParserStrictness jsParserStrictness) + : m_sourceCode(sourceCode) + , m_name(name) + , m_flags((codeType << 1) | jsParserStrictness) + , m_hash(string().impl()->hash()) { - iterator result = m_map.find(key); - if (result == m_map.end()) - return 0; - return &m_data[result->value].second; } - void add(const KeyType& key, const EntryType& value) + + SourceCodeKey(WTF::HashTableDeletedValueType) + : m_sourceCode(WTF::HashTableDeletedValue) { - iterator result = m_map.find(key); - if (result != m_map.end()) { - m_data[result->value].second = value; - return; + } + + bool isHashTableDeletedValue() const { return m_sourceCode.isHashTableDeletedValue(); } + + unsigned hash() const { return m_hash; } + + size_t length() const { return m_sourceCode.length(); } + + bool isNull() const { return m_sourceCode.isNull(); } + + // To save memory, we compute our string on demand. It's expected that source + // providers cache their strings to make this efficient. + String string() const { return m_sourceCode.toString(); } + + bool operator==(const SourceCodeKey& other) const + { + return m_hash == other.m_hash + && length() == other.length() + && m_flags == other.m_flags + && m_name == other.m_name + && string() == other.string(); + } + +private: + SourceCode m_sourceCode; + String m_name; + unsigned m_flags; + unsigned m_hash; +}; + +struct SourceCodeKeyHash { + static unsigned hash(const SourceCodeKey& key) { return key.hash(); } + static bool equal(const SourceCodeKey& a, const SourceCodeKey& b) { return a == b; } + static const bool safeToCompareToEmptyOrDeleted = false; +}; + +struct SourceCodeKeyHashTraits : SimpleClassHashTraits<SourceCodeKey> { + static const bool hasIsEmptyValueFunction = true; + static bool isEmptyValue(const SourceCodeKey& sourceCodeKey) { return sourceCodeKey.isNull(); } +}; + +struct SourceCodeValue { + SourceCodeValue() + { + } + + SourceCodeValue(VM& vm, JSCell* cell, int64_t age) + : cell(vm, cell) + , age(age) + { + } + + Strong<JSCell> cell; + int64_t age; +}; + +class CodeCacheMap { +public: + typedef HashMap<SourceCodeKey, SourceCodeValue, SourceCodeKeyHash, SourceCodeKeyHashTraits> MapType; + typedef MapType::iterator iterator; + typedef MapType::AddResult AddResult; + + CodeCacheMap(int64_t workingSetMaxBytes, size_t workingSetMaxEntries) + : m_size(0) + , m_sizeAtLastPrune(0) + , m_timeAtLastPrune(monotonicallyIncreasingTime()) + , m_minCapacity(0) + , m_capacity(0) + , m_age(0) + , m_workingSetMaxBytes(workingSetMaxBytes) + , m_workingSetMaxEntries(workingSetMaxEntries) + { + } + + AddResult add(const SourceCodeKey& key, const SourceCodeValue& value) + { + prune(); + + AddResult addResult = m_map.add(key, value); + if (addResult.isNewEntry) { + m_size += key.length(); + m_age += key.length(); + return addResult; + } + + int64_t age = m_age - addResult.iterator->value.age; + if (age > m_capacity) { + // A requested object is older than the cache's capacity. We can + // infer that requested objects are subject to high eviction probability, + // so we grow the cache to improve our hit rate. + m_capacity += recencyBias * oldObjectSamplingMultiplier * key.length(); + } else if (age < m_capacity / 2) { + // A requested object is much younger than the cache's capacity. We can + // infer that requested objects are subject to low eviction probability, + // so we shrink the cache to save memory. + m_capacity -= recencyBias * key.length(); + if (m_capacity < m_minCapacity) + m_capacity = m_minCapacity; } - size_t newIndex = m_randomGenerator.getUint32() % CacheSize; - if (m_data[newIndex].second) - m_map.remove(m_data[newIndex].first); - m_map.add(key, newIndex); - m_data[newIndex].first = key; - m_data[newIndex].second = value; - ASSERT(m_map.size() <= CacheSize); + + addResult.iterator->value.age = m_age; + m_age += key.length(); + return addResult; } + + void remove(iterator it) + { + m_size -= it->key.length(); + m_map.remove(it); + } + + void clear() + { + m_size = 0; + m_age = 0; + m_map.clear(); + } + + int64_t age() { return m_age; } + + static const int64_t globalWorkingSetMaxBytes; + static const size_t globalWorkingSetMaxEntries; + + // We have a smaller cap for the per-codeblock CodeCache that approximates the + // linked EvalCodeCache limits, but still allows us to keep large string based + // evals at least partially cached. + static const unsigned nonGlobalWorkingSetScale; + static const int64_t nonGlobalWorkingSetMaxBytes; + static const size_t nonGlobalWorkingSetMaxEntries; + private: - HashMap<KeyType, unsigned> m_map; - FixedArray<std::pair<KeyType, EntryType>, CacheSize> m_data; - WeakRandom m_randomGenerator; + // This constant factor biases cache capacity toward allowing a minimum + // working set to enter the cache before it starts evicting. + static const double workingSetTime; + + // This constant factor biases cache capacity toward recent activity. We + // want to adapt to changing workloads. + static const int64_t recencyBias = 4; + + // This constant factor treats a sampled event for one old object as if it + // happened for many old objects. Most old objects are evicted before we can + // sample them, so we need to extrapolate from the ones we do sample. + static const int64_t oldObjectSamplingMultiplier = 32; + + size_t numberOfEntries() const { return static_cast<size_t>(m_map.size()); } + bool canPruneQuickly() const { return numberOfEntries() < m_workingSetMaxEntries; } + + void pruneSlowCase(); + void prune() + { + if (m_size <= m_capacity && canPruneQuickly()) + return; + + if (monotonicallyIncreasingTime() - m_timeAtLastPrune < workingSetTime + && m_size - m_sizeAtLastPrune < m_workingSetMaxBytes + && canPruneQuickly()) + return; + + pruneSlowCase(); + } + + MapType m_map; + int64_t m_size; + int64_t m_sizeAtLastPrune; + double m_timeAtLastPrune; + int64_t m_minCapacity; + int64_t m_capacity; + int64_t m_age; + const int64_t m_workingSetMaxBytes; + const size_t m_workingSetMaxEntries; }; -class CodeCache { +// Caches top-level code such as <script>, eval(), new Function, and JSEvaluateScript(). +class CodeCache : public RefCounted<CodeCache> { public: - static PassOwnPtr<CodeCache> create() { return adoptPtr(new CodeCache); } + enum CodeCacheKind { GlobalCodeCache, NonGlobalCodeCache }; + static PassRefPtr<CodeCache> create(CodeCacheKind kind) { return adoptRef(new CodeCache(kind)); } - UnlinkedProgramCodeBlock* getProgramCodeBlock(JSGlobalData&, ProgramExecutable*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&); - UnlinkedEvalCodeBlock* getEvalCodeBlock(JSGlobalData&, EvalExecutable*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&); - UnlinkedFunctionCodeBlock* getFunctionCodeBlock(JSGlobalData&, UnlinkedFunctionExecutable*, const SourceCode&, CodeSpecializationKind, DebuggerMode, ProfilerMode, ParserError&); - UnlinkedFunctionExecutable* getFunctionExecutableFromGlobalCode(JSGlobalData&, const Identifier&, const SourceCode&, ParserError&); - void usedFunctionCode(JSGlobalData&, UnlinkedFunctionCodeBlock*); + UnlinkedProgramCodeBlock* getProgramCodeBlock(VM&, ProgramExecutable*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&); + UnlinkedEvalCodeBlock* getEvalCodeBlock(VM&, JSScope*, EvalExecutable*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&); + UnlinkedFunctionExecutable* getFunctionExecutableFromGlobalCode(VM&, const Identifier&, const SourceCode&, ParserError&); ~CodeCache(); - enum CodeType { EvalType, ProgramType, FunctionType }; - typedef std::pair<String, unsigned> CodeBlockKey; - typedef std::pair<String, String> GlobalFunctionKey; + void clear() + { + m_sourceCode.clear(); + } private: - CodeCache(); - - UnlinkedFunctionCodeBlock* generateFunctionCodeBlock(JSGlobalData&, UnlinkedFunctionExecutable*, const SourceCode&, CodeSpecializationKind, DebuggerMode, ProfilerMode, ParserError&); + CodeCache(CodeCacheKind); - template <class UnlinkedCodeBlockType, class ExecutableType> inline UnlinkedCodeBlockType* getCodeBlock(JSGlobalData&, ExecutableType*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&); - CodeBlockKey makeCodeBlockKey(const SourceCode&, CodeType, JSParserStrictness); - GlobalFunctionKey makeGlobalFunctionKey(const SourceCode&, const String&); + template <class UnlinkedCodeBlockType, class ExecutableType> + UnlinkedCodeBlockType* getCodeBlock(VM&, JSScope*, ExecutableType*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&); - enum { - kMaxCodeBlockEntries = 1024, - kMaxGlobalFunctionEntries = 1024, - kMaxFunctionCodeBlocks = 1024 - }; + template <class UnlinkedCodeBlockType, class ExecutableType> + UnlinkedCodeBlockType* generateBytecode(VM&, JSScope*, ExecutableType*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&); - CacheMap<CodeBlockKey, Strong<UnlinkedCodeBlock>, kMaxCodeBlockEntries> m_cachedCodeBlocks; - CacheMap<GlobalFunctionKey, Strong<UnlinkedFunctionExecutable>, kMaxGlobalFunctionEntries> m_cachedGlobalFunctions; - CacheMap<UnlinkedFunctionCodeBlock*, Strong<UnlinkedFunctionCodeBlock>, kMaxFunctionCodeBlocks> m_cachedFunctionCode; + CodeCacheMap m_sourceCode; }; } -#endif +#endif // CodeCache_h diff --git a/Source/JavaScriptCore/runtime/CommonIdentifiers.cpp b/Source/JavaScriptCore/runtime/CommonIdentifiers.cpp index e929d7a49..e19df1c64 100644 --- a/Source/JavaScriptCore/runtime/CommonIdentifiers.cpp +++ b/Source/JavaScriptCore/runtime/CommonIdentifiers.cpp @@ -23,15 +23,15 @@ namespace JSC { -#define INITIALIZE_PROPERTY_NAME(name) , name(globalData, #name) -#define INITIALIZE_KEYWORD(name) , name##Keyword(globalData, #name) +#define INITIALIZE_PROPERTY_NAME(name) , name(vm, #name) +#define INITIALIZE_KEYWORD(name) , name##Keyword(vm, #name) -CommonIdentifiers::CommonIdentifiers(JSGlobalData* globalData) +CommonIdentifiers::CommonIdentifiers(VM* vm) : nullIdentifier() , emptyIdentifier(Identifier::EmptyIdentifier) - , underscoreProto(globalData, "__proto__") - , thisIdentifier(globalData, "this") - , useStrictIdentifier(globalData, "use strict") + , underscoreProto(vm, "__proto__") + , thisIdentifier(vm, "this") + , useStrictIdentifier(vm, "use strict") JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(INITIALIZE_KEYWORD) JSC_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PROPERTY_NAME) { diff --git a/Source/JavaScriptCore/runtime/CommonIdentifiers.h b/Source/JavaScriptCore/runtime/CommonIdentifiers.h index ae3b45b8c..13cf037d5 100644 --- a/Source/JavaScriptCore/runtime/CommonIdentifiers.h +++ b/Source/JavaScriptCore/runtime/CommonIdentifiers.h @@ -27,40 +27,93 @@ // MarkedArgumentBuffer of property names, passed to a macro so we can do set them up various // ways without repeating the list. #define JSC_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(macro) \ + macro(Array) \ + macro(Boolean) \ + macro(Date) \ + macro(Error) \ + macro(EvalError) \ + macro(Function) \ + macro(Infinity) \ + macro(JSON) \ + macro(Math) \ + macro(NaN) \ + macro(Number) \ + macro(Object) \ + macro(RangeError) \ + macro(ReferenceError) \ + macro(RegExp) \ + macro(String) \ + macro(SyntaxError) \ + macro(TypeError) \ + macro(URIError) \ + macro(UTC) \ + macro(__defineGetter__) \ + macro(__defineSetter__) \ + macro(__lookupGetter__) \ + macro(__lookupSetter__) \ + macro(anonymous) \ macro(apply) \ macro(arguments) \ - macro(Array) \ macro(bind) \ + macro(bytecode) \ + macro(bytecodeIndex) \ + macro(bytecodes) \ + macro(bytecodesID) \ macro(call) \ macro(callee) \ macro(caller) \ + macro(compilationKind) \ + macro(compilations) \ macro(compile) \ macro(configurable) \ macro(constructor) \ + macro(count) \ + macro(counters) \ + macro(description) \ + macro(descriptions) \ + macro(displayName) \ + macro(document) \ macro(enumerable) \ macro(eval) \ macro(exec) \ + macro(executionCount) \ + macro(exitKind) \ macro(fromCharCode) \ - macro(global) \ macro(get) \ + macro(global) \ macro(hasOwnProperty) \ + macro(hash) \ + macro(header) \ + macro(id) \ macro(ignoreCase) \ macro(index) \ + macro(inferredName) \ macro(input) \ + macro(instructionCount) \ macro(isArray) \ macro(isPrototypeOf) \ + macro(isWatchpoint) \ + macro(join) \ macro(lastIndex) \ macro(length) \ macro(message) \ macro(multiline) \ macro(name) \ macro(now) \ - macro(Object) \ + macro(numInlinedCalls) \ + macro(numInlinedGetByIds) \ + macro(numInlinedPutByIds) \ + macro(opcode) \ + macro(origin) \ + macro(osrExitSites) \ + macro(osrExits) \ macro(parse) \ + macro(profiledBytecodes) \ macro(propertyIsEnumerable) \ macro(prototype) \ macro(set) \ macro(source) \ + macro(sourceCode) \ macro(stack) \ macro(test) \ macro(toExponential) \ @@ -70,12 +123,10 @@ macro(toLocaleString) \ macro(toPrecision) \ macro(toString) \ - macro(UTC) \ macro(value) \ macro(valueOf) \ - macro(writable) \ - macro(displayName) \ - macro(join) + macro(window) \ + macro(writable) #define JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(macro) \ macro(null) \ @@ -130,8 +181,8 @@ namespace JSC { class CommonIdentifiers { WTF_MAKE_NONCOPYABLE(CommonIdentifiers); WTF_MAKE_FAST_ALLOCATED; private: - CommonIdentifiers(JSGlobalData*); - friend class JSGlobalData; + CommonIdentifiers(VM*); + friend class VM; public: const Identifier nullIdentifier; diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.h b/Source/JavaScriptCore/runtime/CommonSlowPaths.h index 2f5159461..731b773f0 100644 --- a/Source/JavaScriptCore/runtime/CommonSlowPaths.h +++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.h @@ -78,7 +78,7 @@ ALWAYS_INLINE ExecState* arityCheckFor(ExecState* exec, JSStack* stack, CodeSpec inline bool opIn(ExecState* exec, JSValue propName, JSValue baseVal) { if (!baseVal.isObject()) { - exec->globalData().exception = createInvalidParamError(exec, "in", baseVal); + exec->vm().exception = createInvalidParameterError(exec, "in", baseVal); return false; } @@ -92,7 +92,7 @@ inline bool opIn(ExecState* exec, JSValue propName, JSValue baseVal) return baseObj->hasProperty(exec, jsCast<NameInstance*>(propName.asCell())->privateName()); Identifier property(exec, propName.toString(exec)->value(exec)); - if (exec->globalData().exception) + if (exec->vm().exception) return false; return baseObj->hasProperty(exec, property); } diff --git a/Source/JavaScriptCore/runtime/Completion.cpp b/Source/JavaScriptCore/runtime/Completion.cpp index 3de8d4841..a2d8a6b5f 100644 --- a/Source/JavaScriptCore/runtime/Completion.cpp +++ b/Source/JavaScriptCore/runtime/Completion.cpp @@ -25,11 +25,12 @@ #include "CallFrame.h" #include "CodeProfiling.h" +#include "Debugger.h" +#include "Interpreter.h" #include "JSGlobalObject.h" #include "JSLock.h" -#include "Interpreter.h" +#include "Operations.h" #include "Parser.h" -#include "Debugger.h" #include <wtf/WTFThreadData.h> #include <stdio.h> @@ -38,7 +39,7 @@ namespace JSC { bool checkSyntax(ExecState* exec, const SourceCode& source, JSValue* returnedException) { JSLockHolder lock(exec); - ASSERT(exec->globalData().identifierTable == wtfThreadData().currentIdentifierTable()); + RELEASE_ASSERT(exec->vm().identifierTable == wtfThreadData().currentIdentifierTable()); ProgramExecutable* program = ProgramExecutable::create(exec, source); JSObject* error = program->checkSyntax(exec); @@ -50,22 +51,29 @@ bool checkSyntax(ExecState* exec, const SourceCode& source, JSValue* returnedExc return true; } + +bool checkSyntax(VM& vm, const SourceCode& source, ParserError& error) +{ + JSLockHolder lock(vm); + RELEASE_ASSERT(vm.identifierTable == wtfThreadData().currentIdentifierTable()); + RefPtr<ProgramNode> programNode = parse<ProgramNode>(&vm, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error); + return programNode; +} JSValue evaluate(ExecState* exec, const SourceCode& source, JSValue thisValue, JSValue* returnedException) { JSLockHolder lock(exec); - ASSERT(exec->globalData().identifierTable == wtfThreadData().currentIdentifierTable()); - if (exec->globalData().isCollectorBusy()) - CRASH(); + RELEASE_ASSERT(exec->vm().identifierTable == wtfThreadData().currentIdentifierTable()); + RELEASE_ASSERT(!exec->vm().isCollectorBusy()); CodeProfiling profile(source); ProgramExecutable* program = ProgramExecutable::create(exec, source); if (!program) { if (returnedException) - *returnedException = exec->globalData().exception; + *returnedException = exec->vm().exception; - exec->globalData().exception = JSValue(); + exec->vm().exception = JSValue(); return jsUndefined(); } @@ -82,7 +90,7 @@ JSValue evaluate(ExecState* exec, const SourceCode& source, JSValue thisValue, J return jsUndefined(); } - ASSERT(result); + RELEASE_ASSERT(result); return result; } diff --git a/Source/JavaScriptCore/runtime/Completion.h b/Source/JavaScriptCore/runtime/Completion.h index d150fcea2..78f8ac795 100644 --- a/Source/JavaScriptCore/runtime/Completion.h +++ b/Source/JavaScriptCore/runtime/Completion.h @@ -23,14 +23,17 @@ #ifndef Completion_h #define Completion_h -#include "JSValue.h" +#include "JSCJSValue.h" namespace JSC { - + + struct ParserError; class ExecState; class JSScope; class SourceCode; + class VM; + JS_EXPORT_PRIVATE bool checkSyntax(VM&, const SourceCode&, ParserError&); JS_EXPORT_PRIVATE bool checkSyntax(ExecState*, const SourceCode&, JSValue* exception = 0); JS_EXPORT_PRIVATE JSValue evaluate(ExecState*, const SourceCode&, JSValue thisValue = JSValue(), JSValue* exception = 0); diff --git a/Source/JavaScriptCore/runtime/ConstructData.cpp b/Source/JavaScriptCore/runtime/ConstructData.cpp index 5da2a911c..3dc46180c 100644 --- a/Source/JavaScriptCore/runtime/ConstructData.cpp +++ b/Source/JavaScriptCore/runtime/ConstructData.cpp @@ -30,6 +30,7 @@ #include "Interpreter.h" #include "JSFunction.h" #include "JSGlobalObject.h" +#include "Operations.h" namespace JSC { diff --git a/Source/JavaScriptCore/runtime/ConstructData.h b/Source/JavaScriptCore/runtime/ConstructData.h index 6426b044e..10317a2f9 100644 --- a/Source/JavaScriptCore/runtime/ConstructData.h +++ b/Source/JavaScriptCore/runtime/ConstructData.h @@ -30,7 +30,7 @@ #define ConstructData_h #include "CallData.h" -#include "JSValue.h" +#include "JSCJSValue.h" namespace JSC { diff --git a/Source/JavaScriptCore/runtime/DateConstructor.cpp b/Source/JavaScriptCore/runtime/DateConstructor.cpp index 9a162e9e7..b21a5d0c2 100644 --- a/Source/JavaScriptCore/runtime/DateConstructor.cpp +++ b/Source/JavaScriptCore/runtime/DateConstructor.cpp @@ -31,6 +31,7 @@ #include "JSString.h" #include "JSStringBuilder.h" #include "ObjectPrototype.h" +#include "Operations.h" #include <math.h> #include <time.h> #include <wtf/MathExtras.h> @@ -80,9 +81,9 @@ DateConstructor::DateConstructor(JSGlobalObject* globalObject, Structure* struct void DateConstructor::finishCreation(ExecState* exec, DatePrototype* datePrototype) { - Base::finishCreation(exec->globalData(), datePrototype->classInfo()->className); - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, datePrototype, DontEnum | DontDelete | ReadOnly); - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(7), ReadOnly | DontEnum | DontDelete); + Base::finishCreation(exec->vm(), datePrototype->classInfo()->className); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().prototype, datePrototype, DontEnum | DontDelete | ReadOnly); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().length, jsNumber(7), ReadOnly | DontEnum | DontDelete); } bool DateConstructor::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot &slot) @@ -124,13 +125,13 @@ JSObject* constructDate(ExecState* exec, JSGlobalObject* globalObject, const Arg args.at(5).toNumber(exec), args.at(6).toNumber(exec) }; - if (!isfinite(doubleArguments[0]) - || !isfinite(doubleArguments[1]) - || (numArgs >= 3 && !isfinite(doubleArguments[2])) - || (numArgs >= 4 && !isfinite(doubleArguments[3])) - || (numArgs >= 5 && !isfinite(doubleArguments[4])) - || (numArgs >= 6 && !isfinite(doubleArguments[5])) - || (numArgs >= 7 && !isfinite(doubleArguments[6]))) + if (!std::isfinite(doubleArguments[0]) + || !std::isfinite(doubleArguments[1]) + || (numArgs >= 3 && !std::isfinite(doubleArguments[2])) + || (numArgs >= 4 && !std::isfinite(doubleArguments[3])) + || (numArgs >= 5 && !std::isfinite(doubleArguments[4])) + || (numArgs >= 6 && !std::isfinite(doubleArguments[5])) + || (numArgs >= 7 && !std::isfinite(doubleArguments[6]))) value = QNaN; else { GregorianDateTime t; @@ -198,13 +199,13 @@ static EncodedJSValue JSC_HOST_CALL dateUTC(ExecState* exec) exec->argument(6).toNumber(exec) }; int n = exec->argumentCount(); - if (isnan(doubleArguments[0]) - || isnan(doubleArguments[1]) - || (n >= 3 && isnan(doubleArguments[2])) - || (n >= 4 && isnan(doubleArguments[3])) - || (n >= 5 && isnan(doubleArguments[4])) - || (n >= 6 && isnan(doubleArguments[5])) - || (n >= 7 && isnan(doubleArguments[6]))) + if (std::isnan(doubleArguments[0]) + || std::isnan(doubleArguments[1]) + || (n >= 3 && std::isnan(doubleArguments[2])) + || (n >= 4 && std::isnan(doubleArguments[3])) + || (n >= 5 && std::isnan(doubleArguments[4])) + || (n >= 6 && std::isnan(doubleArguments[5])) + || (n >= 7 && std::isnan(doubleArguments[6]))) return JSValue::encode(jsNaN()); GregorianDateTime t; diff --git a/Source/JavaScriptCore/runtime/DateConstructor.h b/Source/JavaScriptCore/runtime/DateConstructor.h index f089e036c..5a6200e99 100644 --- a/Source/JavaScriptCore/runtime/DateConstructor.h +++ b/Source/JavaScriptCore/runtime/DateConstructor.h @@ -40,9 +40,9 @@ namespace JSC { static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } protected: diff --git a/Source/JavaScriptCore/runtime/DateInstance.cpp b/Source/JavaScriptCore/runtime/DateInstance.cpp index 47a19df47..db7b84634 100644 --- a/Source/JavaScriptCore/runtime/DateInstance.cpp +++ b/Source/JavaScriptCore/runtime/DateInstance.cpp @@ -24,7 +24,7 @@ #include "JSDateMath.h" #include "JSGlobalObject.h" - +#include "Operations.h" #include <math.h> #include <wtf/MathExtras.h> @@ -35,22 +35,22 @@ namespace JSC { const ClassInfo DateInstance::s_info = {"Date", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(DateInstance)}; DateInstance::DateInstance(ExecState* exec, Structure* structure) - : JSWrapperObject(exec->globalData(), structure) + : JSWrapperObject(exec->vm(), structure) { } -void DateInstance::finishCreation(JSGlobalData& globalData) +void DateInstance::finishCreation(VM& vm) { - Base::finishCreation(globalData); + Base::finishCreation(vm); ASSERT(inherits(&s_info)); - setInternalValue(globalData, jsNaN()); + setInternalValue(vm, jsNaN()); } -void DateInstance::finishCreation(JSGlobalData& globalData, double time) +void DateInstance::finishCreation(VM& vm, double time) { - Base::finishCreation(globalData); + Base::finishCreation(vm); ASSERT(inherits(&s_info)); - setInternalValue(globalData, jsNumber(timeClip(time))); + setInternalValue(vm, jsNumber(timeClip(time))); } void DateInstance::destroy(JSCell* cell) @@ -61,11 +61,11 @@ void DateInstance::destroy(JSCell* cell) const GregorianDateTime* DateInstance::calculateGregorianDateTime(ExecState* exec) const { double milli = internalNumber(); - if (isnan(milli)) + if (std::isnan(milli)) return 0; if (!m_data) - m_data = exec->globalData().dateInstanceCache.add(milli); + m_data = exec->vm().dateInstanceCache.add(milli); if (m_data->m_gregorianDateTimeCachedForMS != milli) { msToGregorianDateTime(exec, milli, false, m_data->m_cachedGregorianDateTime); @@ -77,11 +77,11 @@ const GregorianDateTime* DateInstance::calculateGregorianDateTime(ExecState* exe const GregorianDateTime* DateInstance::calculateGregorianDateTimeUTC(ExecState* exec) const { double milli = internalNumber(); - if (isnan(milli)) + if (std::isnan(milli)) return 0; if (!m_data) - m_data = exec->globalData().dateInstanceCache.add(milli); + m_data = exec->vm().dateInstanceCache.add(milli); if (m_data->m_gregorianDateTimeUTCCachedForMS != milli) { msToGregorianDateTime(exec, milli, true, m_data->m_cachedGregorianDateTimeUTC); diff --git a/Source/JavaScriptCore/runtime/DateInstance.h b/Source/JavaScriptCore/runtime/DateInstance.h index 9742e6889..870777240 100644 --- a/Source/JavaScriptCore/runtime/DateInstance.h +++ b/Source/JavaScriptCore/runtime/DateInstance.h @@ -28,8 +28,8 @@ namespace JSC { class DateInstance : public JSWrapperObject { protected: JS_EXPORT_PRIVATE DateInstance(ExecState*, Structure*); - void finishCreation(JSGlobalData&); - JS_EXPORT_PRIVATE void finishCreation(JSGlobalData&, double); + void finishCreation(VM&); + JS_EXPORT_PRIVATE void finishCreation(VM&, double); static void destroy(JSCell*); @@ -39,14 +39,14 @@ namespace JSC { static DateInstance* create(ExecState* exec, Structure* structure, double date) { DateInstance* instance = new (NotNull, allocateCell<DateInstance>(*exec->heap())) DateInstance(exec, structure); - instance->finishCreation(exec->globalData(), date); + instance->finishCreation(exec->vm(), date); return instance; } static DateInstance* create(ExecState* exec, Structure* structure) { DateInstance* instance = new (NotNull, allocateCell<DateInstance>(*exec->heap())) DateInstance(exec, structure); - instance->finishCreation(exec->globalData()); + instance->finishCreation(exec->vm()); return instance; } @@ -68,9 +68,9 @@ namespace JSC { return calculateGregorianDateTimeUTC(exec); } - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } private: diff --git a/Source/JavaScriptCore/runtime/DatePrototype.cpp b/Source/JavaScriptCore/runtime/DatePrototype.cpp index 75da466fb..9cbaf7480 100644 --- a/Source/JavaScriptCore/runtime/DatePrototype.cpp +++ b/Source/JavaScriptCore/runtime/DatePrototype.cpp @@ -33,6 +33,7 @@ #include "JSStringBuilder.h" #include "Lookup.h" #include "ObjectPrototype.h" +#include "Operations.h" #if !PLATFORM(MAC) && HAVE(LANGINFO_H) #include <langinfo.h> @@ -46,7 +47,6 @@ #include <wtf/Assertions.h> #include <wtf/MathExtras.h> #include <wtf/StringExtras.h> -#include <wtf/UnusedParam.h> #if HAVE(SYS_PARAM_H) #include <sys/param.h> @@ -60,7 +60,7 @@ #include <sys/timeb.h> #endif -#if PLATFORM(MAC) || PLATFORM(IOS) || (PLATFORM(WX) && OS(DARWIN)) || (PLATFORM(QT) && OS(DARWIN)) +#if OS(DARWIN) && USE(CF) #include <CoreFoundation/CoreFoundation.h> #elif USE(ICU_UNICODE) #include <unicode/udat.h> @@ -124,9 +124,9 @@ namespace JSC { enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime }; -#if PLATFORM(MAC) || PLATFORM(IOS) || (PLATFORM(WX) && OS(DARWIN)) || (PLATFORM(QT) && OS(DARWIN)) +#if OS(DARWIN) && USE(CF) -// FIXME: Since this is superior to the strftime-based version, why limit this to PLATFORM(MAC)? +// FIXME: Since this is superior to the strftime-based version, why limit this to OS(DARWIN)? // Instead we should consider using this whenever USE(CF) is true. static CFDateFormatterStyle styleFromArgString(const String& string, CFDateFormatterStyle defaultStyle) @@ -245,7 +245,7 @@ static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, L length += GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, buffer.data() + length, buffer.size() - length); } } else - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); // Remove terminating null character. if (length) @@ -336,7 +336,7 @@ static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, doubl return formatLocaleDate(exec, *gregorianDateTime, format); } -#endif // !PLATFORM(MAC) && !PLATFORM(IOS) +#endif // OS(DARWIN) && USE(CF) static EncodedJSValue formateDateInstance(ExecState* exec, DateTimeFormat format, bool asUTCVariant) { @@ -374,7 +374,7 @@ static bool fillStructuresUsingTimeArgs(ExecState* exec, int maxArgs, double* ms if (maxArgs >= 4 && idx < numArgs) { t->setHour(0); double hours = exec->argument(idx++).toIntegerPreserveNaN(exec); - ok = isfinite(hours); + ok = std::isfinite(hours); milliseconds += hours * msPerHour; } @@ -382,7 +382,7 @@ static bool fillStructuresUsingTimeArgs(ExecState* exec, int maxArgs, double* ms if (maxArgs >= 3 && idx < numArgs && ok) { t->setMinute(0); double minutes = exec->argument(idx++).toIntegerPreserveNaN(exec); - ok = isfinite(minutes); + ok = std::isfinite(minutes); milliseconds += minutes * msPerMinute; } @@ -390,7 +390,7 @@ static bool fillStructuresUsingTimeArgs(ExecState* exec, int maxArgs, double* ms if (maxArgs >= 2 && idx < numArgs && ok) { t->setSecond(0); double seconds = exec->argument(idx++).toIntegerPreserveNaN(exec); - ok = isfinite(seconds); + ok = std::isfinite(seconds); milliseconds += seconds * msPerSecond; } @@ -400,7 +400,7 @@ static bool fillStructuresUsingTimeArgs(ExecState* exec, int maxArgs, double* ms // milliseconds if (idx < numArgs) { double millis = exec->argument(idx).toIntegerPreserveNaN(exec); - ok = isfinite(millis); + ok = std::isfinite(millis); milliseconds += millis; } else milliseconds += *ms; @@ -426,19 +426,19 @@ static bool fillStructuresUsingDateArgs(ExecState *exec, int maxArgs, double *ms // years if (maxArgs >= 3 && idx < numArgs) { double years = exec->argument(idx++).toIntegerPreserveNaN(exec); - ok = isfinite(years); + ok = std::isfinite(years); t->setYear(toInt32(years)); } // months if (maxArgs >= 2 && idx < numArgs && ok) { double months = exec->argument(idx++).toIntegerPreserveNaN(exec); - ok = isfinite(months); + ok = std::isfinite(months); t->setMonth(toInt32(months)); } // days if (idx < numArgs && ok) { double days = exec->argument(idx++).toIntegerPreserveNaN(exec); - ok = isfinite(days); + ok = std::isfinite(days); t->setMonthDay(0); *ms += days * msPerDay; } @@ -508,7 +508,7 @@ DatePrototype::DatePrototype(ExecState* exec, Structure* structure) void DatePrototype::finishCreation(ExecState* exec, JSGlobalObject*) { - Base::finishCreation(exec->globalData()); + Base::finishCreation(exec->vm()); ASSERT(inherits(&s_info)); // The constructor will be added later, after DateConstructor has been built. @@ -545,7 +545,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); - if (!isfinite(thisDateObj->internalNumber())) + if (!std::isfinite(thisDateObj->internalNumber())) return throwVMError(exec, createRangeError(exec, ASCIILiteral("Invalid Date"))); const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); @@ -833,7 +833,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec) DateInstance* thisDateObj = asDateInstance(thisValue); double milli = thisDateObj->internalNumber(); - if (isnan(milli)) + if (std::isnan(milli)) return JSValue::encode(jsNaN()); double secs = floor(milli / msPerSecond); @@ -849,7 +849,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec) DateInstance* thisDateObj = asDateInstance(thisValue); double milli = thisDateObj->internalNumber(); - if (isnan(milli)) + if (std::isnan(milli)) return JSValue::encode(jsNaN()); double secs = floor(milli / msPerSecond); @@ -881,7 +881,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec) double milli = timeClip(exec->argument(0).toNumber(exec)); JSValue result = jsNumber(milli); - thisDateObj->setInternalValue(exec->globalData(), result); + thisDateObj->setInternalValue(exec->vm(), result); return JSValue::encode(result); } @@ -894,9 +894,9 @@ static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, DateInstance* thisDateObj = asDateInstance(thisValue); double milli = thisDateObj->internalNumber(); - if (!exec->argumentCount() || isnan(milli)) { + if (!exec->argumentCount() || std::isnan(milli)) { JSValue result = jsNaN(); - thisDateObj->setInternalValue(exec->globalData(), result); + thisDateObj->setInternalValue(exec->vm(), result); return JSValue::encode(result); } @@ -913,12 +913,12 @@ static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, gregorianDateTime.copyFrom(*other); if (!fillStructuresUsingTimeArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) { JSValue result = jsNaN(); - thisDateObj->setInternalValue(exec->globalData(), result); + thisDateObj->setInternalValue(exec->vm(), result); return JSValue::encode(result); } JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC)); - thisDateObj->setInternalValue(exec->globalData(), result); + thisDateObj->setInternalValue(exec->vm(), result); return JSValue::encode(result); } @@ -931,7 +931,7 @@ static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, DateInstance* thisDateObj = asDateInstance(thisValue); if (!exec->argumentCount()) { JSValue result = jsNaN(); - thisDateObj->setInternalValue(exec->globalData(), result); + thisDateObj->setInternalValue(exec->vm(), result); return JSValue::encode(result); } @@ -939,7 +939,7 @@ static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, double ms = 0; GregorianDateTime gregorianDateTime; - if (numArgsToUse == 3 && isnan(milli)) + if (numArgsToUse == 3 && std::isnan(milli)) msToGregorianDateTime(exec, 0, true, gregorianDateTime); else { ms = milli - floor(milli / msPerSecond) * msPerSecond; @@ -953,12 +953,12 @@ static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, if (!fillStructuresUsingDateArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) { JSValue result = jsNaN(); - thisDateObj->setInternalValue(exec->globalData(), result); + thisDateObj->setInternalValue(exec->vm(), result); return JSValue::encode(result); } JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC)); - thisDateObj->setInternalValue(exec->globalData(), result); + thisDateObj->setInternalValue(exec->vm(), result); return JSValue::encode(result); } @@ -1055,7 +1055,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec) DateInstance* thisDateObj = asDateInstance(thisValue); if (!exec->argumentCount()) { JSValue result = jsNaN(); - thisDateObj->setInternalValue(exec->globalData(), result); + thisDateObj->setInternalValue(exec->vm(), result); return JSValue::encode(result); } @@ -1063,7 +1063,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec) double ms = 0; GregorianDateTime gregorianDateTime; - if (isnan(milli)) + if (std::isnan(milli)) // Based on ECMA 262 B.2.5 (setYear) // the time must be reset to +0 if it is NaN. msToGregorianDateTime(exec, 0, true, gregorianDateTime); @@ -1075,15 +1075,15 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec) } double year = exec->argument(0).toIntegerPreserveNaN(exec); - if (!isfinite(year)) { + if (!std::isfinite(year)) { JSValue result = jsNaN(); - thisDateObj->setInternalValue(exec->globalData(), result); + thisDateObj->setInternalValue(exec->vm(), result); return JSValue::encode(result); } gregorianDateTime.setYear(toInt32((year >= 0 && year <= 99) ? (year + 1900) : year)); JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, false)); - thisDateObj->setInternalValue(exec->globalData(), result); + thisDateObj->setInternalValue(exec->vm(), result); return JSValue::encode(result); } @@ -1110,7 +1110,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec) if (exec->hadException()) return JSValue::encode(jsNull()); - JSValue toISOValue = object->get(exec, exec->globalData().propertyNames->toISOString); + JSValue toISOValue = object->get(exec, exec->vm().propertyNames->toISOString); if (exec->hadException()) return JSValue::encode(jsNull()); diff --git a/Source/JavaScriptCore/runtime/DatePrototype.h b/Source/JavaScriptCore/runtime/DatePrototype.h index c4f6d6916..85f7d46d7 100644 --- a/Source/JavaScriptCore/runtime/DatePrototype.h +++ b/Source/JavaScriptCore/runtime/DatePrototype.h @@ -46,9 +46,9 @@ namespace JSC { static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } protected: diff --git a/Source/JavaScriptCore/runtime/Error.cpp b/Source/JavaScriptCore/runtime/Error.cpp index 68ae12d90..9cbe20b97 100644 --- a/Source/JavaScriptCore/runtime/Error.cpp +++ b/Source/JavaScriptCore/runtime/Error.cpp @@ -34,6 +34,7 @@ #include "JSObject.h" #include "JSString.h" #include "NativeErrorConstructor.h" +#include "Operations.h" #include "SourceCode.h" #include <wtf/text/StringBuilder.h> @@ -46,37 +47,37 @@ static const char* sourceURLPropertyName = "sourceURL"; JSObject* createError(JSGlobalObject* globalObject, const String& message) { ASSERT(!message.isEmpty()); - return ErrorInstance::create(globalObject->globalData(), globalObject->errorStructure(), message); + return ErrorInstance::create(globalObject->vm(), globalObject->errorStructure(), message); } JSObject* createEvalError(JSGlobalObject* globalObject, const String& message) { ASSERT(!message.isEmpty()); - return ErrorInstance::create(globalObject->globalData(), globalObject->evalErrorConstructor()->errorStructure(), message); + return ErrorInstance::create(globalObject->vm(), globalObject->evalErrorConstructor()->errorStructure(), message); } JSObject* createRangeError(JSGlobalObject* globalObject, const String& message) { ASSERT(!message.isEmpty()); - return ErrorInstance::create(globalObject->globalData(), globalObject->rangeErrorConstructor()->errorStructure(), message); + return ErrorInstance::create(globalObject->vm(), globalObject->rangeErrorConstructor()->errorStructure(), message); } JSObject* createReferenceError(JSGlobalObject* globalObject, const String& message) { ASSERT(!message.isEmpty()); - return ErrorInstance::create(globalObject->globalData(), globalObject->referenceErrorConstructor()->errorStructure(), message); + return ErrorInstance::create(globalObject->vm(), globalObject->referenceErrorConstructor()->errorStructure(), message); } JSObject* createSyntaxError(JSGlobalObject* globalObject, const String& message) { ASSERT(!message.isEmpty()); - return ErrorInstance::create(globalObject->globalData(), globalObject->syntaxErrorConstructor()->errorStructure(), message); + return ErrorInstance::create(globalObject->vm(), globalObject->syntaxErrorConstructor()->errorStructure(), message); } JSObject* createTypeError(JSGlobalObject* globalObject, const String& message) { ASSERT(!message.isEmpty()); - return ErrorInstance::create(globalObject->globalData(), globalObject->typeErrorConstructor()->errorStructure(), message); + return ErrorInstance::create(globalObject->vm(), globalObject->typeErrorConstructor()->errorStructure(), message); } JSObject* createNotEnoughArgumentsError(JSGlobalObject* globalObject) @@ -87,7 +88,7 @@ JSObject* createNotEnoughArgumentsError(JSGlobalObject* globalObject) JSObject* createURIError(JSGlobalObject* globalObject, const String& message) { ASSERT(!message.isEmpty()); - return ErrorInstance::create(globalObject->globalData(), globalObject->URIErrorConstructor()->errorStructure(), message); + return ErrorInstance::create(globalObject->vm(), globalObject->URIErrorConstructor()->errorStructure(), message); } JSObject* createError(ExecState* exec, const String& message) @@ -132,15 +133,15 @@ JSObject* createURIError(ExecState* exec, const String& message) JSObject* addErrorInfo(CallFrame* callFrame, JSObject* error, int line, const SourceCode& source) { - JSGlobalData* globalData = &callFrame->globalData(); + VM* vm = &callFrame->vm(); const String& sourceURL = source.provider()->url(); if (line != -1) - error->putDirect(*globalData, Identifier(globalData, linePropertyName), jsNumber(line), ReadOnly | DontDelete); + error->putDirect(*vm, Identifier(vm, linePropertyName), jsNumber(line), ReadOnly | DontDelete); if (!sourceURL.isNull()) - error->putDirect(*globalData, Identifier(globalData, sourceURLPropertyName), jsString(globalData, sourceURL), ReadOnly | DontDelete); + error->putDirect(*vm, Identifier(vm, sourceURLPropertyName), jsString(vm, sourceURL), ReadOnly | DontDelete); - globalData->interpreter->addStackTraceIfNecessary(callFrame, error); + vm->interpreter->addStackTraceIfNecessary(callFrame, error); return error; } @@ -154,16 +155,15 @@ bool hasErrorInfo(ExecState* exec, JSObject* error) JSValue throwError(ExecState* exec, JSValue error) { - if (error.isObject()) - return throwError(exec, asObject(error)); - exec->globalData().exception = error; + Interpreter::addStackTraceIfNecessary(exec, error); + exec->vm().exception = error; return error; } JSObject* throwError(ExecState* exec, JSObject* error) { Interpreter::addStackTraceIfNecessary(exec, error); - exec->globalData().exception = error; + exec->vm().exception = error; return error; } diff --git a/Source/JavaScriptCore/runtime/Error.h b/Source/JavaScriptCore/runtime/Error.h index 9c34a0574..36e425d7e 100644 --- a/Source/JavaScriptCore/runtime/Error.h +++ b/Source/JavaScriptCore/runtime/Error.h @@ -31,7 +31,7 @@ namespace JSC { class ExecState; - class JSGlobalData; + class VM; class JSGlobalObject; class JSObject; class SourceCode; @@ -89,7 +89,7 @@ namespace JSC { static StrictModeTypeErrorFunction* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, const String& message) { StrictModeTypeErrorFunction* function = new (NotNull, allocateCell<StrictModeTypeErrorFunction>(*exec->heap())) StrictModeTypeErrorFunction(globalObject, structure, message); - function->finishCreation(exec->globalData(), String()); + function->finishCreation(exec->vm(), String()); return function; } @@ -119,9 +119,9 @@ namespace JSC { static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } private: diff --git a/Source/JavaScriptCore/runtime/ErrorConstructor.cpp b/Source/JavaScriptCore/runtime/ErrorConstructor.cpp index f2578a497..b143f5a18 100644 --- a/Source/JavaScriptCore/runtime/ErrorConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ErrorConstructor.cpp @@ -24,6 +24,7 @@ #include "ErrorPrototype.h" #include "JSGlobalObject.h" #include "JSString.h" +#include "Operations.h" namespace JSC { @@ -38,10 +39,10 @@ ErrorConstructor::ErrorConstructor(JSGlobalObject* globalObject, Structure* stru void ErrorConstructor::finishCreation(ExecState* exec, ErrorPrototype* errorPrototype) { - Base::finishCreation(exec->globalData(), errorPrototype->classInfo()->className); + Base::finishCreation(exec->vm(), errorPrototype->classInfo()->className); // ECMA 15.11.3.1 Error.prototype - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, errorPrototype, DontEnum | DontDelete | ReadOnly); - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), DontDelete | ReadOnly | DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().prototype, errorPrototype, DontEnum | DontDelete | ReadOnly); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().length, jsNumber(1), DontDelete | ReadOnly | DontEnum); } // ECMA 15.9.3 diff --git a/Source/JavaScriptCore/runtime/ErrorConstructor.h b/Source/JavaScriptCore/runtime/ErrorConstructor.h index 58399a9bc..b8e3b841b 100644 --- a/Source/JavaScriptCore/runtime/ErrorConstructor.h +++ b/Source/JavaScriptCore/runtime/ErrorConstructor.h @@ -41,9 +41,9 @@ namespace JSC { static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } protected: diff --git a/Source/JavaScriptCore/runtime/ErrorInstance.cpp b/Source/JavaScriptCore/runtime/ErrorInstance.cpp index 9c0fe3e8b..e8f7ac162 100644 --- a/Source/JavaScriptCore/runtime/ErrorInstance.cpp +++ b/Source/JavaScriptCore/runtime/ErrorInstance.cpp @@ -22,6 +22,7 @@ #include "ErrorInstance.h" #include "JSScope.h" +#include "Operations.h" namespace JSC { @@ -29,8 +30,8 @@ ASSERT_HAS_TRIVIAL_DESTRUCTOR(ErrorInstance); const ClassInfo ErrorInstance::s_info = { "Error", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(ErrorInstance) }; -ErrorInstance::ErrorInstance(JSGlobalData& globalData, Structure* structure) - : JSNonFinalObject(globalData, structure) +ErrorInstance::ErrorInstance(VM& vm, Structure* structure) + : JSNonFinalObject(vm, structure) , m_appendSourceToMessage(false) { } diff --git a/Source/JavaScriptCore/runtime/ErrorInstance.h b/Source/JavaScriptCore/runtime/ErrorInstance.h index 894676361..26a8b31ea 100644 --- a/Source/JavaScriptCore/runtime/ErrorInstance.h +++ b/Source/JavaScriptCore/runtime/ErrorInstance.h @@ -31,21 +31,21 @@ namespace JSC { static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ErrorInstanceType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ErrorInstanceType, StructureFlags), &s_info); } - static ErrorInstance* create(JSGlobalData& globalData, Structure* structure, const String& message) + static ErrorInstance* create(VM& vm, Structure* structure, const String& message) { - ErrorInstance* instance = new (NotNull, allocateCell<ErrorInstance>(globalData.heap)) ErrorInstance(globalData, structure); - instance->finishCreation(globalData, message); + ErrorInstance* instance = new (NotNull, allocateCell<ErrorInstance>(vm.heap)) ErrorInstance(vm, structure); + instance->finishCreation(vm, message); return instance; } static ErrorInstance* create(ExecState* exec, Structure* structure, JSValue message) { - return create(exec->globalData(), structure, message.isUndefined() ? String() : message.toString(exec)->value(exec)); + return create(exec->vm(), structure, message.isUndefined() ? String() : message.toString(exec)->value(exec)); } bool appendSourceToMessage() { return m_appendSourceToMessage; } @@ -53,14 +53,14 @@ namespace JSC { void clearAppendSourceToMessage() { m_appendSourceToMessage = false; } protected: - explicit ErrorInstance(JSGlobalData&, Structure*); + explicit ErrorInstance(VM&, Structure*); - void finishCreation(JSGlobalData& globalData, const String& message) + void finishCreation(VM& vm, const String& message) { - Base::finishCreation(globalData); + Base::finishCreation(vm); ASSERT(inherits(&s_info)); if (!message.isNull()) - putDirect(globalData, globalData.propertyNames->message, jsString(&globalData, message), DontEnum); + putDirect(vm, vm.propertyNames->message, jsString(&vm, message), DontEnum); } bool m_appendSourceToMessage; diff --git a/Source/JavaScriptCore/runtime/ErrorPrototype.cpp b/Source/JavaScriptCore/runtime/ErrorPrototype.cpp index a30efdc31..bab3a7440 100644 --- a/Source/JavaScriptCore/runtime/ErrorPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ErrorPrototype.cpp @@ -26,6 +26,7 @@ #include "JSString.h" #include "JSStringBuilder.h" #include "ObjectPrototype.h" +#include "Operations.h" #include "StringRecursionChecker.h" namespace JSC { @@ -49,15 +50,15 @@ const ClassInfo ErrorPrototype::s_info = { "Error", &ErrorInstance::s_info, 0, E */ ErrorPrototype::ErrorPrototype(ExecState* exec, Structure* structure) - : ErrorInstance(exec->globalData(), structure) + : ErrorInstance(exec->vm(), structure) { } void ErrorPrototype::finishCreation(ExecState* exec, JSGlobalObject*) { - Base::finishCreation(exec->globalData(), ""); + Base::finishCreation(exec->vm(), ""); ASSERT(inherits(&s_info)); - putDirect(exec->globalData(), exec->propertyNames().name, jsNontrivialString(exec, String(ASCIILiteral("Error"))), DontEnum); + putDirect(exec->vm(), exec->propertyNames().name, jsNontrivialString(exec, String(ASCIILiteral("Error"))), DontEnum); } bool ErrorPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot &slot) diff --git a/Source/JavaScriptCore/runtime/ErrorPrototype.h b/Source/JavaScriptCore/runtime/ErrorPrototype.h index e961946df..9401b2220 100644 --- a/Source/JavaScriptCore/runtime/ErrorPrototype.h +++ b/Source/JavaScriptCore/runtime/ErrorPrototype.h @@ -40,9 +40,9 @@ namespace JSC { static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ErrorInstanceType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ErrorInstanceType, StructureFlags), &s_info); } protected: diff --git a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp index a4368a2bb..ccd7a02cb 100644 --- a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp +++ b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp @@ -37,36 +37,10 @@ #include "JSNotAnObject.h" #include "Interpreter.h" #include "Nodes.h" +#include "Operations.h" namespace JSC { -ASSERT_HAS_TRIVIAL_DESTRUCTOR(InterruptedExecutionError); - -const ClassInfo InterruptedExecutionError::s_info = { "InterruptedExecutionError", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(InterruptedExecutionError) }; - -JSValue InterruptedExecutionError::defaultValue(const JSObject*, ExecState* exec, PreferredPrimitiveType hint) -{ - if (hint == PreferString) - return jsNontrivialString(exec, String(ASCIILiteral("JavaScript execution exceeded timeout."))); - return JSValue(QNaN); -} - -JSObject* createInterruptedExecutionException(JSGlobalData* globalData) -{ - return InterruptedExecutionError::create(*globalData); -} - -bool isInterruptedExecutionException(JSObject* object) -{ - return object->inherits(&InterruptedExecutionError::s_info); -} - -bool isInterruptedExecutionException(JSValue value) -{ - return value.inherits(&InterruptedExecutionError::s_info); -} - - ASSERT_HAS_TRIVIAL_DESTRUCTOR(TerminatedExecutionError); const ClassInfo TerminatedExecutionError::s_info = { "TerminatedExecutionError", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(TerminatedExecutionError) }; @@ -78,9 +52,9 @@ JSValue TerminatedExecutionError::defaultValue(const JSObject*, ExecState* exec, return JSValue(QNaN); } -JSObject* createTerminatedExecutionException(JSGlobalData* globalData) +JSObject* createTerminatedExecutionException(VM* vm) { - return TerminatedExecutionError::create(*globalData); + return TerminatedExecutionError::create(*vm); } bool isTerminatedExecutionException(JSObject* object) @@ -110,40 +84,59 @@ JSObject* createUndefinedVariableError(ExecState* exec, const Identifier& ident) return createReferenceError(exec, message); } -JSObject* createInvalidParamError(ExecState* exec, const char* op, JSValue value) +JSString* errorDescriptionForValue(ExecState* exec, JSValue v) +{ + VM& vm = exec->vm(); + if (v.isNull()) + return vm.smallStrings.nullString(); + if (v.isUndefined()) + return vm.smallStrings.undefinedString(); + if (v.isInt32()) + return jsString(&vm, vm.numericStrings.add(v.asInt32())); + if (v.isDouble()) + return jsString(&vm, vm.numericStrings.add(v.asDouble())); + if (v.isTrue()) + return vm.smallStrings.trueString(); + if (v.isFalse()) + return vm.smallStrings.falseString(); + if (v.isString()) + return jsCast<JSString*>(v.asCell()); + if (v.isObject()) { + CallData callData; + JSObject* object = asObject(v); + if (object->methodTable()->getCallData(object, callData) != CallTypeNone) + return vm.smallStrings.functionString(); + } + return jsString(exec, asObject(v)->methodTable()->className(asObject(v))); +} + +JSObject* createError(ExecState* exec, ErrorFactory errorFactory, JSValue value, const String& message) { - String errorMessage = makeString("'", value.toString(exec)->value(exec), "' is not a valid argument for '", op, "'"); - JSObject* exception = createTypeError(exec, errorMessage); + String errorMessage = makeString(errorDescriptionForValue(exec, value)->value(exec), " ", message); + JSObject* exception = errorFactory(exec, errorMessage); ASSERT(exception->isErrorInstance()); static_cast<ErrorInstance*>(exception)->setAppendSourceToMessage(); return exception; } +JSObject* createInvalidParameterError(ExecState* exec, const char* op, JSValue value) +{ + return createError(exec, createTypeError, value, makeString("is not a valid argument for '", op, "'")); +} + JSObject* createNotAConstructorError(ExecState* exec, JSValue value) { - String errorMessage = makeString("'", value.toString(exec)->value(exec), "' is not a constructor"); - JSObject* exception = createTypeError(exec, errorMessage); - ASSERT(exception->isErrorInstance()); - static_cast<ErrorInstance*>(exception)->setAppendSourceToMessage(); - return exception; + return createError(exec, createTypeError, value, "is not a constructor"); } JSObject* createNotAFunctionError(ExecState* exec, JSValue value) { - String errorMessage = makeString("'", value.toString(exec)->value(exec), "' is not a function"); - JSObject* exception = createTypeError(exec, errorMessage); - ASSERT(exception->isErrorInstance()); - static_cast<ErrorInstance*>(exception)->setAppendSourceToMessage(); - return exception; + return createError(exec, createTypeError, value, "is not a function"); } JSObject* createNotAnObjectError(ExecState* exec, JSValue value) { - String errorMessage = makeString("'", value.toString(exec)->value(exec), "' is not an object"); - JSObject* exception = createTypeError(exec, errorMessage); - ASSERT(exception->isErrorInstance()); - static_cast<ErrorInstance*>(exception)->setAppendSourceToMessage(); - return exception; + return createError(exec, createTypeError, value, "is not an object"); } JSObject* createErrorForInvalidGlobalAssignment(ExecState* exec, const String& propertyName) @@ -167,4 +160,10 @@ JSObject* throwStackOverflowError(ExecState* exec) return throwError(exec, createStackOverflowError(exec)); } +JSObject* throwTerminatedExecutionException(ExecState* exec) +{ + Interpreter::ErrorHandlingMode mode(exec); + return throwError(exec, createTerminatedExecutionException(&exec->vm())); +} + } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ExceptionHelpers.h b/Source/JavaScriptCore/runtime/ExceptionHelpers.h index d2daaa044..bfe1d66af 100644 --- a/Source/JavaScriptCore/runtime/ExceptionHelpers.h +++ b/Source/JavaScriptCore/runtime/ExceptionHelpers.h @@ -33,59 +33,32 @@ namespace JSC { -JS_EXPORT_PRIVATE JSObject* createInterruptedExecutionException(JSGlobalData*); -bool isInterruptedExecutionException(JSObject*); -bool isInterruptedExecutionException(JSValue); +typedef JSObject* (*ErrorFactory)(ExecState*, const String&); -JSObject* createTerminatedExecutionException(JSGlobalData*); +JSObject* createTerminatedExecutionException(VM*); bool isTerminatedExecutionException(JSObject*); JS_EXPORT_PRIVATE bool isTerminatedExecutionException(JSValue); - +JS_EXPORT_PRIVATE JSObject* createError(ExecState*, ErrorFactory, JSValue, const String&); JS_EXPORT_PRIVATE JSObject* createStackOverflowError(ExecState*); JSObject* createStackOverflowError(JSGlobalObject*); JSObject* createOutOfMemoryError(JSGlobalObject*); JSObject* createUndefinedVariableError(ExecState*, const Identifier&); JSObject* createNotAnObjectError(ExecState*, JSValue); -JSObject* createInvalidParamError(ExecState*, const char* op, JSValue); +JSObject* createInvalidParameterError(ExecState*, const char* op, JSValue); JSObject* createNotAConstructorError(ExecState*, JSValue); JSObject* createNotAFunctionError(ExecState*, JSValue); JSObject* createErrorForInvalidGlobalAssignment(ExecState*, const String&); +JSString* errorDescriptionForValue(ExecState*, JSValue); JSObject* throwOutOfMemoryError(ExecState*); JSObject* throwStackOverflowError(ExecState*); +JSObject* throwTerminatedExecutionException(ExecState*); -class InterruptedExecutionError : public JSNonFinalObject { -private: - InterruptedExecutionError(JSGlobalData& globalData) - : JSNonFinalObject(globalData, globalData.interruptedExecutionErrorStructure.get()) - { - } - - static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType); - -public: - typedef JSNonFinalObject Base; - - static InterruptedExecutionError* create(JSGlobalData& globalData) - { - InterruptedExecutionError* error = new (NotNull, allocateCell<InterruptedExecutionError>(globalData.heap)) InterruptedExecutionError(globalData); - error->finishCreation(globalData); - return error; - } - - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); - } - - static const ClassInfo s_info; -}; - class TerminatedExecutionError : public JSNonFinalObject { private: - TerminatedExecutionError(JSGlobalData& globalData) - : JSNonFinalObject(globalData, globalData.terminatedExecutionErrorStructure.get()) + TerminatedExecutionError(VM& vm) + : JSNonFinalObject(vm, vm.terminatedExecutionErrorStructure.get()) { } @@ -94,16 +67,16 @@ private: public: typedef JSNonFinalObject Base; - static TerminatedExecutionError* create(JSGlobalData& globalData) + static TerminatedExecutionError* create(VM& vm) { - TerminatedExecutionError* error = new (NotNull, allocateCell<TerminatedExecutionError>(globalData.heap)) TerminatedExecutionError(globalData); - error->finishCreation(globalData); + TerminatedExecutionError* error = new (NotNull, allocateCell<TerminatedExecutionError>(vm.heap)) TerminatedExecutionError(vm); + error->finishCreation(vm); return error; } - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } static JS_EXPORTDATA const ClassInfo s_info; diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp index ff4c2ff76..918537650 100644 --- a/Source/JavaScriptCore/runtime/Executable.cpp +++ b/Source/JavaScriptCore/runtime/Executable.cpp @@ -33,6 +33,7 @@ #include "ExecutionHarness.h" #include "JIT.h" #include "JITDriver.h" +#include "Operations.h" #include "Parser.h" #include <wtf/Vector.h> #include <wtf/text/StringBuilder.h> @@ -67,6 +68,11 @@ Intrinsic ExecutableBase::intrinsic() const return nativeExecutable->intrinsic(); return NoIntrinsic; } +#else +Intrinsic ExecutableBase::intrinsic() const +{ + return NoIntrinsic; +} #endif const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(NativeExecutable) }; @@ -88,14 +94,14 @@ Intrinsic NativeExecutable::intrinsic() const #if ENABLE(JIT) // Utility method used for jettisoning code blocks. template<typename T> -static void jettisonCodeBlock(JSGlobalData& globalData, OwnPtr<T>& codeBlock) +static void jettisonCodeBlock(VM& vm, OwnPtr<T>& codeBlock) { ASSERT(JITCode::isOptimizingJIT(codeBlock->getJITType())); ASSERT(codeBlock->alternative()); OwnPtr<T> codeBlockToJettison = codeBlock.release(); codeBlock = static_pointer_cast<T>(codeBlockToJettison->releaseAlternative()); codeBlockToJettison->unlinkIncomingCalls(); - globalData.heap.jettisonDFGCodeBlock(static_pointer_cast<CodeBlock>(codeBlockToJettison.release())); + vm.heap.jettisonDFGCodeBlock(static_pointer_cast<CodeBlock>(codeBlockToJettison.release())); } #endif @@ -110,8 +116,9 @@ void ScriptExecutable::destroy(JSCell* cell) const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(EvalExecutable) }; -EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext) - : ScriptExecutable(exec->globalData().evalExecutableStructure.get(), exec, source, inStrictContext) +EvalExecutable::EvalExecutable(ExecState* exec, PassRefPtr<CodeCache> codeCache, const SourceCode& source, bool inStrictContext) + : ScriptExecutable(exec->vm().evalExecutableStructure.get(), exec, source, inStrictContext) + , m_codeCache(codeCache) { } @@ -123,7 +130,7 @@ void EvalExecutable::destroy(JSCell* cell) const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(ProgramExecutable) }; ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source) - : ScriptExecutable(exec->globalData().programExecutableStructure.get(), exec, source, false) + : ScriptExecutable(exec->vm().programExecutableStructure.get(), exec, source, false) { } @@ -134,14 +141,15 @@ void ProgramExecutable::destroy(JSCell* cell) const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionExecutable) }; -FunctionExecutable::FunctionExecutable(JSGlobalData& globalData, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine) - : ScriptExecutable(globalData.functionExecutableStructure.get(), globalData, source, unlinkedExecutable->isInStrictContext()) - , m_unlinkedExecutable(globalData, this, unlinkedExecutable) +FunctionExecutable::FunctionExecutable(VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine, unsigned startColumn) + : ScriptExecutable(vm.functionExecutableStructure.get(), vm, source, unlinkedExecutable->isInStrictContext()) + , m_unlinkedExecutable(vm, this, unlinkedExecutable) { - ASSERT(!source.isNull()); + RELEASE_ASSERT(!source.isNull()); ASSERT(source.length()); m_firstLine = firstLine; m_lastLine = lastLine; + m_startColumn = startColumn; } void FunctionExecutable::destroy(JSCell* cell) @@ -151,7 +159,7 @@ void FunctionExecutable::destroy(JSCell* cell) JSObject* EvalExecutable::compileOptimized(ExecState* exec, JSScope* scope, unsigned bytecodeIndex) { - ASSERT(exec->globalData().dynamicGlobalObject); + ASSERT(exec->vm().dynamicGlobalObject); ASSERT(!!m_evalCodeBlock); JSObject* error = 0; if (m_evalCodeBlock->getJITType() != JITCode::topTierJIT()) @@ -177,7 +185,7 @@ inline const char* samplingDescription(JITCode::JITType jitType) case JITCode::DFGJIT: return "DFG Compilation (TOTAL)"; default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return 0; } } @@ -190,7 +198,7 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, JSScope* scope, JITCo UNUSED_PARAM(jitType); UNUSED_PARAM(bytecodeIndex); #endif - JSGlobalData* globalData = &exec->globalData(); + VM* vm = &exec->vm(); JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); if (!!m_evalCodeBlock) { @@ -199,19 +207,19 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, JSScope* scope, JITCo m_evalCodeBlock = newCodeBlock.release(); } else { UNUSED_PARAM(scope); - UNUSED_PARAM(globalData); + UNUSED_PARAM(vm); UNUSED_PARAM(lexicalGlobalObject); if (!lexicalGlobalObject->evalEnabled()) return throwError(exec, createEvalError(exec, lexicalGlobalObject->evalDisabledErrorMessage())); JSObject* exception = 0; - UnlinkedEvalCodeBlock* unlinkedEvalCode = lexicalGlobalObject->createEvalCodeBlock(exec, this, &exception); + UnlinkedEvalCodeBlock* unlinkedEvalCode = lexicalGlobalObject->createEvalCodeBlock(m_codeCache.get(), exec, scope, this, &exception); if (!unlinkedEvalCode) return exception; OwnPtr<CodeBlock> previousCodeBlock = m_evalCodeBlock.release(); ASSERT((jitType == JITCode::bottomTierJIT()) == !previousCodeBlock); - m_unlinkedEvalCodeBlock.set(*globalData, this, unlinkedEvalCode); + m_unlinkedEvalCodeBlock.set(*vm, this, unlinkedEvalCode); m_evalCodeBlock = adoptPtr(new EvalCodeBlock(this, unlinkedEvalCode, lexicalGlobalObject, source().provider(), scope->localDepth(), previousCodeBlock.release())); m_evalCodeBlock->copyPostParseDataFromAlternative(); } @@ -231,9 +239,9 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, JSScope* scope, JITCo } #if ENABLE(JIT) -void EvalExecutable::jettisonOptimizedCode(JSGlobalData& globalData) +void EvalExecutable::jettisonOptimizedCode(VM& vm) { - jettisonCodeBlock(globalData, m_evalCodeBlock); + jettisonCodeBlock(vm, m_evalCodeBlock); m_jitCodeForCall = m_evalCodeBlock->getJITCode(); ASSERT(!m_jitCodeForCallWithArityCheck); } @@ -256,7 +264,7 @@ void EvalExecutable::unlinkCalls() #if ENABLE(JIT) if (!m_jitCodeForCall) return; - ASSERT(m_evalCodeBlock); + RELEASE_ASSERT(m_evalCodeBlock); m_evalCodeBlock->unlinkCalls(); #endif } @@ -271,9 +279,9 @@ void EvalExecutable::clearCode() JSObject* ProgramExecutable::checkSyntax(ExecState* exec) { ParserError error; - JSGlobalData* globalData = &exec->globalData(); + VM* vm = &exec->vm(); JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); - RefPtr<ProgramNode> programNode = parse<ProgramNode>(globalData, m_source, 0, Identifier(), JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, error); + RefPtr<ProgramNode> programNode = parse<ProgramNode>(vm, m_source, 0, Identifier(), JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, error); if (programNode) return 0; ASSERT(error.m_type != ParserError::ErrorNone); @@ -282,7 +290,7 @@ JSObject* ProgramExecutable::checkSyntax(ExecState* exec) JSObject* ProgramExecutable::compileOptimized(ExecState* exec, JSScope* scope, unsigned bytecodeIndex) { - ASSERT(exec->globalData().dynamicGlobalObject); + RELEASE_ASSERT(exec->vm().dynamicGlobalObject); ASSERT(!!m_programCodeBlock); JSObject* error = 0; if (m_programCodeBlock->getJITType() != JITCode::topTierJIT()) @@ -313,7 +321,7 @@ JSObject* ProgramExecutable::compileInternal(ExecState* exec, JSScope* scope, JI m_programCodeBlock = newCodeBlock.release(); } else { JSGlobalObject* globalObject = scope->globalObject(); - m_programCodeBlock = adoptPtr(new ProgramCodeBlock(this, m_unlinkedProgramCodeBlock.get(), globalObject, source().provider(), m_programCodeBlock.release())); + m_programCodeBlock = adoptPtr(new ProgramCodeBlock(this, m_unlinkedProgramCodeBlock.get(), globalObject, source().provider(), source().startColumn(), m_programCodeBlock.release())); m_programCodeBlock->copyPostParseDataFromAlternative(); } @@ -332,9 +340,9 @@ JSObject* ProgramExecutable::compileInternal(ExecState* exec, JSScope* scope, JI } #if ENABLE(JIT) -void ProgramExecutable::jettisonOptimizedCode(JSGlobalData& globalData) +void ProgramExecutable::jettisonOptimizedCode(VM& vm) { - jettisonCodeBlock(globalData, m_programCodeBlock); + jettisonCodeBlock(vm, m_programCodeBlock); m_jitCodeForCall = m_programCodeBlock->getJITCode(); ASSERT(!m_jitCodeForCallWithArityCheck); } @@ -345,7 +353,7 @@ void ProgramExecutable::unlinkCalls() #if ENABLE(JIT) if (!m_jitCodeForCall) return; - ASSERT(m_programCodeBlock); + RELEASE_ASSERT(m_programCodeBlock); m_programCodeBlock->unlinkCalls(); #endif } @@ -367,21 +375,21 @@ int ProgramExecutable::addGlobalVar(JSGlobalObject* globalObject, const Identifi return index; } -JSObject* ProgramExecutable::initalizeGlobalProperties(JSGlobalData& globalData, CallFrame* callFrame, JSScope* scope) +JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callFrame, JSScope* scope) { - ASSERT(scope); + RELEASE_ASSERT(scope); JSGlobalObject* globalObject = scope->globalObject(); - ASSERT(globalObject); - ASSERT(&globalObject->globalData() == &globalData); + RELEASE_ASSERT(globalObject); + ASSERT(&globalObject->vm() == &vm); JSObject* exception = 0; UnlinkedProgramCodeBlock* unlinkedCode = globalObject->createProgramCodeBlock(callFrame, this, &exception); if (exception) return exception; - m_unlinkedProgramCodeBlock.set(globalData, this, unlinkedCode); + m_unlinkedProgramCodeBlock.set(vm, this, unlinkedCode); - BatchedTransitionOptimizer optimizer(globalData, globalObject); + BatchedTransitionOptimizer optimizer(vm, globalObject); const UnlinkedProgramCodeBlock::VariableDeclations& variableDeclarations = unlinkedCode->variableDeclarations(); const UnlinkedProgramCodeBlock::FunctionDeclations& functionDeclarations = unlinkedCode->functionDeclarations(); @@ -393,12 +401,12 @@ JSObject* ProgramExecutable::initalizeGlobalProperties(JSGlobalData& globalData, CallFrame* globalExec = globalObject->globalExec(); for (size_t i = 0; i < functionDeclarations.size(); ++i) { - bool propertyDidExist = globalObject->removeDirect(globalData, functionDeclarations[i].first); // Newly declared functions overwrite existing properties. + bool propertyDidExist = globalObject->removeDirect(vm, functionDeclarations[i].first); // Newly declared functions overwrite existing properties. UnlinkedFunctionExecutable* unlinkedFunctionExecutable = functionDeclarations[i].second.get(); - JSValue value = JSFunction::create(globalExec, unlinkedFunctionExecutable->link(globalData, m_source, lineNo(), 0), scope); + JSValue value = JSFunction::create(globalExec, unlinkedFunctionExecutable->link(vm, m_source, lineNo(), 0), scope); int index = addGlobalVar(globalObject, functionDeclarations[i].first, IsVariable, !propertyDidExist ? IsFunctionToSpecialize : NotFunctionOrNotSpecializable); - globalObject->registerAt(index).set(globalData, globalObject, value); + globalObject->registerAt(index).set(vm, globalObject, value); } for (size_t i = 0; i < variableDeclarations.size(); ++i) { @@ -436,21 +444,21 @@ FunctionCodeBlock* FunctionExecutable::baselineCodeBlockFor(CodeSpecializationKi if (kind == CodeForCall) result = m_codeBlockForCall.get(); else { - ASSERT(kind == CodeForConstruct); + RELEASE_ASSERT(kind == CodeForConstruct); result = m_codeBlockForConstruct.get(); } if (!result) return 0; while (result->alternative()) result = static_cast<FunctionCodeBlock*>(result->alternative()); - ASSERT(result); + RELEASE_ASSERT(result); ASSERT(JITCode::isBaselineCode(result->getJITType())); return result; } JSObject* FunctionExecutable::compileOptimizedForCall(ExecState* exec, JSScope* scope, unsigned bytecodeIndex) { - ASSERT(exec->globalData().dynamicGlobalObject); + RELEASE_ASSERT(exec->vm().dynamicGlobalObject); ASSERT(!!m_codeBlockForCall); JSObject* error = 0; if (m_codeBlockForCall->getJITType() != JITCode::topTierJIT()) @@ -461,7 +469,7 @@ JSObject* FunctionExecutable::compileOptimizedForCall(ExecState* exec, JSScope* JSObject* FunctionExecutable::compileOptimizedForConstruct(ExecState* exec, JSScope* scope, unsigned bytecodeIndex) { - ASSERT(exec->globalData().dynamicGlobalObject); + RELEASE_ASSERT(exec->vm().dynamicGlobalObject); ASSERT(!!m_codeBlockForConstruct); JSObject* error = 0; if (m_codeBlockForConstruct->getJITType() != JITCode::topTierJIT()) @@ -482,30 +490,29 @@ bool FunctionExecutable::jitCompileForConstruct(ExecState* exec) } #endif -FunctionCodeBlock* FunctionExecutable::codeBlockWithBytecodeFor(CodeSpecializationKind kind) -{ - return baselineCodeBlockFor(kind); -} - PassOwnPtr<FunctionCodeBlock> FunctionExecutable::produceCodeBlockFor(JSScope* scope, CodeSpecializationKind specializationKind, JSObject*& exception) { if (!!codeBlockFor(specializationKind)) return adoptPtr(new FunctionCodeBlock(CodeBlock::CopyParsedBlock, *codeBlockFor(specializationKind))); - JSGlobalData* globalData = scope->globalData(); + VM* vm = scope->vm(); JSGlobalObject* globalObject = scope->globalObject(); ParserError error; DebuggerMode debuggerMode = globalObject->hasDebugger() ? DebuggerOn : DebuggerOff; ProfilerMode profilerMode = globalObject->hasProfiler() ? ProfilerOn : ProfilerOff; - UnlinkedFunctionCodeBlock* unlinkedCodeBlock = m_unlinkedExecutable->codeBlockFor(*globalData, m_source, specializationKind, debuggerMode, profilerMode, error); - recordParse(m_unlinkedExecutable->features(), m_unlinkedExecutable->hasCapturedVariables(), lineNo(), lastLine()); + UnlinkedFunctionCodeBlock* unlinkedCodeBlock = m_unlinkedExecutable->codeBlockFor(*vm, scope, m_source, specializationKind, debuggerMode, profilerMode, error); + recordParse(m_unlinkedExecutable->features(), m_unlinkedExecutable->hasCapturedVariables(), lineNo(), lastLine(), startColumn()); if (!unlinkedCodeBlock) { exception = error.toErrorObject(globalObject, m_source); return nullptr; } - OwnPtr<FunctionCodeBlock> result = adoptPtr(new FunctionCodeBlock(this, unlinkedCodeBlock, globalObject, source().provider(), source().startOffset())); + SourceProvider* provider = source().provider(); + unsigned sourceOffset = source().startOffset(); + unsigned startColumn = source().startColumn(); + + OwnPtr<FunctionCodeBlock> result = adoptPtr(new FunctionCodeBlock(this, unlinkedCodeBlock, globalObject, provider, sourceOffset, startColumn)); result->copyPostParseDataFrom(codeBlockFor(specializationKind).get()); return result.release(); } @@ -531,7 +538,7 @@ JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, JSScope* s m_codeBlockForCall = newCodeBlock.release(); m_numParametersForCall = m_codeBlockForCall->numParameters(); - ASSERT(m_numParametersForCall); + RELEASE_ASSERT(m_numParametersForCall); #if ENABLE(JIT) if (!prepareFunctionForExecution(exec, m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, jitType, bytecodeIndex, CodeForCall)) @@ -567,7 +574,7 @@ JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, JSSco m_codeBlockForConstruct = newCodeBlock.release(); m_numParametersForConstruct = m_codeBlockForConstruct->numParameters(); - ASSERT(m_numParametersForConstruct); + RELEASE_ASSERT(m_numParametersForConstruct); #if ENABLE(JIT) if (!prepareFunctionForExecution(exec, m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, jitType, bytecodeIndex, CodeForConstruct)) @@ -584,16 +591,16 @@ JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, JSSco } #if ENABLE(JIT) -void FunctionExecutable::jettisonOptimizedCodeForCall(JSGlobalData& globalData) +void FunctionExecutable::jettisonOptimizedCodeForCall(VM& vm) { - jettisonCodeBlock(globalData, m_codeBlockForCall); + jettisonCodeBlock(vm, m_codeBlockForCall); m_jitCodeForCall = m_codeBlockForCall->getJITCode(); m_jitCodeForCallWithArityCheck = m_codeBlockForCall->getJITCodeWithArityCheck(); } -void FunctionExecutable::jettisonOptimizedCodeForConstruct(JSGlobalData& globalData) +void FunctionExecutable::jettisonOptimizedCodeForConstruct(VM& vm) { - jettisonCodeBlock(globalData, m_codeBlockForConstruct); + jettisonCodeBlock(vm, m_codeBlockForConstruct); m_jitCodeForConstruct = m_codeBlockForConstruct->getJITCode(); m_jitCodeForConstructWithArityCheck = m_codeBlockForConstruct->getJITCodeWithArityCheck(); } @@ -638,11 +645,11 @@ void FunctionExecutable::unlinkCalls() { #if ENABLE(JIT) if (!!m_jitCodeForCall) { - ASSERT(m_codeBlockForCall); + RELEASE_ASSERT(m_codeBlockForCall); m_codeBlockForCall->unlinkCalls(); } if (!!m_jitCodeForConstruct) { - ASSERT(m_codeBlockForConstruct); + RELEASE_ASSERT(m_codeBlockForConstruct); m_codeBlockForConstruct->unlinkCalls(); } #endif @@ -655,9 +662,10 @@ FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& name, E return 0; unsigned firstLine = source.firstLine() + unlinkedFunction->firstLineOffset(); unsigned startOffset = source.startOffset() + unlinkedFunction->startOffset(); + unsigned startColumn = source.startColumn(); unsigned sourceLength = unlinkedFunction->sourceLength(); - SourceCode functionSource(source.provider(), startOffset, startOffset + sourceLength, firstLine); - return FunctionExecutable::create(exec->globalData(), functionSource, unlinkedFunction, firstLine, unlinkedFunction->lineCount()); + SourceCode functionSource(source.provider(), startOffset, startOffset + sourceLength, firstLine, startColumn); + return FunctionExecutable::create(exec->vm(), functionSource, unlinkedFunction, firstLine, unlinkedFunction->lineCount(), startColumn); } String FunctionExecutable::paramString() const @@ -678,7 +686,7 @@ CodeBlockHash NativeExecutable::hashFor(CodeSpecializationKind kind) const if (kind == CodeForCall) return CodeBlockHash(static_cast<unsigned>(bitwise_cast<size_t>(m_function))); - ASSERT(kind == CodeForConstruct); + RELEASE_ASSERT(kind == CodeForConstruct); return CodeBlockHash(static_cast<unsigned>(bitwise_cast<size_t>(m_constructor))); } diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h index 83eb602c4..28e823ca4 100644 --- a/Source/JavaScriptCore/runtime/Executable.h +++ b/Source/JavaScriptCore/runtime/Executable.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2010, 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,10 +32,11 @@ #include "HandlerInfo.h" #include "JSFunction.h" #include "Interpreter.h" +#include "JITCode.h" #include "JSGlobalObject.h" #include "LLIntCLoop.h" -#include "Nodes.h" #include "SamplingTool.h" +#include "SourceCode.h" #include "UnlinkedCodeBlock.h" #include <wtf/PassOwnPtr.h> @@ -67,16 +68,16 @@ namespace JSC { static const int NUM_PARAMETERS_IS_HOST = 0; static const int NUM_PARAMETERS_NOT_COMPILED = -1; - ExecutableBase(JSGlobalData& globalData, Structure* structure, int numParameters) - : JSCell(globalData, structure) + ExecutableBase(VM& vm, Structure* structure, int numParameters) + : JSCell(vm, structure) , m_numParametersForCall(numParameters) , m_numParametersForConstruct(numParameters) { } - void finishCreation(JSGlobalData& globalData) + void finishCreation(VM& vm) { - Base::finishCreation(globalData); + Base::finishCreation(vm); } public: @@ -101,7 +102,7 @@ namespace JSC { return m_numParametersForCall == NUM_PARAMETERS_IS_HOST; } - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(CompoundType, StructureFlags), &s_info); } + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CompoundType, StructureFlags), &s_info); } void clearCode(); @@ -176,16 +177,6 @@ namespace JSC { return hasJITCodeForConstruct(); } - // Intrinsics are only for calls, currently. - Intrinsic intrinsic() const; - - Intrinsic intrinsicFor(CodeSpecializationKind kind) const - { - if (isCall(kind)) - return intrinsic(); - return NoIntrinsic; - } - static ptrdiff_t offsetOfJITCodeFor(CodeSpecializationKind kind) { if (kind == CodeForCall) @@ -211,6 +202,16 @@ namespace JSC { } #endif // ENABLE(JIT) + // Intrinsics are only for calls, currently. + Intrinsic intrinsic() const; + + Intrinsic intrinsicFor(CodeSpecializationKind kind) const + { + if (isCall(kind)) + return intrinsic(); + return NoIntrinsic; + } + #if ENABLE(JIT) || ENABLE(LLINT_C_LOOP) MacroAssemblerCodePtr hostCodeEntryFor(CodeSpecializationKind kind) { @@ -270,26 +271,26 @@ namespace JSC { typedef ExecutableBase Base; #if ENABLE(JIT) - static NativeExecutable* create(JSGlobalData& globalData, MacroAssemblerCodeRef callThunk, NativeFunction function, MacroAssemblerCodeRef constructThunk, NativeFunction constructor, Intrinsic intrinsic) + static NativeExecutable* create(VM& vm, MacroAssemblerCodeRef callThunk, NativeFunction function, MacroAssemblerCodeRef constructThunk, NativeFunction constructor, Intrinsic intrinsic) { NativeExecutable* executable; if (!callThunk) { - executable = new (NotNull, allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor); - executable->finishCreation(globalData, JITCode(), JITCode(), intrinsic); + executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor); + executable->finishCreation(vm, JITCode(), JITCode(), intrinsic); } else { - executable = new (NotNull, allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor); - executable->finishCreation(globalData, JITCode::HostFunction(callThunk), JITCode::HostFunction(constructThunk), intrinsic); + executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor); + executable->finishCreation(vm, JITCode::HostFunction(callThunk), JITCode::HostFunction(constructThunk), intrinsic); } return executable; } #endif #if ENABLE(LLINT_C_LOOP) - static NativeExecutable* create(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor) + static NativeExecutable* create(VM& vm, NativeFunction function, NativeFunction constructor) { - ASSERT(!globalData.canUseJIT()); - NativeExecutable* executable = new (NotNull, allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor); - executable->finishCreation(globalData); + ASSERT(!vm.canUseJIT()); + NativeExecutable* executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor); + executable->finishCreation(vm); return executable; } #endif @@ -302,8 +303,24 @@ namespace JSC { NativeFunction function() { return m_function; } NativeFunction constructor() { return m_constructor; } + + NativeFunction nativeFunctionFor(CodeSpecializationKind kind) + { + if (kind == CodeForCall) + return function(); + ASSERT(kind == CodeForConstruct); + return constructor(); + } + + static ptrdiff_t offsetOfNativeFunctionFor(CodeSpecializationKind kind) + { + if (kind == CodeForCall) + return OBJECT_OFFSETOF(NativeExecutable, m_function); + ASSERT(kind == CodeForConstruct); + return OBJECT_OFFSETOF(NativeExecutable, m_constructor); + } - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(LeafType, StructureFlags), &s_info); } + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(LeafType, StructureFlags), &s_info); } static const ClassInfo s_info; @@ -311,9 +328,9 @@ namespace JSC { protected: #if ENABLE(JIT) - void finishCreation(JSGlobalData& globalData, JITCode callThunk, JITCode constructThunk, Intrinsic intrinsic) + void finishCreation(VM& vm, JITCode callThunk, JITCode constructThunk, Intrinsic intrinsic) { - Base::finishCreation(globalData); + Base::finishCreation(vm); m_jitCodeForCall = callThunk; m_jitCodeForConstruct = constructThunk; m_jitCodeForCallWithArityCheck = callThunk.addressForCall(); @@ -323,8 +340,8 @@ namespace JSC { #endif private: - NativeExecutable(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor) - : ExecutableBase(globalData, globalData.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST) + NativeExecutable(VM& vm, NativeFunction function, NativeFunction constructor) + : ExecutableBase(vm, vm.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST) , m_function(function) , m_constructor(constructor) { @@ -340,17 +357,19 @@ namespace JSC { public: typedef ExecutableBase Base; - ScriptExecutable(Structure* structure, JSGlobalData& globalData, const SourceCode& source, bool isInStrictContext) - : ExecutableBase(globalData, structure, NUM_PARAMETERS_NOT_COMPILED) + ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext) + : ExecutableBase(vm, structure, NUM_PARAMETERS_NOT_COMPILED) , m_source(source) , m_features(isInStrictContext ? StrictModeFeature : 0) + , m_neverInline(false) { } ScriptExecutable(Structure* structure, ExecState* exec, const SourceCode& source, bool isInStrictContext) - : ExecutableBase(exec->globalData(), structure, NUM_PARAMETERS_NOT_COMPILED) + : ExecutableBase(exec->vm(), structure, NUM_PARAMETERS_NOT_COMPILED) , m_source(source) , m_features(isInStrictContext ? StrictModeFeature : 0) + , m_neverInline(false) { } @@ -365,11 +384,16 @@ namespace JSC { const String& sourceURL() const { return m_source.provider()->url(); } int lineNo() const { return m_firstLine; } int lastLine() const { return m_lastLine; } + unsigned startColumn() const { return m_startColumn; } bool usesEval() const { return m_features & EvalFeature; } bool usesArguments() const { return m_features & ArgumentsFeature; } bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature | CatchFeature); } bool isStrictMode() const { return m_features & StrictModeFeature; } + + void setNeverInline(bool value) { m_neverInline = value; } + bool neverInline() const { return m_neverInline; } + bool isInliningCandidate() const { return !neverInline(); } void unlinkCalls(); @@ -377,31 +401,34 @@ namespace JSC { static const ClassInfo s_info; - void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine) + void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine, unsigned startColumn) { m_features = features; m_hasCapturedVariables = hasCapturedVariables; m_firstLine = firstLine; m_lastLine = lastLine; + m_startColumn = startColumn; } protected: - void finishCreation(JSGlobalData& globalData) + void finishCreation(VM& vm) { - Base::finishCreation(globalData); - globalData.heap.addCompiledCode(this); // Balanced by Heap::deleteUnmarkedCompiledCode(). + Base::finishCreation(vm); + vm.heap.addCompiledCode(this); // Balanced by Heap::deleteUnmarkedCompiledCode(). #if ENABLE(CODEBLOCK_SAMPLING) - if (SamplingTool* sampler = globalData.interpreter->sampler()) - sampler->notifyOfScope(globalData, this); + if (SamplingTool* sampler = vm.interpreter->sampler()) + sampler->notifyOfScope(vm, this); #endif } SourceCode m_source; CodeFeatures m_features; bool m_hasCapturedVariables; + bool m_neverInline; int m_firstLine; int m_lastLine; + unsigned m_startColumn; }; class EvalExecutable : public ScriptExecutable { @@ -413,7 +440,7 @@ namespace JSC { JSObject* compile(ExecState* exec, JSScope* scope) { - ASSERT(exec->globalData().dynamicGlobalObject); + RELEASE_ASSERT(exec->vm().dynamicGlobalObject); JSObject* error = 0; if (!m_evalCodeBlock) error = compileInternal(exec, scope, JITCode::bottomTierJIT()); @@ -424,7 +451,7 @@ namespace JSC { JSObject* compileOptimized(ExecState*, JSScope*, unsigned bytecodeIndex); #if ENABLE(JIT) - void jettisonOptimizedCode(JSGlobalData&); + void jettisonOptimizedCode(VM&); bool jitCompile(ExecState*); #endif @@ -434,10 +461,10 @@ namespace JSC { return *m_evalCodeBlock; } - static EvalExecutable* create(ExecState* exec, const SourceCode& source, bool isInStrictContext) + static EvalExecutable* create(ExecState* exec, PassRefPtr<CodeCache> cache, const SourceCode& source, bool isInStrictContext) { - EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext); - executable->finishCreation(exec->globalData()); + EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, cache, source, isInStrictContext); + executable->finishCreation(exec->vm()); return executable; } @@ -447,9 +474,9 @@ namespace JSC { return generatedJITCodeForCall(); } #endif - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { - return Structure::create(globalData, globalObject, proto, TypeInfo(EvalExecutableType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, proto, TypeInfo(EvalExecutableType, StructureFlags), &s_info); } static const ClassInfo s_info; @@ -462,13 +489,14 @@ namespace JSC { private: static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; - EvalExecutable(ExecState*, const SourceCode&, bool); + EvalExecutable(ExecState*, PassRefPtr<CodeCache>, const SourceCode&, bool); JSObject* compileInternal(ExecState*, JSScope*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX); static void visitChildren(JSCell*, SlotVisitor&); OwnPtr<EvalCodeBlock> m_evalCodeBlock; WriteBarrier<UnlinkedEvalCodeBlock> m_unlinkedEvalCodeBlock; + RefPtr<CodeCache> m_codeCache; }; class ProgramExecutable : public ScriptExecutable { @@ -479,18 +507,18 @@ namespace JSC { static ProgramExecutable* create(ExecState* exec, const SourceCode& source) { ProgramExecutable* executable = new (NotNull, allocateCell<ProgramExecutable>(*exec->heap())) ProgramExecutable(exec, source); - executable->finishCreation(exec->globalData()); + executable->finishCreation(exec->vm()); return executable; } - JSObject* initalizeGlobalProperties(JSGlobalData&, CallFrame*, JSScope*); + JSObject* initializeGlobalProperties(VM&, CallFrame*, JSScope*); static void destroy(JSCell*); JSObject* compile(ExecState* exec, JSScope* scope) { - ASSERT(exec->globalData().dynamicGlobalObject); + RELEASE_ASSERT(exec->vm().dynamicGlobalObject); JSObject* error = 0; if (!m_programCodeBlock) error = compileInternal(exec, scope, JITCode::bottomTierJIT()); @@ -501,7 +529,7 @@ namespace JSC { JSObject* compileOptimized(ExecState*, JSScope*, unsigned bytecodeIndex); #if ENABLE(JIT) - void jettisonOptimizedCode(JSGlobalData&); + void jettisonOptimizedCode(VM&); bool jitCompile(ExecState*); #endif @@ -520,9 +548,9 @@ namespace JSC { } #endif - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { - return Structure::create(globalData, globalObject, proto, TypeInfo(ProgramExecutableType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, proto, TypeInfo(ProgramExecutableType, StructureFlags), &s_info); } static const ClassInfo s_info; @@ -555,15 +583,20 @@ namespace JSC { public: typedef ScriptExecutable Base; - static FunctionExecutable* create(JSGlobalData& globalData, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine) + static FunctionExecutable* create(VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine, unsigned startColumn) { - FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(globalData.heap)) FunctionExecutable(globalData, source, unlinkedExecutable, firstLine, lastLine); - executable->finishCreation(globalData); + FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(vm.heap)) FunctionExecutable(vm, source, unlinkedExecutable, firstLine, lastLine, startColumn); + executable->finishCreation(vm); return executable; } static FunctionExecutable* fromGlobalCode(const Identifier& name, ExecState*, Debugger*, const SourceCode&, JSObject** exception); static void destroy(JSCell*); + + UnlinkedFunctionExecutable* unlinkedExecutable() + { + return m_unlinkedExecutable.get(); + } // Returns either call or construct bytecode. This can be appropriate // for answering questions that that don't vary between call and construct -- @@ -576,13 +609,11 @@ namespace JSC { return *m_codeBlockForConstruct; } - FunctionCodeBlock* codeBlockWithBytecodeFor(CodeSpecializationKind); - PassOwnPtr<FunctionCodeBlock> produceCodeBlockFor(JSScope*, CodeSpecializationKind, JSObject*& exception); JSObject* compileForCall(ExecState* exec, JSScope* scope) { - ASSERT(exec->globalData().dynamicGlobalObject); + RELEASE_ASSERT(exec->vm().dynamicGlobalObject); JSObject* error = 0; if (!m_codeBlockForCall) error = compileForCallInternal(exec, scope, JITCode::bottomTierJIT()); @@ -593,7 +624,7 @@ namespace JSC { JSObject* compileOptimizedForCall(ExecState*, JSScope*, unsigned bytecodeIndex); #if ENABLE(JIT) - void jettisonOptimizedCodeForCall(JSGlobalData&); + void jettisonOptimizedCodeForCall(VM&); bool jitCompileForCall(ExecState*); #endif @@ -610,7 +641,7 @@ namespace JSC { JSObject* compileForConstruct(ExecState* exec, JSScope* scope) { - ASSERT(exec->globalData().dynamicGlobalObject); + RELEASE_ASSERT(exec->vm().dynamicGlobalObject); JSObject* error = 0; if (!m_codeBlockForConstruct) error = compileForConstructInternal(exec, scope, JITCode::bottomTierJIT()); @@ -621,7 +652,7 @@ namespace JSC { JSObject* compileOptimizedForConstruct(ExecState*, JSScope*, unsigned bytecodeIndex); #if ENABLE(JIT) - void jettisonOptimizedCodeForConstruct(JSGlobalData&); + void jettisonOptimizedCodeForConstruct(VM&); bool jitCompileForConstruct(ExecState*); #endif @@ -661,13 +692,13 @@ namespace JSC { } #if ENABLE(JIT) - void jettisonOptimizedCodeFor(JSGlobalData& globalData, CodeSpecializationKind kind) + void jettisonOptimizedCodeFor(VM& vm, CodeSpecializationKind kind) { if (kind == CodeForCall) - jettisonOptimizedCodeForCall(globalData); + jettisonOptimizedCodeForCall(vm); else { ASSERT(kind == CodeForConstruct); - jettisonOptimizedCodeForConstruct(globalData); + jettisonOptimizedCodeForConstruct(vm); } } @@ -713,9 +744,9 @@ namespace JSC { void clearCodeIfNotCompiling(); void clearUnlinkedCodeForRecompilationIfNotCompiling(); static void visitChildren(JSCell*, SlotVisitor&); - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { - return Structure::create(globalData, globalObject, proto, TypeInfo(FunctionExecutableType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, proto, TypeInfo(FunctionExecutableType, StructureFlags), &s_info); } static const ClassInfo s_info; @@ -725,7 +756,7 @@ namespace JSC { void clearCode(); private: - FunctionExecutable(JSGlobalData&, const SourceCode&, UnlinkedFunctionExecutable*, unsigned firstLine, unsigned lastLine); + FunctionExecutable(VM&, const SourceCode&, UnlinkedFunctionExecutable*, unsigned firstLine, unsigned lastLine, unsigned startColumn); JSObject* compileForCallInternal(ExecState*, JSScope*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX); JSObject* compileForConstructInternal(ExecState*, JSScope*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX); @@ -755,38 +786,6 @@ namespace JSC { OwnPtr<FunctionCodeBlock> m_codeBlockForConstruct; }; - inline JSFunction::JSFunction(JSGlobalData& globalData, FunctionExecutable* executable, JSScope* scope) - : Base(globalData, scope->globalObject()->functionStructure()) - , m_executable(globalData, this, executable) - , m_scope(globalData, this, scope) - , m_inheritorIDWatchpoint(InitializedBlind) // See comment in JSFunction.cpp concerning the reason for using InitializedBlind as opposed to InitializedWatching. - { - } - - inline FunctionExecutable* JSFunction::jsExecutable() const - { - ASSERT(!isHostFunctionNonInline()); - return static_cast<FunctionExecutable*>(m_executable.get()); - } - - inline bool JSFunction::isHostFunction() const - { - ASSERT(m_executable); - return m_executable->isHostFunction(); - } - - inline NativeFunction JSFunction::nativeFunction() - { - ASSERT(isHostFunction()); - return static_cast<NativeExecutable*>(m_executable.get())->function(); - } - - inline NativeFunction JSFunction::nativeConstructor() - { - ASSERT(isHostFunction()); - return static_cast<NativeExecutable*>(m_executable.get())->constructor(); - } - inline bool isHostFunction(JSValue value, NativeFunction nativeFunction) { JSFunction* function = jsCast<JSFunction*>(getJSFunction(value)); @@ -819,10 +818,12 @@ namespace JSC { case FunctionExecutableType: return jsCast<FunctionExecutable*>(this)->unlinkCalls(); default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } } } +#include "JSFunctionInlines.h" + #endif diff --git a/Source/JavaScriptCore/runtime/ExecutionHarness.h b/Source/JavaScriptCore/runtime/ExecutionHarness.h index b71b60217..ba52a1e51 100644 --- a/Source/JavaScriptCore/runtime/ExecutionHarness.h +++ b/Source/JavaScriptCore/runtime/ExecutionHarness.h @@ -41,8 +41,10 @@ inline bool prepareForExecution(ExecState* exec, OwnPtr<CodeBlockType>& codeBloc #if ENABLE(LLINT) if (JITCode::isBaselineCode(jitType)) { // Start off in the low level interpreter. - LLInt::getEntrypoint(exec->globalData(), codeBlock.get(), jitCode); + LLInt::getEntrypoint(exec->vm(), codeBlock.get(), jitCode); codeBlock->setJITCode(jitCode, MacroAssemblerCodePtr()); + if (exec->vm().m_perBytecodeProfiler) + exec->vm().m_perBytecodeProfiler->ensureBytecodesFor(codeBlock.get()); return true; } #endif // ENABLE(LLINT) @@ -54,8 +56,10 @@ inline bool prepareFunctionForExecution(ExecState* exec, OwnPtr<FunctionCodeBloc #if ENABLE(LLINT) if (JITCode::isBaselineCode(jitType)) { // Start off in the low level interpreter. - LLInt::getFunctionEntrypoint(exec->globalData(), kind, jitCode, jitCodeWithArityCheck); + LLInt::getFunctionEntrypoint(exec->vm(), kind, jitCode, jitCodeWithArityCheck); codeBlock->setJITCode(jitCode, jitCodeWithArityCheck); + if (exec->vm().m_perBytecodeProfiler) + exec->vm().m_perBytecodeProfiler->ensureBytecodesFor(codeBlock.get()); return true; } #else diff --git a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp index bf74c0a97..3c4379b39 100644 --- a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp +++ b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp @@ -29,6 +29,7 @@ #include "JSString.h" #include "Lexer.h" #include "Nodes.h" +#include "Operations.h" #include "Parser.h" #include <wtf/text/StringBuilder.h> @@ -45,11 +46,11 @@ FunctionConstructor::FunctionConstructor(JSGlobalObject* globalObject, Structure void FunctionConstructor::finishCreation(ExecState* exec, FunctionPrototype* functionPrototype) { - Base::finishCreation(exec->globalData(), functionPrototype->classInfo()->className); - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, functionPrototype, DontEnum | DontDelete | ReadOnly); + Base::finishCreation(exec->vm(), functionPrototype->classInfo()->className); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().prototype, functionPrototype, DontEnum | DontDelete | ReadOnly); // Number of arguments for constructor - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontDelete | DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontDelete | DontEnum); } static EncodedJSValue JSC_HOST_CALL constructWithFunctionConstructor(ExecState* exec) @@ -123,7 +124,7 @@ JSObject* constructFunctionSkippingEvalEnabledCheck(ExecState* exec, JSGlobalObj // ECMA 15.3.2 The Function Constructor JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args) { - return constructFunction(exec, globalObject, args, Identifier(exec, "anonymous"), String(), TextPosition::minimumPosition()); + return constructFunction(exec, globalObject, args, exec->propertyNames().anonymous, String(), TextPosition::minimumPosition()); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/FunctionConstructor.h b/Source/JavaScriptCore/runtime/FunctionConstructor.h index 99eafee80..3d211f633 100644 --- a/Source/JavaScriptCore/runtime/FunctionConstructor.h +++ b/Source/JavaScriptCore/runtime/FunctionConstructor.h @@ -44,9 +44,9 @@ namespace JSC { static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } private: diff --git a/Source/JavaScriptCore/runtime/FunctionExecutableDump.cpp b/Source/JavaScriptCore/runtime/FunctionExecutableDump.cpp new file mode 100644 index 000000000..1577ed57a --- /dev/null +++ b/Source/JavaScriptCore/runtime/FunctionExecutableDump.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2013 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 "FunctionExecutableDump.h" + +namespace JSC { + +void FunctionExecutableDump::dump(PrintStream& out) const +{ + out.print(m_executable->inferredName().string(), "#", m_executable->hashFor(CodeForCall), "/", m_executable->hashFor(CodeForConstruct), ":[", RawPointer(m_executable), "]"); +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/runtime/FunctionExecutableDump.h b/Source/JavaScriptCore/runtime/FunctionExecutableDump.h new file mode 100644 index 000000000..732ec458f --- /dev/null +++ b/Source/JavaScriptCore/runtime/FunctionExecutableDump.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2013 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 FunctionExecutableDump_h +#define FunctionExecutableDump_h + +#include "Executable.h" +#include <wtf/PrintStream.h> + +namespace JSC { + +class FunctionExecutableDump { +public: + explicit FunctionExecutableDump(FunctionExecutable* executable) + : m_executable(executable) + { + } + + void dump(PrintStream&) const; +private: + FunctionExecutable* m_executable; +}; + +} // namespace JSC + +#endif // FunctionExecutableDump_h + diff --git a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp index 8e4390b1b..183298267 100644 --- a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp +++ b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp @@ -29,6 +29,7 @@ #include "JSStringBuilder.h" #include "Interpreter.h" #include "Lexer.h" +#include "Operations.h" namespace JSC { @@ -48,23 +49,23 @@ FunctionPrototype::FunctionPrototype(JSGlobalObject* globalObject, Structure* st void FunctionPrototype::finishCreation(ExecState* exec, const String& name) { - Base::finishCreation(exec->globalData(), name); - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum); + Base::finishCreation(exec->vm(), name); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum); } void FunctionPrototype::addFunctionProperties(ExecState* exec, JSGlobalObject* globalObject, JSFunction** callFunction, JSFunction** applyFunction) { JSFunction* toStringFunction = JSFunction::create(exec, globalObject, 0, exec->propertyNames().toString.string(), functionProtoFuncToString); - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().toString, toStringFunction, DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().toString, toStringFunction, DontEnum); *applyFunction = JSFunction::create(exec, globalObject, 2, exec->propertyNames().apply.string(), functionProtoFuncApply); - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().apply, *applyFunction, DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().apply, *applyFunction, DontEnum); *callFunction = JSFunction::create(exec, globalObject, 1, exec->propertyNames().call.string(), functionProtoFuncCall); - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().call, *callFunction, DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().call, *callFunction, DontEnum); JSFunction* bindFunction = JSFunction::create(exec, globalObject, 1, exec->propertyNames().bind.string(), functionProtoFuncBind); - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().bind, bindFunction, DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().bind, bindFunction, DontEnum); } static EncodedJSValue JSC_HOST_CALL callFunctionPrototype(ExecState*) @@ -186,12 +187,12 @@ EncodedJSValue JSC_HOST_CALL functionProtoFuncBind(ExecState* exec) // Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (arg1, arg2 etc), in order. size_t numBoundArgs = exec->argumentCount() > 1 ? exec->argumentCount() - 1 : 0; - JSArray* boundArgs = JSArray::tryCreateUninitialized(exec->globalData(), globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), numBoundArgs); + JSArray* boundArgs = JSArray::tryCreateUninitialized(exec->vm(), globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), numBoundArgs); if (!boundArgs) return JSValue::encode(throwOutOfMemoryError(exec)); for (size_t i = 0; i < numBoundArgs; ++i) - boundArgs->initializeIndex(exec->globalData(), i, exec->argument(i + 1)); + boundArgs->initializeIndex(exec->vm(), i, exec->argument(i + 1)); // If the [[Class]] internal property of Target is "Function", then ... // Else set the length own property of F to 0. diff --git a/Source/JavaScriptCore/runtime/FunctionPrototype.h b/Source/JavaScriptCore/runtime/FunctionPrototype.h index 07f381306..0083fb9d2 100644 --- a/Source/JavaScriptCore/runtime/FunctionPrototype.h +++ b/Source/JavaScriptCore/runtime/FunctionPrototype.h @@ -38,9 +38,9 @@ namespace JSC { void addFunctionProperties(ExecState*, JSGlobalObject*, JSFunction** callFunction, JSFunction** applyFunction); - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { - return Structure::create(globalData, globalObject, proto, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), &s_info); } static const ClassInfo s_info; diff --git a/Source/JavaScriptCore/runtime/GCActivityCallback.cpp b/Source/JavaScriptCore/runtime/GCActivityCallback.cpp index 0c07b5e02..4898122b5 100644 --- a/Source/JavaScriptCore/runtime/GCActivityCallback.cpp +++ b/Source/JavaScriptCore/runtime/GCActivityCallback.cpp @@ -31,16 +31,20 @@ #include "APIShims.h" #include "Heap.h" -#include "JSGlobalData.h" +#include "VM.h" #include "JSLock.h" #include "JSObject.h" #include <wtf/RetainPtr.h> #include <wtf/WTFThreadData.h> +#if PLATFORM(EFL) +#include <wtf/MainThread.h> +#endif + namespace JSC { -#if USE(CF) || PLATFORM(QT) +#if USE(CF) || PLATFORM(QT) || PLATFORM(EFL) const double gcTimeSlicePerMB = 0.01; // Percentage of CPU time we will spend to reclaim 1 MB const double maxGCTimeSlice = 0.05; // The maximum amount of CPU time we want to use for opportunistic timer-triggered collections. @@ -50,19 +54,25 @@ const double hour = 60 * 60; #if USE(CF) DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap) - : GCActivityCallback(heap->globalData(), CFRunLoopGetCurrent()) + : GCActivityCallback(heap->vm(), CFRunLoopGetCurrent()) , m_delay(s_decade) { } DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap, CFRunLoopRef runLoop) - : GCActivityCallback(heap->globalData(), runLoop) + : GCActivityCallback(heap->vm(), runLoop) , m_delay(s_decade) { } #elif PLATFORM(QT) DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap) - : GCActivityCallback(heap->globalData()) + : GCActivityCallback(heap->vm()) + , m_delay(hour) +{ +} +#elif PLATFORM(EFL) +DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap) + : GCActivityCallback(heap->vm(), WTF::isMainThread()) , m_delay(hour) { } @@ -70,11 +80,11 @@ DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap) void DefaultGCActivityCallback::doWork() { - Heap* heap = &m_globalData->heap; + Heap* heap = &m_vm->heap; if (!isEnabled()) return; - APIEntryShim shim(m_globalData); + APIEntryShim shim(m_vm); #if !PLATFORM(IOS) double startTime = WTF::monotonicallyIncreasingTime(); if (heap->isPagedOut(startTime + pagingTimeOut)) { @@ -116,15 +126,40 @@ void DefaultGCActivityCallback::cancelTimer() m_delay = hour; m_timer.stop(); } +#elif PLATFORM(EFL) +void DefaultGCActivityCallback::scheduleTimer(double newDelay) +{ + if (newDelay * timerSlop > m_delay) + return; + + stop(); + m_delay = newDelay; + + ASSERT(!m_timer); + m_timer = add(newDelay, this); +} + +void DefaultGCActivityCallback::cancelTimer() +{ + m_delay = hour; + stop(); +} #endif void DefaultGCActivityCallback::didAllocate(size_t bytes) { +#if PLATFORM(EFL) + if (!isEnabled()) + return; + + ASSERT(WTF::isMainThread()); +#endif + // The first byte allocated in an allocation cycle will report 0 bytes to didAllocate. // We pretend it's one byte so that we don't ignore this allocation entirely. if (!bytes) bytes = 1; - Heap* heap = static_cast<Heap*>(&m_globalData->heap); + Heap* heap = static_cast<Heap*>(&m_vm->heap); double gcTimeSlice = std::min((static_cast<double>(bytes) / MB) * gcTimeSlicePerMB, maxGCTimeSlice); double newDelay = heap->lastGCLength() / gcTimeSlice; scheduleTimer(newDelay); @@ -143,7 +178,7 @@ void DefaultGCActivityCallback::cancel() #else DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap) - : GCActivityCallback(heap->globalData()) + : GCActivityCallback(heap->vm()) { } diff --git a/Source/JavaScriptCore/runtime/GCActivityCallback.h b/Source/JavaScriptCore/runtime/GCActivityCallback.h index 3522e6c8e..a7aec6a8d 100644 --- a/Source/JavaScriptCore/runtime/GCActivityCallback.h +++ b/Source/JavaScriptCore/runtime/GCActivityCallback.h @@ -52,14 +52,20 @@ public: protected: #if USE(CF) - GCActivityCallback(JSGlobalData* globalData, CFRunLoopRef runLoop) - : HeapTimer(globalData, runLoop) + GCActivityCallback(VM* vm, CFRunLoopRef runLoop) + : HeapTimer(vm, runLoop) , m_enabled(true) { } +#elif PLATFORM(EFL) + GCActivityCallback(VM* vm, bool flag) + : HeapTimer(vm) + , m_enabled(flag) + { + } #else - GCActivityCallback(JSGlobalData* globalData) - : HeapTimer(globalData) + GCActivityCallback(VM* vm) + : HeapTimer(vm) , m_enabled(true) { } @@ -70,7 +76,7 @@ protected: class DefaultGCActivityCallback : public GCActivityCallback { public: - static DefaultGCActivityCallback* create(Heap*); + static PassOwnPtr<DefaultGCActivityCallback> create(Heap*); DefaultGCActivityCallback(Heap*); @@ -84,7 +90,7 @@ public: protected: DefaultGCActivityCallback(Heap*, CFRunLoopRef); #endif -#if USE(CF) || PLATFORM(QT) +#if USE(CF) || PLATFORM(QT) || PLATFORM(EFL) protected: void cancelTimer(); void scheduleTimer(double); @@ -94,9 +100,9 @@ private: #endif }; -inline DefaultGCActivityCallback* DefaultGCActivityCallback::create(Heap* heap) +inline PassOwnPtr<DefaultGCActivityCallback> DefaultGCActivityCallback::create(Heap* heap) { - return new DefaultGCActivityCallback(heap); + return adoptPtr(new DefaultGCActivityCallback(heap)); } } diff --git a/Source/JavaScriptCore/runtime/GCActivityCallbackBlackBerry.cpp b/Source/JavaScriptCore/runtime/GCActivityCallbackBlackBerry.cpp index 35b992567..d7c9d53c2 100644 --- a/Source/JavaScriptCore/runtime/GCActivityCallbackBlackBerry.cpp +++ b/Source/JavaScriptCore/runtime/GCActivityCallbackBlackBerry.cpp @@ -20,29 +20,29 @@ #include "GCActivityCallback.h" #include "Heap.h" -#include "JSGlobalData.h" +#include "VM.h" #include <BlackBerryPlatformMemory.h> namespace JSC { DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap) - : GCActivityCallback(heap->globalData()) + : GCActivityCallback(heap->vm()) { } void DefaultGCActivityCallback::doWork() { - JSLock lock(SilenceAssertionsOnly); - m_globalData->heap.collect(Heap::DoNotSweep); + JSLockHolder lock(m_vm); + m_vm->heap.collect(Heap::DoNotSweep); } -void DefaultGCActivityCallback::didAllocate(size_t bytesAllocated) +void DefaultGCActivityCallback::didAllocate(size_t) { if (m_timer.started()) return; // Try using ~5% CPU time. - m_timer.start(m_globalData->heap.lastGCLength() * 20); + m_timer.start(m_vm->heap.lastGCLength() * 20); } void DefaultGCActivityCallback::willCollect() diff --git a/Source/JavaScriptCore/runtime/GetterSetter.cpp b/Source/JavaScriptCore/runtime/GetterSetter.cpp index 8ed582548..b4651141e 100644 --- a/Source/JavaScriptCore/runtime/GetterSetter.cpp +++ b/Source/JavaScriptCore/runtime/GetterSetter.cpp @@ -24,6 +24,7 @@ #include "GetterSetter.h" #include "JSObject.h" +#include "Operations.h" #include <wtf/Assertions.h> namespace JSC { diff --git a/Source/JavaScriptCore/runtime/GetterSetter.h b/Source/JavaScriptCore/runtime/GetterSetter.h index b8caf0198..f459e4432 100644 --- a/Source/JavaScriptCore/runtime/GetterSetter.h +++ b/Source/JavaScriptCore/runtime/GetterSetter.h @@ -39,7 +39,7 @@ namespace JSC { private: GetterSetter(ExecState* exec) - : JSCell(exec->globalData(), exec->globalData().getterSetterStructure.get()) + : JSCell(exec->vm(), exec->vm().getterSetterStructure.get()) { } @@ -49,19 +49,19 @@ namespace JSC { static GetterSetter* create(ExecState* exec) { GetterSetter* getterSetter = new (NotNull, allocateCell<GetterSetter>(*exec->heap())) GetterSetter(exec); - getterSetter->finishCreation(exec->globalData()); + getterSetter->finishCreation(exec->vm()); return getterSetter; } static void visitChildren(JSCell*, SlotVisitor&); JSObject* getter() const { return m_getter.get(); } - void setGetter(JSGlobalData& globalData, JSObject* getter) { m_getter.setMayBeNull(globalData, this, getter); } + void setGetter(VM& vm, JSObject* getter) { m_getter.setMayBeNull(vm, this, getter); } JSObject* setter() const { return m_setter.get(); } - void setSetter(JSGlobalData& globalData, JSObject* setter) { m_setter.setMayBeNull(globalData, this, setter); } - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + void setSetter(VM& vm, JSObject* setter) { m_setter.setMayBeNull(vm, this, setter); } + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(GetterSetterType, OverridesVisitChildren), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(GetterSetterType, OverridesVisitChildren), &s_info); } static const ClassInfo s_info; diff --git a/Source/JavaScriptCore/runtime/Identifier.cpp b/Source/JavaScriptCore/runtime/Identifier.cpp index 583c12bb1..ad61b493a 100644 --- a/Source/JavaScriptCore/runtime/Identifier.cpp +++ b/Source/JavaScriptCore/runtime/Identifier.cpp @@ -25,6 +25,7 @@ #include "JSObject.h" #include "JSScope.h" #include "NumericStrings.h" +#include "Operations.h" #include <new> #include <string.h> #include <wtf/Assertions.h> @@ -50,7 +51,7 @@ void deleteIdentifierTable(IdentifierTable* table) struct IdentifierASCIIStringTranslator { static unsigned hash(const LChar* c) { - return StringHasher::computeHashAndMaskTop8Bits<LChar>(c); + return StringHasher::computeHashAndMaskTop8Bits(c); } static bool equal(StringImpl* r, const LChar* s) @@ -69,7 +70,7 @@ struct IdentifierASCIIStringTranslator { struct IdentifierLCharFromUCharTranslator { static unsigned hash(const CharBuffer<UChar>& buf) { - return StringHasher::computeHashAndMaskTop8Bits<UChar>(buf.s, buf.length); + return StringHasher::computeHashAndMaskTop8Bits(buf.s, buf.length); } static bool equal(StringImpl* str, const CharBuffer<UChar>& buf) @@ -87,19 +88,14 @@ struct IdentifierLCharFromUCharTranslator { } }; -PassRefPtr<StringImpl> Identifier::add(JSGlobalData* globalData, const char* c) +PassRefPtr<StringImpl> Identifier::add(VM* vm, const char* c) { ASSERT(c); ASSERT(c[0]); if (!c[1]) - return add(globalData, globalData->smallStrings.singleCharacterStringRep(c[0])); + return add(vm, vm->smallStrings.singleCharacterStringRep(c[0])); - IdentifierTable& identifierTable = *globalData->identifierTable; - LiteralIdentifierTable& literalIdentifierTable = identifierTable.literalTable(); - - const LiteralIdentifierTable::iterator& iter = literalIdentifierTable.find(c); - if (iter != literalIdentifierTable.end()) - return iter->value; + IdentifierTable& identifierTable = *vm->identifierTable; HashSet<StringImpl*>::AddResult addResult = identifierTable.add<const LChar*, IdentifierASCIIStringTranslator>(reinterpret_cast<const LChar*>(c)); @@ -107,36 +103,34 @@ PassRefPtr<StringImpl> Identifier::add(JSGlobalData* globalData, const char* c) // The boolean in the pair tells us if that is so. RefPtr<StringImpl> addedString = addResult.isNewEntry ? adoptRef(*addResult.iterator) : *addResult.iterator; - literalIdentifierTable.add(c, addedString.get()); - return addedString.release(); } PassRefPtr<StringImpl> Identifier::add(ExecState* exec, const char* c) { - return add(&exec->globalData(), c); + return add(&exec->vm(), c); } -PassRefPtr<StringImpl> Identifier::add8(JSGlobalData* globalData, const UChar* s, int length) +PassRefPtr<StringImpl> Identifier::add8(VM* vm, const UChar* s, int length) { if (length == 1) { UChar c = s[0]; ASSERT(c <= 0xff); if (canUseSingleCharacterString(c)) - return add(globalData, globalData->smallStrings.singleCharacterStringRep(c)); + return add(vm, vm->smallStrings.singleCharacterStringRep(c)); } if (!length) return StringImpl::empty(); CharBuffer<UChar> buf = { s, static_cast<unsigned>(length) }; - HashSet<StringImpl*>::AddResult addResult = globalData->identifierTable->add<CharBuffer<UChar>, IdentifierLCharFromUCharTranslator >(buf); + HashSet<StringImpl*>::AddResult addResult = vm->identifierTable->add<CharBuffer<UChar>, IdentifierLCharFromUCharTranslator >(buf); // If the string is newly-translated, then we need to adopt it. // The boolean in the pair tells us if that is so. return addResult.isNewEntry ? adoptRef(*addResult.iterator) : *addResult.iterator; } -PassRefPtr<StringImpl> Identifier::addSlowCase(JSGlobalData* globalData, StringImpl* r) +PassRefPtr<StringImpl> Identifier::addSlowCase(VM* vm, StringImpl* r) { ASSERT(!r->isIdentifier()); // The empty & null strings are static singletons, and static strings are handled @@ -146,68 +140,68 @@ PassRefPtr<StringImpl> Identifier::addSlowCase(JSGlobalData* globalData, StringI if (r->length() == 1) { UChar c = (*r)[0]; if (c <= maxSingleCharacterString) - r = globalData->smallStrings.singleCharacterStringRep(c); + r = vm->smallStrings.singleCharacterStringRep(c); if (r->isIdentifier()) return r; } - return *globalData->identifierTable->add(r).iterator; + return *vm->identifierTable->add(r).iterator; } PassRefPtr<StringImpl> Identifier::addSlowCase(ExecState* exec, StringImpl* r) { - return addSlowCase(&exec->globalData(), r); + return addSlowCase(&exec->vm(), r); } Identifier Identifier::from(ExecState* exec, unsigned value) { - return Identifier(exec, exec->globalData().numericStrings.add(value)); + return Identifier(exec, exec->vm().numericStrings.add(value)); } Identifier Identifier::from(ExecState* exec, int value) { - return Identifier(exec, exec->globalData().numericStrings.add(value)); + return Identifier(exec, exec->vm().numericStrings.add(value)); } Identifier Identifier::from(ExecState* exec, double value) { - return Identifier(exec, exec->globalData().numericStrings.add(value)); + return Identifier(exec, exec->vm().numericStrings.add(value)); } -Identifier Identifier::from(JSGlobalData* globalData, unsigned value) +Identifier Identifier::from(VM* vm, unsigned value) { - return Identifier(globalData, globalData->numericStrings.add(value)); + return Identifier(vm, vm->numericStrings.add(value)); } -Identifier Identifier::from(JSGlobalData* globalData, int value) +Identifier Identifier::from(VM* vm, int value) { - return Identifier(globalData, globalData->numericStrings.add(value)); + return Identifier(vm, vm->numericStrings.add(value)); } -Identifier Identifier::from(JSGlobalData* globalData, double value) +Identifier Identifier::from(VM* vm, double value) { - return Identifier(globalData, globalData->numericStrings.add(value)); + return Identifier(vm, vm->numericStrings.add(value)); } #ifndef NDEBUG -void Identifier::checkCurrentIdentifierTable(JSGlobalData* globalData) +void Identifier::checkCurrentIdentifierTable(VM* vm) { // Check the identifier table accessible through the threadspecific matches the - // globalData's identifier table. - ASSERT_UNUSED(globalData, globalData->identifierTable == wtfThreadData().currentIdentifierTable()); + // vm's identifier table. + ASSERT_UNUSED(vm, vm->identifierTable == wtfThreadData().currentIdentifierTable()); } void Identifier::checkCurrentIdentifierTable(ExecState* exec) { - checkCurrentIdentifierTable(&exec->globalData()); + checkCurrentIdentifierTable(&exec->vm()); } #else // These only exists so that our exports are the same for debug and release builds. -// This would be an ASSERT_NOT_REACHED(), but we're in NDEBUG only code here! -NO_RETURN_DUE_TO_CRASH void Identifier::checkCurrentIdentifierTable(JSGlobalData*) { CRASH(); } +// This would be an RELEASE_ASSERT_NOT_REACHED(), but we're in NDEBUG only code here! +NO_RETURN_DUE_TO_CRASH void Identifier::checkCurrentIdentifierTable(VM*) { CRASH(); } NO_RETURN_DUE_TO_CRASH void Identifier::checkCurrentIdentifierTable(ExecState*) { CRASH(); } #endif diff --git a/Source/JavaScriptCore/runtime/Identifier.h b/Source/JavaScriptCore/runtime/Identifier.h index dcb739ec3..75b68b6e1 100644 --- a/Source/JavaScriptCore/runtime/Identifier.h +++ b/Source/JavaScriptCore/runtime/Identifier.h @@ -21,7 +21,7 @@ #ifndef Identifier_h #define Identifier_h -#include "JSGlobalData.h" +#include "VM.h" #include <wtf/ThreadSpecific.h> #include <wtf/WTFThreadData.h> #include <wtf/text/CString.h> @@ -42,15 +42,15 @@ namespace JSC { template<unsigned charactersCount> Identifier(ExecState* exec, const char (&characters)[charactersCount]) : m_string(add(exec, characters)) { } template<unsigned charactersCount> - Identifier(JSGlobalData* globalData, const char (&characters)[charactersCount]) : m_string(add(globalData, characters)) { } + Identifier(VM* vm, const char (&characters)[charactersCount]) : m_string(add(vm, characters)) { } Identifier(ExecState* exec, StringImpl* rep) : m_string(add(exec, rep)) { } Identifier(ExecState* exec, const String& s) : m_string(add(exec, s.impl())) { } - Identifier(JSGlobalData* globalData, const LChar* s, int length) : m_string(add(globalData, s, length)) { } - Identifier(JSGlobalData* globalData, const UChar* s, int length) : m_string(add(globalData, s, length)) { } - Identifier(JSGlobalData* globalData, StringImpl* rep) : m_string(add(globalData, rep)) { } - Identifier(JSGlobalData* globalData, const String& s) : m_string(add(globalData, s.impl())) { } + Identifier(VM* vm, const LChar* s, int length) : m_string(add(vm, s, length)) { } + Identifier(VM* vm, const UChar* s, int length) : m_string(add(vm, s, length)) { } + Identifier(VM* vm, StringImpl* rep) : m_string(add(vm, rep)) { } + Identifier(VM* vm, const String& s) : m_string(add(vm, s.impl())) { } const String& string() const { return m_string; } StringImpl* impl() const { return m_string.impl(); } @@ -60,14 +60,14 @@ namespace JSC { CString ascii() const { return m_string.ascii(); } - static Identifier createLCharFromUChar(JSGlobalData* globalData, const UChar* s, int length) { return Identifier(globalData, add8(globalData, s, length)); } + static Identifier createLCharFromUChar(VM* vm, const UChar* s, int length) { return Identifier(vm, add8(vm, s, length)); } JS_EXPORT_PRIVATE static Identifier from(ExecState* exec, unsigned y); JS_EXPORT_PRIVATE static Identifier from(ExecState* exec, int y); static Identifier from(ExecState* exec, double y); - static Identifier from(JSGlobalData*, unsigned y); - static Identifier from(JSGlobalData*, int y); - static Identifier from(JSGlobalData*, double y); + static Identifier from(VM*, unsigned y); + static Identifier from(VM*, int y); + static Identifier from(VM*, double y); bool isNull() const { return m_string.isNull(); } bool isEmpty() const { return m_string.isEmpty(); } @@ -87,7 +87,7 @@ namespace JSC { static bool equal(const StringImpl* a, const StringImpl* b) { return ::equal(a, b); } // Only to be used with string literals. - static PassRefPtr<StringImpl> add(JSGlobalData*, const char*); + static PassRefPtr<StringImpl> add(VM*, const char*); JS_EXPORT_PRIVATE static PassRefPtr<StringImpl> add(ExecState*, const char*); private: @@ -99,8 +99,8 @@ namespace JSC { static bool equal(const Identifier& a, const Identifier& b) { return a.m_string.impl() == b.m_string.impl(); } static bool equal(const Identifier& a, const LChar* b) { return equal(a.m_string.impl(), b); } - template <typename T> static PassRefPtr<StringImpl> add(JSGlobalData*, const T*, int length); - static PassRefPtr<StringImpl> add8(JSGlobalData*, const UChar*, int length); + template <typename T> static PassRefPtr<StringImpl> add(VM*, const T*, int length); + static PassRefPtr<StringImpl> add8(VM*, const UChar*, int length); template <typename T> ALWAYS_INLINE static bool canUseSingleCharacterString(T); static PassRefPtr<StringImpl> add(ExecState* exec, StringImpl* r) @@ -112,21 +112,21 @@ namespace JSC { return r; return addSlowCase(exec, r); } - static PassRefPtr<StringImpl> add(JSGlobalData* globalData, StringImpl* r) + static PassRefPtr<StringImpl> add(VM* vm, StringImpl* r) { #ifndef NDEBUG - checkCurrentIdentifierTable(globalData); + checkCurrentIdentifierTable(vm); #endif if (r->isIdentifier()) return r; - return addSlowCase(globalData, r); + return addSlowCase(vm, r); } JS_EXPORT_PRIVATE static PassRefPtr<StringImpl> addSlowCase(ExecState*, StringImpl* r); - JS_EXPORT_PRIVATE static PassRefPtr<StringImpl> addSlowCase(JSGlobalData*, StringImpl* r); + JS_EXPORT_PRIVATE static PassRefPtr<StringImpl> addSlowCase(VM*, StringImpl* r); JS_EXPORT_PRIVATE static void checkCurrentIdentifierTable(ExecState*); - JS_EXPORT_PRIVATE static void checkCurrentIdentifierTable(JSGlobalData*); + JS_EXPORT_PRIVATE static void checkCurrentIdentifierTable(VM*); }; template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(LChar) @@ -150,7 +150,7 @@ namespace JSC { struct IdentifierCharBufferTranslator { static unsigned hash(const CharBuffer<T>& buf) { - return StringHasher::computeHashAndMaskTop8Bits<T>(buf.s, buf.length); + return StringHasher::computeHashAndMaskTop8Bits(buf.s, buf.length); } static bool equal(StringImpl* str, const CharBuffer<T>& buf) @@ -170,18 +170,18 @@ namespace JSC { }; template <typename T> - PassRefPtr<StringImpl> Identifier::add(JSGlobalData* globalData, const T* s, int length) + PassRefPtr<StringImpl> Identifier::add(VM* vm, const T* s, int length) { if (length == 1) { T c = s[0]; if (canUseSingleCharacterString(c)) - return add(globalData, globalData->smallStrings.singleCharacterStringRep(c)); + return add(vm, vm->smallStrings.singleCharacterStringRep(c)); } if (!length) return StringImpl::empty(); CharBuffer<T> buf = { s, static_cast<unsigned>(length) }; - HashSet<StringImpl*>::AddResult addResult = globalData->identifierTable->add<CharBuffer<T>, IdentifierCharBufferTranslator<T> >(buf); + HashSet<StringImpl*>::AddResult addResult = vm->identifierTable->add<CharBuffer<T>, IdentifierCharBufferTranslator<T> >(buf); // If the string is newly-translated, then we need to adopt it. // The boolean in the pair tells us if that is so. @@ -251,11 +251,17 @@ namespace JSC { template<typename U, typename V> HashSet<StringImpl*>::AddResult IdentifierTable::add(U value) { - HashSet<StringImpl*>::AddResult result = m_table.add<U, V>(value); + HashSet<StringImpl*>::AddResult result = m_table.add<V>(value); (*result.iterator)->setIsIdentifier(true); return result; } } // namespace JSC +namespace WTF { + +template <> struct VectorTraits<JSC::Identifier> : SimpleClassVectorTraits { }; + +} // namespace WTF + #endif // Identifier_h diff --git a/Source/JavaScriptCore/runtime/IndexingHeader.h b/Source/JavaScriptCore/runtime/IndexingHeader.h index caa18183a..145b61876 100644 --- a/Source/JavaScriptCore/runtime/IndexingHeader.h +++ b/Source/JavaScriptCore/runtime/IndexingHeader.h @@ -44,25 +44,25 @@ public: static ptrdiff_t offsetOfIndexingHeader() { return -static_cast<ptrdiff_t>(sizeof(IndexingHeader)); } - static ptrdiff_t offsetOfPublicLength() { return OBJECT_OFFSETOF(IndexingHeader, m_publicLength); } - static ptrdiff_t offsetOfVectorLength() { return OBJECT_OFFSETOF(IndexingHeader, m_vectorLength); } + static ptrdiff_t offsetOfPublicLength() { return OBJECT_OFFSETOF(IndexingHeader, u.lengths.publicLength); } + static ptrdiff_t offsetOfVectorLength() { return OBJECT_OFFSETOF(IndexingHeader, u.lengths.vectorLength); } IndexingHeader() - : m_publicLength(0) - , m_vectorLength(0) { + u.lengths.publicLength = 0; + u.lengths.vectorLength = 0; } - uint32_t vectorLength() const { return m_vectorLength; } + uint32_t vectorLength() const { return u.lengths.vectorLength; } void setVectorLength(uint32_t length) { - ASSERT(length <= maximumLength); - m_vectorLength = length; + RELEASE_ASSERT(length <= maximumLength); + u.lengths.vectorLength = length; } - uint32_t publicLength() { return m_publicLength; } - void setPublicLength(uint32_t auxWord) { m_publicLength = auxWord; } + uint32_t publicLength() { return u.lengths.publicLength; } + void setPublicLength(uint32_t auxWord) { u.lengths.publicLength = auxWord; } static IndexingHeader* from(Butterfly* butterfly) { @@ -86,12 +86,12 @@ public: PropertyStorage propertyStorage() { - return reinterpret_cast<PropertyStorage>(this); + return reinterpret_cast_ptr<PropertyStorage>(this); } ConstPropertyStorage propertyStorage() const { - return reinterpret_cast<ConstPropertyStorage>(this); + return reinterpret_cast_ptr<ConstPropertyStorage>(this); } ArrayStorage* arrayStorage() @@ -111,9 +111,13 @@ public: private: friend class LLIntOffsetsExtractor; - - uint32_t m_publicLength; // The meaning of this field depends on the array type, but for all JSArrays we rely on this being the publicly visible length (array.length). - uint32_t m_vectorLength; // The length of the indexed property storage. The actual size of the storage depends on this, and the type. + + union { + struct { + uint32_t publicLength; // The meaning of this field depends on the array type, but for all JSArrays we rely on this being the publicly visible length (array.length). + uint32_t vectorLength; // The length of the indexed property storage. The actual size of the storage depends on this, and the type. + } lengths; + } u; }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/IndexingType.cpp b/Source/JavaScriptCore/runtime/IndexingType.cpp index dc2733ad1..040a7828a 100644 --- a/Source/JavaScriptCore/runtime/IndexingType.cpp +++ b/Source/JavaScriptCore/runtime/IndexingType.cpp @@ -71,9 +71,8 @@ IndexingType leastUpperBoundOfIndexingTypeAndValue(IndexingType indexingType, JS return leastUpperBoundOfIndexingTypeAndType(indexingType, speculationFromValue(value)); } -const char* indexingTypeToString(IndexingType indexingType) +void dumpIndexingType(PrintStream& out, IndexingType indexingType) { - static char result[128]; const char* basicName; switch (indexingType & AllArrayTypes) { case NonArray: @@ -120,11 +119,7 @@ const char* indexingTypeToString(IndexingType indexingType) break; } - snprintf( - result, sizeof(result), "%s%s", basicName, - (indexingType & MayHaveIndexedAccessors) ? "|MayHaveIndexedAccessors" : ""); - - return result; + out.printf("%s%s", basicName, (indexingType & MayHaveIndexedAccessors) ? "|MayHaveIndexedAccessors" : ""); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/IndexingType.h b/Source/JavaScriptCore/runtime/IndexingType.h index ab253be1e..dc5684b5f 100644 --- a/Source/JavaScriptCore/runtime/IndexingType.h +++ b/Source/JavaScriptCore/runtime/IndexingType.h @@ -34,27 +34,27 @@ namespace JSC { typedef uint8_t IndexingType; // Flags for testing the presence of capabilities. -static const IndexingType IsArray = 1; +static const IndexingType IsArray = 0x01; // The shape of the indexed property storage. -static const IndexingType IndexingShapeMask = 30; -static const IndexingType NoIndexingShape = 0; -static const IndexingType UndecidedShape = 2; // Only useful for arrays. -static const IndexingType Int32Shape = 20; -static const IndexingType DoubleShape = 22; -static const IndexingType ContiguousShape = 26; -static const IndexingType ArrayStorageShape = 28; -static const IndexingType SlowPutArrayStorageShape = 30; +static const IndexingType IndexingShapeMask = 0x1E; +static const IndexingType NoIndexingShape = 0x00; +static const IndexingType UndecidedShape = 0x02; // Only useful for arrays. +static const IndexingType Int32Shape = 0x14; +static const IndexingType DoubleShape = 0x16; +static const IndexingType ContiguousShape = 0x1A; +static const IndexingType ArrayStorageShape = 0x1C; +static const IndexingType SlowPutArrayStorageShape = 0x1E; static const IndexingType IndexingShapeShift = 1; static const IndexingType NumberOfIndexingShapes = 16; // Additional flags for tracking the history of the type. These are usually // masked off unless you ask for them directly. -static const IndexingType MayHaveIndexedAccessors = 32; +static const IndexingType MayHaveIndexedAccessors = 0x20; // List of acceptable array types. -static const IndexingType NonArray = 0; +static const IndexingType NonArray = 0x0; static const IndexingType NonArrayWithInt32 = Int32Shape; static const IndexingType NonArrayWithDouble = DoubleShape; static const IndexingType NonArrayWithContiguous = ContiguousShape; @@ -149,7 +149,8 @@ IndexingType leastUpperBoundOfIndexingTypes(IndexingType, IndexingType); IndexingType leastUpperBoundOfIndexingTypeAndType(IndexingType, SpeculatedType); IndexingType leastUpperBoundOfIndexingTypeAndValue(IndexingType, JSValue); -const char* indexingTypeToString(IndexingType); +void dumpIndexingType(PrintStream&, IndexingType); +MAKE_PRINT_ADAPTOR(IndexingTypeDump, IndexingType, dumpIndexingType); // Mask of all possible types. static const IndexingType AllArrayTypes = 31; diff --git a/Source/JavaScriptCore/runtime/InternalFunction.cpp b/Source/JavaScriptCore/runtime/InternalFunction.cpp index afb5e6317..071babc46 100644 --- a/Source/JavaScriptCore/runtime/InternalFunction.cpp +++ b/Source/JavaScriptCore/runtime/InternalFunction.cpp @@ -26,6 +26,7 @@ #include "FunctionPrototype.h" #include "JSGlobalObject.h" #include "JSString.h" +#include "Operations.h" namespace JSC { @@ -34,26 +35,26 @@ ASSERT_HAS_TRIVIAL_DESTRUCTOR(InternalFunction); const ClassInfo InternalFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(InternalFunction) }; InternalFunction::InternalFunction(JSGlobalObject* globalObject, Structure* structure) - : JSDestructibleObject(globalObject->globalData(), structure) + : JSDestructibleObject(globalObject->vm(), structure) { } -void InternalFunction::finishCreation(JSGlobalData& globalData, const String& name) +void InternalFunction::finishCreation(VM& vm, const String& name) { - Base::finishCreation(globalData); + Base::finishCreation(vm); ASSERT(inherits(&s_info)); ASSERT(methodTable()->getCallData != InternalFunction::s_info.methodTable.getCallData); - putDirect(globalData, globalData.propertyNames->name, jsString(&globalData, name), DontDelete | ReadOnly | DontEnum); + putDirect(vm, vm.propertyNames->name, jsString(&vm, name), DontDelete | ReadOnly | DontEnum); } const String& InternalFunction::name(ExecState* exec) { - return asString(getDirect(exec->globalData(), exec->globalData().propertyNames->name))->tryGetValue(); + return asString(getDirect(exec->vm(), exec->vm().propertyNames->name))->tryGetValue(); } const String InternalFunction::displayName(ExecState* exec) { - JSValue displayName = getDirect(exec->globalData(), exec->globalData().propertyNames->displayName); + JSValue displayName = getDirect(exec->vm(), exec->vm().propertyNames->displayName); if (displayName && isJSString(displayName)) return asString(displayName)->tryGetValue(); @@ -63,7 +64,7 @@ const String InternalFunction::displayName(ExecState* exec) CallType InternalFunction::getCallData(JSCell*, CallData&) { - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return CallTypeNone; } diff --git a/Source/JavaScriptCore/runtime/InternalFunction.h b/Source/JavaScriptCore/runtime/InternalFunction.h index daeebc34d..e35f5f9f2 100644 --- a/Source/JavaScriptCore/runtime/InternalFunction.h +++ b/Source/JavaScriptCore/runtime/InternalFunction.h @@ -41,9 +41,9 @@ namespace JSC { const String displayName(ExecState*); const String calculatedDisplayName(ExecState*); - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { - return Structure::create(globalData, globalObject, proto, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), &s_info); } protected: @@ -51,7 +51,7 @@ namespace JSC { JS_EXPORT_PRIVATE InternalFunction(JSGlobalObject*, Structure*); - JS_EXPORT_PRIVATE void finishCreation(JSGlobalData&, const String& name); + JS_EXPORT_PRIVATE void finishCreation(VM&, const String& name); static CallType getCallData(JSCell*, CallData&); }; diff --git a/Source/JavaScriptCore/runtime/Intrinsic.h b/Source/JavaScriptCore/runtime/Intrinsic.h index 73244e7c7..313826edb 100644 --- a/Source/JavaScriptCore/runtime/Intrinsic.h +++ b/Source/JavaScriptCore/runtime/Intrinsic.h @@ -47,6 +47,8 @@ enum Intrinsic { LogIntrinsic, RegExpExecIntrinsic, RegExpTestIntrinsic, + StringPrototypeValueOfIntrinsic, + IMulIntrinsic }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h b/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h index 21d7b215c..f0910951b 100644 --- a/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h +++ b/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h @@ -23,8 +23,8 @@ #ifndef JSAPIValueWrapper_h #define JSAPIValueWrapper_h +#include "JSCJSValue.h" #include "JSCell.h" -#include "JSValue.h" #include "CallFrame.h" #include "Structure.h" @@ -37,9 +37,9 @@ namespace JSC { JSValue value() const { return m_value.get(); } - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(APIValueWrapperType, OverridesVisitChildren | OverridesGetPropertyNames), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(APIValueWrapperType, OverridesVisitChildren | OverridesGetPropertyNames), &s_info); } static JS_EXPORTDATA const ClassInfo s_info; @@ -54,14 +54,14 @@ namespace JSC { protected: void finishCreation(ExecState* exec, JSValue value) { - Base::finishCreation(exec->globalData()); - m_value.set(exec->globalData(), this, value); + Base::finishCreation(exec->vm()); + m_value.set(exec->vm(), this, value); ASSERT(!value.isCell()); } private: JSAPIValueWrapper(ExecState* exec) - : JSCell(exec->globalData(), exec->globalData().apiWrapperStructure.get()) + : JSCell(exec->vm(), exec->vm().apiWrapperStructure.get()) { } diff --git a/Source/JavaScriptCore/runtime/JSActivation.cpp b/Source/JavaScriptCore/runtime/JSActivation.cpp index 3b665962f..3a3bb50af 100644 --- a/Source/JavaScriptCore/runtime/JSActivation.cpp +++ b/Source/JavaScriptCore/runtime/JSActivation.cpp @@ -32,6 +32,7 @@ #include "Arguments.h" #include "Interpreter.h" #include "JSFunction.h" +#include "Operations.h" using namespace std; @@ -85,7 +86,7 @@ inline bool JSActivation::symbolTableGet(PropertyName propertyName, PropertyDesc inline bool JSActivation::symbolTablePut(ExecState* exec, PropertyName propertyName, JSValue value, bool shouldThrow) { - JSGlobalData& globalData = exec->globalData(); + VM& vm = exec->vm(); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.publicName()); @@ -101,7 +102,7 @@ inline bool JSActivation::symbolTablePut(ExecState* exec, PropertyName propertyN if (isTornOff() && !isValid(entry)) return false; - registerAt(entry.getIndex()).set(globalData, this, value); + registerAt(entry.getIndex()).set(vm, this, value); return true; } @@ -124,7 +125,7 @@ void JSActivation::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode); } -inline bool JSActivation::symbolTablePutWithAttributes(JSGlobalData& globalData, PropertyName propertyName, JSValue value, unsigned attributes) +inline bool JSActivation::symbolTablePutWithAttributes(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes) { ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); @@ -137,7 +138,7 @@ inline bool JSActivation::symbolTablePutWithAttributes(JSGlobalData& globalData, return false; entry.setAttributes(attributes); - registerAt(entry.getIndex()).set(globalData, this, value); + registerAt(entry.getIndex()).set(vm, this, value); return true; } @@ -156,8 +157,8 @@ bool JSActivation::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyNam if (thisObject->symbolTableGet(propertyName, slot)) return true; - if (WriteBarrierBase<Unknown>* location = thisObject->getDirectLocation(exec->globalData(), propertyName)) { - slot.setValue(location->get()); + if (JSValue value = thisObject->getDirect(exec->vm(), propertyName)) { + slot.setValue(value); return true; } @@ -200,7 +201,7 @@ void JSActivation::put(JSCell* cell, ExecState* exec, PropertyName propertyName, // properties are non-standard extensions that other implementations do not // expose in the activation object. ASSERT(!thisObject->hasGetterSetterProperties()); - thisObject->putOwnDataProperty(exec->globalData(), propertyName, value, slot); + thisObject->putOwnDataProperty(exec->vm(), propertyName, value, slot); } // FIXME: Make this function honor ReadOnly (const) and DontEnum @@ -209,7 +210,7 @@ void JSActivation::putDirectVirtual(JSObject* object, ExecState* exec, PropertyN JSActivation* thisObject = jsCast<JSActivation*>(object); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); - if (thisObject->symbolTablePutWithAttributes(exec->globalData(), propertyName, value, attributes)) + if (thisObject->symbolTablePutWithAttributes(exec->vm(), propertyName, value, attributes)) return; // We don't call through to JSObject because __proto__ and getter/setter @@ -244,7 +245,7 @@ JSValue JSActivation::argumentsGetter(ExecState*, JSValue slotBase, PropertyName return arguments; int realArgumentsRegister = unmodifiedArgumentsRegister(argumentsRegister); - JSValue arguments = JSValue(Arguments::create(callFrame->globalData(), callFrame)); + JSValue arguments = JSValue(Arguments::create(callFrame->vm(), callFrame)); callFrame->uncheckedR(argumentsRegister) = arguments; callFrame->uncheckedR(realArgumentsRegister) = arguments; diff --git a/Source/JavaScriptCore/runtime/JSActivation.h b/Source/JavaScriptCore/runtime/JSActivation.h index b8f5621af..dfbc0c134 100644 --- a/Source/JavaScriptCore/runtime/JSActivation.h +++ b/Source/JavaScriptCore/runtime/JSActivation.h @@ -41,22 +41,22 @@ namespace JSC { class JSActivation : public JSVariableObject { private: - JSActivation(JSGlobalData& globalData, CallFrame*, SharedSymbolTable*); + JSActivation(VM& vm, CallFrame*, SharedSymbolTable*); public: typedef JSVariableObject Base; - static JSActivation* create(JSGlobalData& globalData, CallFrame* callFrame, CodeBlock* codeBlock) + static JSActivation* create(VM& vm, CallFrame* callFrame, CodeBlock* codeBlock) { SharedSymbolTable* symbolTable = codeBlock->symbolTable(); JSActivation* activation = new ( NotNull, allocateCell<JSActivation>( - globalData.heap, + vm.heap, allocationSize(symbolTable) ) - ) JSActivation(globalData, callFrame, symbolTable); - activation->finishCreation(globalData); + ) JSActivation(vm, callFrame, symbolTable); + activation->finishCreation(vm); return activation; } @@ -75,11 +75,11 @@ namespace JSC { static JSObject* toThisObject(JSCell*, ExecState*); - void tearOff(JSGlobalData&); + void tearOff(VM&); static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(ActivationObjectType, StructureFlags), &s_info); } + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(ActivationObjectType, StructureFlags), &s_info); } WriteBarrierBase<Unknown>& registerAt(int) const; bool isValidIndex(int) const; @@ -96,7 +96,7 @@ namespace JSC { bool symbolTableGet(PropertyName, PropertyDescriptor&); bool symbolTableGet(PropertyName, PropertySlot&, bool& slotIsWriteable); bool symbolTablePut(ExecState*, PropertyName, JSValue, bool shouldThrow); - bool symbolTablePutWithAttributes(JSGlobalData&, PropertyName, JSValue, unsigned attributes); + bool symbolTablePutWithAttributes(VM&, PropertyName, JSValue, unsigned attributes); static JSValue argumentsGetter(ExecState*, JSValue, PropertyName); NEVER_INLINE PropertySlot::GetValueFunc getArgumentsGetter(); @@ -110,9 +110,9 @@ namespace JSC { extern int activationCount; extern int allTheThingsCount; - inline JSActivation::JSActivation(JSGlobalData& globalData, CallFrame* callFrame, SharedSymbolTable* symbolTable) + inline JSActivation::JSActivation(VM& vm, CallFrame* callFrame, SharedSymbolTable* symbolTable) : Base( - globalData, + vm, callFrame->lexicalGlobalObject()->activationStructure(), callFrame->registers(), callFrame->scope(), @@ -149,17 +149,17 @@ namespace JSC { return storageOffset() - (symbolTable->captureStart() * sizeof(WriteBarrier<Unknown>)); } - inline void JSActivation::tearOff(JSGlobalData& globalData) + inline void JSActivation::tearOff(VM& vm) { ASSERT(!isTornOff()); - WriteBarrierBase<Unknown>* dst = reinterpret_cast<WriteBarrierBase<Unknown>*>( + WriteBarrierBase<Unknown>* dst = reinterpret_cast_ptr<WriteBarrierBase<Unknown>*>( reinterpret_cast<char*>(this) + registersOffset(symbolTable())); WriteBarrierBase<Unknown>* src = m_registers; int captureEnd = symbolTable()->captureEnd(); for (int i = symbolTable()->captureStart(); i < captureEnd; ++i) - dst[i].set(globalData, this, src[i].get()); + dst[i].set(vm, this, src[i].get()); m_registers = dst; ASSERT(isTornOff()); @@ -167,7 +167,7 @@ namespace JSC { inline bool JSActivation::isTornOff() { - return m_registers == reinterpret_cast<WriteBarrierBase<Unknown>*>( + return m_registers == reinterpret_cast_ptr<WriteBarrierBase<Unknown>*>( reinterpret_cast<char*>(this) + registersOffset(symbolTable())); } @@ -178,7 +178,7 @@ namespace JSC { inline WriteBarrier<Unknown>* JSActivation::storage() { - return reinterpret_cast<WriteBarrier<Unknown>*>( + return reinterpret_cast_ptr<WriteBarrier<Unknown>*>( reinterpret_cast<char*>(this) + storageOffset()); } diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp index c742804f7..f97ccedcd 100644 --- a/Source/JavaScriptCore/runtime/JSArray.cpp +++ b/Source/JavaScriptCore/runtime/JSArray.cpp @@ -48,10 +48,10 @@ ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSArray); const ClassInfo JSArray::s_info = {"Array", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSArray)}; -Butterfly* createArrayButterflyInDictionaryIndexingMode(JSGlobalData& globalData, unsigned initialLength) +Butterfly* createArrayButterflyInDictionaryIndexingMode(VM& vm, unsigned initialLength) { Butterfly* butterfly = Butterfly::create( - globalData, 0, 0, true, IndexingHeader(), ArrayStorage::sizeFor(0)); + vm, 0, 0, true, IndexingHeader(), ArrayStorage::sizeFor(0)); ArrayStorage* storage = butterfly->arrayStorage(); storage->setLength(initialLength); storage->setVectorLength(0); @@ -67,7 +67,7 @@ void JSArray::setLengthWritable(ExecState* exec, bool writable) if (!isLengthWritable() || writable) return; - enterDictionaryIndexingMode(exec->globalData()); + enterDictionaryIndexingMode(exec->vm()); SparseArrayValueMap* map = arrayStorage()->m_sparseMap.get(); ASSERT(map); @@ -244,9 +244,9 @@ void JSArray::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, Pro } // This method makes room in the vector, but leaves the new space for count slots uncleared. -bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, bool addToFront, unsigned count) +bool JSArray::unshiftCountSlowCase(VM& vm, bool addToFront, unsigned count) { - ArrayStorage* storage = ensureArrayStorage(globalData); + ArrayStorage* storage = ensureArrayStorage(vm); Butterfly* butterfly = storage->butterfly(); unsigned propertyCapacity = structure()->outOfLineCapacity(); unsigned propertySize = structure()->outOfLineSize(); @@ -286,7 +286,7 @@ bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, bool addToFront, un newStorageCapacity = currentCapacity; } else { size_t newSize = Butterfly::totalSize(0, propertyCapacity, true, ArrayStorage::sizeFor(desiredCapacity)); - if (!globalData.heap.tryAllocateStorage(newSize, &newAllocBase)) + if (!vm.heap.tryAllocateStorage(newSize, &newAllocBase)) return false; newStorageCapacity = desiredCapacity; } @@ -349,8 +349,8 @@ bool JSArray::setLengthWithArrayStorage(ExecState* exec, unsigned newLength, boo if (newLength < length) { // Copy any keys we might be interested in into a vector. - Vector<unsigned> keys; - keys.reserveCapacity(min(map->size(), static_cast<size_t>(length - newLength))); + Vector<unsigned, 0, UnsafeVectorOverflow> keys; + keys.reserveInitialCapacity(min(map->size(), static_cast<size_t>(length - newLength))); SparseArrayValueMap::const_iterator end = map->end(); for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) { unsigned index = static_cast<unsigned>(it->key); @@ -408,9 +408,9 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException if (newLength >= MIN_SPARSE_ARRAY_INDEX) { return setLengthWithArrayStorage( exec, newLength, throwException, - convertContiguousToArrayStorage(exec->globalData())); + convertContiguousToArrayStorage(exec->vm())); } - createInitialUndecided(exec->globalData(), newLength); + createInitialUndecided(exec->vm(), newLength); return true; case ArrayWithUndecided: @@ -424,10 +424,10 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException && !isDenseEnoughForVector(newLength, countElements()))) { return setLengthWithArrayStorage( exec, newLength, throwException, - ensureArrayStorage(exec->globalData())); + ensureArrayStorage(exec->vm())); } if (newLength > m_butterfly->publicLength()) { - ensureLength(exec->globalData(), newLength); + ensureLength(exec->vm(), newLength); return true; } if (structure()->indexingType() == ArrayWithDouble) { @@ -469,7 +469,7 @@ JSValue JSArray::pop(ExecState* exec) if (!length--) return jsUndefined(); - ASSERT(length < m_butterfly->vectorLength()); + RELEASE_ASSERT(length < m_butterfly->vectorLength()); JSValue value = m_butterfly->contiguous()[length].get(); if (value) { m_butterfly->contiguous()[length].clear(); @@ -485,7 +485,7 @@ JSValue JSArray::pop(ExecState* exec) if (!length--) return jsUndefined(); - ASSERT(length < m_butterfly->vectorLength()); + RELEASE_ASSERT(length < m_butterfly->vectorLength()); double value = m_butterfly->contiguousDouble()[length]; if (value == value) { m_butterfly->contiguousDouble()[length] = QNaN; @@ -513,7 +513,7 @@ JSValue JSArray::pop(ExecState* exec) JSValue element = valueSlot.get(); valueSlot.clear(); - ASSERT(isLengthWritable()); + RELEASE_ASSERT(isLengthWritable()); storage->setLength(index); return element; } @@ -549,19 +549,19 @@ void JSArray::push(ExecState* exec, JSValue value) { switch (structure()->indexingType()) { case ArrayClass: { - createInitialUndecided(exec->globalData(), 0); + createInitialUndecided(exec->vm(), 0); // Fall through. } case ArrayWithUndecided: { - convertUndecidedForValue(exec->globalData(), value); + convertUndecidedForValue(exec->vm(), value); push(exec, value); return; } case ArrayWithInt32: { if (!value.isInt32()) { - convertInt32ForValue(exec->globalData(), value); + convertInt32ForValue(exec->vm(), value); push(exec, value); return; } @@ -589,7 +589,7 @@ void JSArray::push(ExecState* exec, JSValue value) unsigned length = m_butterfly->publicLength(); ASSERT(length <= m_butterfly->vectorLength()); if (length < m_butterfly->vectorLength()) { - m_butterfly->contiguous()[length].set(exec->globalData(), this, value); + m_butterfly->contiguous()[length].set(exec->vm(), this, value); m_butterfly->setPublicLength(length + 1); return; } @@ -607,13 +607,13 @@ void JSArray::push(ExecState* exec, JSValue value) case ArrayWithDouble: { if (!value.isNumber()) { - convertDoubleToContiguous(exec->globalData()); + convertDoubleToContiguous(exec->vm()); push(exec, value); return; } double valueAsDouble = value.asNumber(); if (valueAsDouble != valueAsDouble) { - convertDoubleToContiguous(exec->globalData()); + convertDoubleToContiguous(exec->vm()); push(exec, value); return; } @@ -653,7 +653,7 @@ void JSArray::push(ExecState* exec, JSValue value) // Fast case - push within vector, always update m_length & m_numValuesInVector. unsigned length = storage->length(); if (length < storage->vectorLength()) { - storage->m_vector[length].set(exec->globalData(), this, value); + storage->m_vector[length].set(exec->vm(), this, value); storage->setLength(length + 1); ++storage->m_numValuesInVector; return; @@ -674,14 +674,14 @@ void JSArray::push(ExecState* exec, JSValue value) } default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } } bool JSArray::shiftCountWithArrayStorage(unsigned startIndex, unsigned count, ArrayStorage* storage) { unsigned oldLength = storage->length(); - ASSERT(count <= oldLength); + RELEASE_ASSERT(count <= oldLength); // If the array contains holes or is otherwise in an abnormal state, // use the generic algorithm in ArrayPrototype. @@ -736,7 +736,7 @@ bool JSArray::shiftCountWithArrayStorage(unsigned startIndex, unsigned count, Ar bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex, unsigned count) { - ASSERT(count > 0); + RELEASE_ASSERT(count > 0); switch (structure()->indexingType()) { case ArrayClass: @@ -749,12 +749,12 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex case ArrayWithInt32: case ArrayWithContiguous: { unsigned oldLength = m_butterfly->publicLength(); - ASSERT(count <= oldLength); + RELEASE_ASSERT(count <= oldLength); // We may have to walk the entire array to do the shift. We're willing to do // so only if it's not horribly slow. if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX) - return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData())); + return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm())); unsigned end = oldLength - count; for (unsigned i = startIndex; i < end; ++i) { @@ -768,7 +768,7 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex // about holes (at least for now), but it can detect them quickly. So // we convert to array storage and then allow the array storage path to // figure it out. - return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData())); + return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm())); } // No need for a barrier since we're just moving data around in the same vector. // This is in line with our standing assumption that we won't have a deletion @@ -784,12 +784,12 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex case ArrayWithDouble: { unsigned oldLength = m_butterfly->publicLength(); - ASSERT(count <= oldLength); + RELEASE_ASSERT(count <= oldLength); // We may have to walk the entire array to do the shift. We're willing to do // so only if it's not horribly slow. if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX) - return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData())); + return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm())); unsigned end = oldLength - count; for (unsigned i = startIndex; i < end; ++i) { @@ -803,7 +803,7 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex // about holes (at least for now), but it can detect them quickly. So // we convert to array storage and then allow the array storage path to // figure it out. - return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData())); + return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm())); } // No need for a barrier since we're just moving data around in the same vector. // This is in line with our standing assumption that we won't have a deletion @@ -832,7 +832,7 @@ bool JSArray::unshiftCountWithArrayStorage(ExecState* exec, unsigned startIndex, { unsigned length = storage->length(); - ASSERT(startIndex <= length); + RELEASE_ASSERT(startIndex <= length); // If the array contains holes or is otherwise in an abnormal state, // use the generic algorithm in ArrayPrototype. @@ -850,7 +850,7 @@ bool JSArray::unshiftCountWithArrayStorage(ExecState* exec, unsigned startIndex, storage->setVectorLength(vectorLength + count); } else if (!moveFront && vectorLength - length >= count) storage = storage->butterfly()->arrayStorage(); - else if (unshiftCountSlowCase(exec->globalData(), moveFront, count)) + else if (unshiftCountSlowCase(exec->vm(), moveFront, count)) storage = arrayStorage(); else { throwOutOfMemoryError(exec); @@ -886,14 +886,14 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd // We may have to walk the entire array to do the unshift. We're willing to do so // only if it's not horribly slow. if (oldLength - startIndex >= MIN_SPARSE_ARRAY_INDEX) - return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData())); + return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm())); - ensureLength(exec->globalData(), oldLength + count); + ensureLength(exec->vm(), oldLength + count); for (unsigned i = oldLength; i-- > startIndex;) { JSValue v = m_butterfly->contiguous()[i].get(); if (UNLIKELY(!v)) - return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData())); + return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm())); m_butterfly->contiguous()[i + count].setWithoutWriteBarrier(v); } @@ -911,14 +911,14 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd // We may have to walk the entire array to do the unshift. We're willing to do so // only if it's not horribly slow. if (oldLength - startIndex >= MIN_SPARSE_ARRAY_INDEX) - return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData())); + return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm())); - ensureLength(exec->globalData(), oldLength + count); + ensureLength(exec->vm(), oldLength + count); for (unsigned i = oldLength; i-- > startIndex;) { double v = m_butterfly->contiguousDouble()[i]; if (UNLIKELY(v != v)) - return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData())); + return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm())); m_butterfly->contiguousDouble()[i + count] = v; } @@ -979,7 +979,7 @@ void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallTy lengthNotIncludingUndefined, newRelevantLength); - WriteBarrier<Unknown>* data = indexingData<indexingType>(); + ContiguousJSValues data = indexingData<indexingType>(); if (indexingType == ArrayWithArrayStorage && arrayStorage()->m_sparseMap.get()) { throwOutOfMemoryError(exec); @@ -1026,8 +1026,8 @@ void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallTy compare = compareNumbersForQSort; break; } - - qsort(data, newRelevantLength, sizeof(WriteBarrier<Unknown>), compare); + ASSERT(data.length() >= newRelevantLength); + qsort(data.data(), newRelevantLength, sizeof(WriteBarrier<Unknown>), compare); return; } @@ -1061,20 +1061,47 @@ void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType cal } } -template<IndexingType indexingType> -void JSArray::sortCompactedVector(ExecState* exec, void* begin, unsigned relevantLength) +template <IndexingType> struct ContiguousTypeAccessor { + typedef WriteBarrier<Unknown> Type; + static JSValue getAsValue(ContiguousData<Type> data, size_t i) { return data[i].get(); } + static void setWithValue(VM& vm, JSArray* thisValue, ContiguousData<Type> data, size_t i, JSValue value) + { + data[i].set(vm, thisValue, value); + } + static void replaceDataReference(ContiguousData<Type>* outData, ContiguousJSValues inData) + { + *outData = inData; + } +}; + +template <> struct ContiguousTypeAccessor<ArrayWithDouble> { + typedef double Type; + static JSValue getAsValue(ContiguousData<Type> data, size_t i) { ASSERT(data[i] == data[i]); return JSValue(JSValue::EncodeAsDouble, data[i]); } + static void setWithValue(VM&, JSArray*, ContiguousData<Type> data, size_t i, JSValue value) + { + data[i] = value.asNumber(); + } + static NO_RETURN_DUE_TO_CRASH void replaceDataReference(ContiguousData<Type>*, ContiguousJSValues) + { + RELEASE_ASSERT_WITH_MESSAGE(0, "Inconsistent indexing types during compact array sort."); + } +}; + + +template<IndexingType indexingType, typename StorageType> +void JSArray::sortCompactedVector(ExecState* exec, ContiguousData<StorageType> data, unsigned relevantLength) { if (!relevantLength) return; - JSGlobalData& globalData = exec->globalData(); + VM& vm = exec->vm(); // Converting JavaScript values to strings can be expensive, so we do it once up front and sort based on that. // This is a considerable improvement over doing it twice per comparison, though it requires a large temporary // buffer. Besides, this protects us from crashing if some objects have custom toString methods that return // random or otherwise changing results, effectively making compare function inconsistent. - Vector<ValueStringPair> values(relevantLength); + Vector<ValueStringPair, 0, UnsafeVectorOverflow> values(relevantLength); if (!values.begin()) { throwOutOfMemoryError(exec); return; @@ -1083,31 +1110,14 @@ void JSArray::sortCompactedVector(ExecState* exec, void* begin, unsigned relevan Heap::heap(this)->pushTempSortVector(&values); bool isSortingPrimitiveValues = true; - switch (indexingType) { - case ArrayWithInt32: - for (size_t i = 0; i < relevantLength; i++) { - JSValue value = static_cast<WriteBarrier<Unknown>*>(begin)[i].get(); - ASSERT(value.isInt32()); - values[i].first = value; - } - break; - - case ArrayWithDouble: - for (size_t i = 0; i < relevantLength; i++) { - double value = static_cast<double*>(begin)[i]; - ASSERT(value == value); - values[i].first = JSValue(JSValue::EncodeAsDouble, value); - } - break; - - default: - for (size_t i = 0; i < relevantLength; i++) { - JSValue value = static_cast<WriteBarrier<Unknown>*>(begin)[i].get(); - ASSERT(!value.isUndefined()); - values[i].first = value; + + for (size_t i = 0; i < relevantLength; i++) { + JSValue value = ContiguousTypeAccessor<indexingType>::getAsValue(data, i); + ASSERT(indexingType != ArrayWithInt32 || value.isInt32()); + ASSERT(!value.isUndefined()); + values[i].first = value; + if (indexingType != ArrayWithDouble && indexingType != ArrayWithInt32) isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive(); - } - break; } // FIXME: The following loop continues to call toString on subsequent values even after @@ -1141,13 +1151,13 @@ void JSArray::sortCompactedVector(ExecState* exec, void* begin, unsigned relevan case ArrayWithInt32: case ArrayWithDouble: case ArrayWithContiguous: - ensureLength(globalData, relevantLength); + ensureLength(vm, relevantLength); break; case ArrayWithArrayStorage: if (arrayStorage()->vectorLength() < relevantLength) { - increaseVectorLength(exec->globalData(), relevantLength); - begin = arrayStorage()->m_vector; + increaseVectorLength(exec->vm(), relevantLength); + ContiguousTypeAccessor<indexingType>::replaceDataReference(&data, arrayStorage()->vector()); } if (arrayStorage()->length() < relevantLength) arrayStorage()->setLength(relevantLength); @@ -1157,12 +1167,8 @@ void JSArray::sortCompactedVector(ExecState* exec, void* begin, unsigned relevan CRASH(); } - for (size_t i = 0; i < relevantLength; i++) { - if (indexingType == ArrayWithDouble) - static_cast<double*>(begin)[i] = values[i].first.asNumber(); - else - static_cast<WriteBarrier<Unknown>*>(begin)[i].set(globalData, this, values[i].first); - } + for (size_t i = 0; i < relevantLength; i++) + ContiguousTypeAccessor<indexingType>::setWithValue(vm, this, data, i, values[i].first); Heap::heap(this)->popTempSortVector(&values); } @@ -1217,13 +1223,12 @@ void JSArray::sort(ExecState* exec) ArrayStorage* storage = m_butterfly->arrayStorage(); ASSERT(!storage->m_sparseMap); - sortCompactedVector<ArrayWithArrayStorage>( - exec, storage->m_vector, lengthNotIncludingUndefined); + sortCompactedVector<ArrayWithArrayStorage>(exec, storage->vector(), lengthNotIncludingUndefined); return; } default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } } @@ -1242,7 +1247,7 @@ struct AVLTreeAbstractorForArrayCompare { typedef JSValue key; typedef int32_t size; - Vector<AVLTreeNodeForArrayCompare> m_nodes; + Vector<AVLTreeNodeForArrayCompare, 0, UnsafeVectorOverflow> m_nodes; ExecState* m_exec; JSValue m_compareFunction; CallType m_compareCallType; @@ -1382,13 +1387,13 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call // Copy the values back into m_storage. AVLTree<AVLTreeAbstractorForArrayCompare, 44>::Iterator iter; iter.start_iter_least(tree); - JSGlobalData& globalData = exec->globalData(); + VM& vm = exec->vm(); for (unsigned i = 0; i < elementsToExtractThreshold; ++i) { ASSERT(i < butterfly()->vectorLength()); if (structure()->indexingType() == ArrayWithDouble) butterfly()->contiguousDouble()[i] = tree.abstractor().m_nodes[*iter].value.asNumber(); else - currentIndexingData()[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value); + currentIndexingData()[i].set(vm, this, tree.abstractor().m_nodes[*iter].value); ++iter; } // Put undefined values back in. @@ -1444,7 +1449,7 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, return; default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } } @@ -1467,7 +1472,7 @@ void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args) case ArrayWithInt32: case ArrayWithContiguous: { vectorEnd = m_butterfly->publicLength(); - vector = m_butterfly->contiguous(); + vector = m_butterfly->contiguous().data(); break; } @@ -1528,7 +1533,7 @@ void JSArray::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t le case ArrayWithInt32: case ArrayWithContiguous: { - vector = m_butterfly->contiguous(); + vector = m_butterfly->contiguous().data(); vectorEnd = m_butterfly->publicLength(); break; } @@ -1635,12 +1640,12 @@ void JSArray::compactForSorting(unsigned& numDefined, unsigned& newRelevantLengt newRelevantLength = numDefined + numUndefined; if (hasArrayStorage(indexingType)) - ASSERT(!arrayStorage()->m_sparseMap); + RELEASE_ASSERT(!arrayStorage()->m_sparseMap); switch (indexingType) { case ArrayWithInt32: case ArrayWithDouble: - ASSERT(numDefined == newRelevantLength); + RELEASE_ASSERT(numDefined == newRelevantLength); break; default: diff --git a/Source/JavaScriptCore/runtime/JSArray.h b/Source/JavaScriptCore/runtime/JSArray.h index cef3b53ad..af81d2e3f 100644 --- a/Source/JavaScriptCore/runtime/JSArray.h +++ b/Source/JavaScriptCore/runtime/JSArray.h @@ -39,19 +39,19 @@ public: typedef JSNonFinalObject Base; protected: - explicit JSArray(JSGlobalData& globalData, Structure* structure, Butterfly* butterfly) - : JSNonFinalObject(globalData, structure, butterfly) + explicit JSArray(VM& vm, Structure* structure, Butterfly* butterfly) + : JSNonFinalObject(vm, structure, butterfly) { } public: - static JSArray* create(JSGlobalData&, Structure*, unsigned initialLength = 0); + static JSArray* create(VM&, Structure*, unsigned initialLength = 0); // tryCreateUninitialized is used for fast construction of arrays whose size and // contents are known at time of creation. Clients of this interface must: // - null-check the result (indicating out of memory, or otherwise unable to allocate vector). // - call 'initializeIndex' for all properties in sequence, for 0 <= i < initialLength. - static JSArray* tryCreateUninitialized(JSGlobalData&, Structure*, unsigned initialLength); + static JSArray* tryCreateUninitialized(VM&, Structure*, unsigned initialLength); JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool throwException); @@ -84,7 +84,7 @@ public: bool shiftCountForShift(ExecState* exec, unsigned startIndex, unsigned count) { - return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData())); + return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm())); } bool shiftCountForSplice(ExecState* exec, unsigned startIndex, unsigned count) { @@ -106,7 +106,7 @@ public: bool unshiftCountForShift(ExecState* exec, unsigned startIndex, unsigned count) { - return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData())); + return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm())); } bool unshiftCountForSplice(ExecState* exec, unsigned startIndex, unsigned count) { @@ -129,9 +129,9 @@ public: void fillArgList(ExecState*, MarkedArgumentBuffer&); void copyToArguments(ExecState*, CallFrame*, uint32_t length); - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, IndexingType indexingType) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, IndexingType indexingType) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info, indexingType); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info, indexingType); } protected: @@ -156,13 +156,13 @@ private: bool unshiftCountWithAnyIndexingType(ExecState*, unsigned startIndex, unsigned count); bool unshiftCountWithArrayStorage(ExecState*, unsigned startIndex, unsigned count, ArrayStorage*); - bool unshiftCountSlowCase(JSGlobalData&, bool, unsigned); + bool unshiftCountSlowCase(VM&, bool, unsigned); template<IndexingType indexingType> void sortNumericVector(ExecState*, JSValue compareFunction, CallType, const CallData&); - template<IndexingType indexingType> - void sortCompactedVector(ExecState*, void* begin, unsigned relevantLength); + template<IndexingType indexingType, typename StorageType> + void sortCompactedVector(ExecState*, ContiguousData<StorageType>, unsigned relevantLength); template<IndexingType indexingType> void sortVector(ExecState*, JSValue compareFunction, CallType, const CallData&); @@ -174,21 +174,21 @@ private: void compactForSorting(unsigned& numDefined, unsigned& newRelevantLength); }; -inline Butterfly* createContiguousArrayButterfly(JSGlobalData& globalData, unsigned length, unsigned& vectorLength) +inline Butterfly* createContiguousArrayButterfly(VM& vm, unsigned length, unsigned& vectorLength) { IndexingHeader header; vectorLength = std::max(length, BASE_VECTOR_LEN); header.setVectorLength(vectorLength); header.setPublicLength(length); Butterfly* result = Butterfly::create( - globalData, 0, 0, true, header, vectorLength * sizeof(EncodedJSValue)); + vm, 0, 0, true, header, vectorLength * sizeof(EncodedJSValue)); return result; } -inline Butterfly* createArrayButterfly(JSGlobalData& globalData, unsigned initialLength) +inline Butterfly* createArrayButterfly(VM& vm, unsigned initialLength) { Butterfly* butterfly = Butterfly::create( - globalData, 0, 0, true, baseIndexingHeaderForArray(initialLength), ArrayStorage::sizeFor(BASE_VECTOR_LEN)); + vm, 0, 0, true, baseIndexingHeaderForArray(initialLength), ArrayStorage::sizeFor(BASE_VECTOR_LEN)); ArrayStorage* storage = butterfly->arrayStorage(); storage->m_indexBias = 0; storage->m_sparseMap.clear(); @@ -196,9 +196,9 @@ inline Butterfly* createArrayButterfly(JSGlobalData& globalData, unsigned initia return butterfly; } -Butterfly* createArrayButterflyInDictionaryIndexingMode(JSGlobalData&, unsigned initialLength); +Butterfly* createArrayButterflyInDictionaryIndexingMode(VM&, unsigned initialLength); -inline JSArray* JSArray::create(JSGlobalData& globalData, Structure* structure, unsigned initialLength) +inline JSArray* JSArray::create(VM& vm, Structure* structure, unsigned initialLength) { Butterfly* butterfly; if (LIKELY(!hasArrayStorage(structure->indexingType()))) { @@ -208,7 +208,7 @@ inline JSArray* JSArray::create(JSGlobalData& globalData, Structure* structure, || hasDouble(structure->indexingType()) || hasContiguous(structure->indexingType())); unsigned vectorLength; - butterfly = createContiguousArrayButterfly(globalData, initialLength, vectorLength); + butterfly = createContiguousArrayButterfly(vm, initialLength, vectorLength); ASSERT(initialLength < MIN_SPARSE_ARRAY_INDEX); if (hasDouble(structure->indexingType())) { for (unsigned i = 0; i < vectorLength; ++i) @@ -218,14 +218,14 @@ inline JSArray* JSArray::create(JSGlobalData& globalData, Structure* structure, ASSERT( structure->indexingType() == ArrayWithSlowPutArrayStorage || structure->indexingType() == ArrayWithArrayStorage); - butterfly = createArrayButterfly(globalData, initialLength); + butterfly = createArrayButterfly(vm, initialLength); } - JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure, butterfly); - array->finishCreation(globalData); + JSArray* array = new (NotNull, allocateCell<JSArray>(vm.heap)) JSArray(vm, structure, butterfly); + array->finishCreation(vm); return array; } -inline JSArray* JSArray::tryCreateUninitialized(JSGlobalData& globalData, Structure* structure, unsigned initialLength) +inline JSArray* JSArray::tryCreateUninitialized(VM& vm, Structure* structure, unsigned initialLength) { unsigned vectorLength = std::max(BASE_VECTOR_LEN, initialLength); if (vectorLength > MAX_STORAGE_VECTOR_LENGTH) @@ -240,7 +240,7 @@ inline JSArray* JSArray::tryCreateUninitialized(JSGlobalData& globalData, Struct || hasContiguous(structure->indexingType())); void* temp; - if (!globalData.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, vectorLength * sizeof(EncodedJSValue)), &temp)) + if (!vm.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, vectorLength * sizeof(EncodedJSValue)), &temp)) return 0; butterfly = Butterfly::fromBase(temp, 0, 0); butterfly->setVectorLength(vectorLength); @@ -251,7 +251,7 @@ inline JSArray* JSArray::tryCreateUninitialized(JSGlobalData& globalData, Struct } } else { void* temp; - if (!globalData.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, ArrayStorage::sizeFor(vectorLength)), &temp)) + if (!vm.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, ArrayStorage::sizeFor(vectorLength)), &temp)) return 0; butterfly = Butterfly::fromBase(temp, 0, 0); *butterfly->indexingHeader() = indexingHeaderForArray(initialLength, vectorLength); @@ -261,8 +261,8 @@ inline JSArray* JSArray::tryCreateUninitialized(JSGlobalData& globalData, Struct storage->m_numValuesInVector = initialLength; } - JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure, butterfly); - array->finishCreation(globalData); + JSArray* array = new (NotNull, allocateCell<JSArray>(vm.heap)) JSArray(vm, structure, butterfly); + array->finishCreation(vm); return array; } @@ -284,34 +284,32 @@ inline bool isJSArray(JSValue v) { return v.isCell() && isJSArray(v.asCell()); } inline JSArray* constructArray(ExecState* exec, Structure* arrayStructure, const ArgList& values) { - JSGlobalData& globalData = exec->globalData(); + VM& vm = exec->vm(); unsigned length = values.size(); - JSArray* array = JSArray::tryCreateUninitialized(globalData, arrayStructure, length); + JSArray* array = JSArray::tryCreateUninitialized(vm, arrayStructure, length); // FIXME: we should probably throw an out of memory error here, but // when making this change we should check that all clients of this // function will correctly handle an exception being thrown from here. - if (!array) - CRASH(); + RELEASE_ASSERT(array); for (unsigned i = 0; i < length; ++i) - array->initializeIndex(globalData, i, values.at(i)); + array->initializeIndex(vm, i, values.at(i)); return array; } inline JSArray* constructArray(ExecState* exec, Structure* arrayStructure, const JSValue* values, unsigned length) { - JSGlobalData& globalData = exec->globalData(); - JSArray* array = JSArray::tryCreateUninitialized(globalData, arrayStructure, length); + VM& vm = exec->vm(); + JSArray* array = JSArray::tryCreateUninitialized(vm, arrayStructure, length); // FIXME: we should probably throw an out of memory error here, but // when making this change we should check that all clients of this // function will correctly handle an exception being thrown from here. - if (!array) - CRASH(); + RELEASE_ASSERT(array); for (unsigned i = 0; i < length; ++i) - array->initializeIndex(globalData, i, values[i]); + array->initializeIndex(vm, i, values[i]); return array; } diff --git a/Source/JavaScriptCore/runtime/JSBoundFunction.cpp b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp index bb1af9d20..fb255d954 100644 --- a/Source/JavaScriptCore/runtime/JSBoundFunction.cpp +++ b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp @@ -28,6 +28,7 @@ #include "GetterSetter.h" #include "JSGlobalObject.h" +#include "Operations.h" namespace JSC { @@ -78,8 +79,7 @@ JSBoundFunction* JSBoundFunction::create(ExecState* exec, JSGlobalObject* global ConstructData constructData; ConstructType constructType = JSC::getConstructData(targetFunction, constructData); bool canConstruct = constructType != ConstructTypeNone; - - NativeExecutable* executable = exec->globalData().getHostFunction(boundFunctionCall, canConstruct ? boundFunctionConstruct : callHostFunctionAsConstructor); + NativeExecutable* executable = exec->vm().getHostFunction(boundFunctionCall, canConstruct ? boundFunctionConstruct : callHostFunctionAsConstructor); JSBoundFunction* function = new (NotNull, allocateCell<JSBoundFunction>(*exec->heap())) JSBoundFunction(exec, globalObject, globalObject->boundFunctionStructure(), targetFunction, boundThis, boundArgs); function->finishCreation(exec, executable, length, name); @@ -98,9 +98,9 @@ bool JSBoundFunction::customHasInstance(JSObject* object, ExecState* exec, JSVal JSBoundFunction::JSBoundFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs) : Base(exec, globalObject, structure) - , m_targetFunction(exec->globalData(), this, targetFunction) - , m_boundThis(exec->globalData(), this, boundThis) - , m_boundArgs(exec->globalData(), this, boundArgs) + , m_targetFunction(exec->vm(), this, targetFunction) + , m_boundThis(exec->vm(), this, boundThis) + , m_boundArgs(exec->vm(), this, boundArgs) { } diff --git a/Source/JavaScriptCore/runtime/JSBoundFunction.h b/Source/JavaScriptCore/runtime/JSBoundFunction.h index 886021940..3378d4048 100644 --- a/Source/JavaScriptCore/runtime/JSBoundFunction.h +++ b/Source/JavaScriptCore/runtime/JSBoundFunction.h @@ -47,10 +47,10 @@ public: JSValue boundThis() { return m_boundThis.get(); } JSValue boundArgs() { return m_boundArgs.get(); } - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { ASSERT(globalObject); - return Structure::create(globalData, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), &s_info); } static const ClassInfo s_info; diff --git a/Source/JavaScriptCore/runtime/JSValue.cpp b/Source/JavaScriptCore/runtime/JSCJSValue.cpp index d9253730f..627e9e077 100644 --- a/Source/JavaScriptCore/runtime/JSValue.cpp +++ b/Source/JavaScriptCore/runtime/JSCJSValue.cpp @@ -21,15 +21,16 @@ */ #include "config.h" -#include "JSValue.h" +#include "JSCJSValue.h" #include "BooleanConstructor.h" #include "BooleanPrototype.h" #include "Error.h" #include "ExceptionHelpers.h" #include "GetterSetter.h" -#include "JSGlobalObject.h" +#include "JSCJSValueInlines.h" #include "JSFunction.h" +#include "JSGlobalObject.h" #include "JSNotAnObject.h" #include "NumberObject.h" #include <wtf/MathExtras.h> @@ -45,7 +46,7 @@ double JSValue::toInteger(ExecState* exec) const if (isInt32()) return asInt32(); double d = toNumber(exec); - return isnan(d) ? 0.0 : trunc(d); + return std::isnan(d) ? 0.0 : trunc(d); } double JSValue::toIntegerPreserveNaN(ExecState* exec) const @@ -111,7 +112,7 @@ JSObject* JSValue::synthesizePrototype(ExecState* exec) const // ECMA 8.7.2 void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { - JSGlobalData& globalData = exec->globalData(); + VM& vm = exec->vm(); unsigned index = propertyName.asIndex(); if (index != PropertyName::NotAnIndex) { @@ -136,7 +137,7 @@ void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue for (; ; obj = asObject(prototype)) { unsigned attributes; JSCell* specificValue; - PropertyOffset offset = obj->structure()->get(globalData, propertyName, attributes, specificValue); + PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes, specificValue); if (offset != invalidOffset) { if (attributes & ReadOnly) { if (slot.isStrictMode()) @@ -144,7 +145,7 @@ void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue return; } - JSValue gs = obj->getDirectOffset(offset); + JSValue gs = obj->getDirect(offset); if (gs.isGetterSetter()) { JSObject* setterFunc = asGetterSetter(gs)->setter(); if (!setterFunc) { @@ -193,51 +194,53 @@ void JSValue::putToPrimitiveByIndex(ExecState* exec, unsigned propertyName, JSVa throwTypeError(exec, StrictModeReadonlyPropertyWriteError); } -char* JSValue::description() const +void JSValue::dump(PrintStream& out) const { - static const size_t size = 256; - static char description[size]; - if (!*this) - snprintf(description, size, "<JSValue()>"); + out.print("<JSValue()>"); else if (isInt32()) - snprintf(description, size, "Int32: %d", asInt32()); + out.printf("Int32: %d", asInt32()); else if (isDouble()) { #if USE(JSVALUE64) - snprintf(description, size, "Double: %lld, %lf", (long long)reinterpretDoubleToInt64(asDouble()), asDouble()); + out.printf("Double: %lld, %lf", (long long)reinterpretDoubleToInt64(asDouble()), asDouble()); #else union { double asDouble; uint32_t asTwoInt32s[2]; } u; u.asDouble = asDouble(); - snprintf(description, size, "Double: %08x:%08x, %lf", u.asTwoInt32s[1], u.asTwoInt32s[0], asDouble()); + out.printf("Double: %08x:%08x, %lf", u.asTwoInt32s[1], u.asTwoInt32s[0], asDouble()); #endif } else if (isCell()) { - if (asCell()->inherits(&Structure::s_info)) { + if (asCell()->inherits(&JSString::s_info)) { + JSString* string = jsCast<JSString*>(asCell()); + out.print("String: "); + if (string->isRope()) + out.print("(rope) "); + out.print(string->tryGetValue()); + } else if (asCell()->inherits(&Structure::s_info)) { Structure* structure = jsCast<Structure*>(asCell()); - snprintf( - description, size, "Structure: %p: %s, %s", - structure, structure->classInfo()->className, - indexingTypeToString(structure->indexingTypeIncludingHistory())); + out.print( + "Structure: ", RawPointer(structure), ": ", structure->classInfo()->className, + ", ", IndexingTypeDump(structure->indexingTypeIncludingHistory())); } else { - snprintf( - description, size, "Cell: %p -> %p (%p: %s, %s)", - asCell(), isObject() ? asObject(*this)->butterfly() : 0, asCell()->structure(), asCell()->structure()->classInfo()->className, - indexingTypeToString(asCell()->structure()->indexingTypeIncludingHistory())); + out.print("Cell: ", RawPointer(asCell())); + if (isObject() && asObject(*this)->butterfly()) + out.print("->", RawPointer(asObject(*this)->butterfly())); + out.print( + " (", RawPointer(asCell()->structure()), ": ", asCell()->structure()->classInfo()->className, + ", ", IndexingTypeDump(asCell()->structure()->indexingTypeIncludingHistory()), ")"); } } else if (isTrue()) - snprintf(description, size, "True"); + out.print("True"); else if (isFalse()) - snprintf(description, size, "False"); + out.print("False"); else if (isNull()) - snprintf(description, size, "Null"); + out.print("Null"); else if (isUndefined()) - snprintf(description, size, "Undefined"); + out.print("Undefined"); else - snprintf(description, size, "INVALID"); - - return description; + out.print("INVALID"); } // This in the ToInt32 operation is defined in section 9.5 of the ECMA-262 spec. @@ -292,20 +295,20 @@ bool JSValue::isValidCallee() JSString* JSValue::toStringSlowCase(ExecState* exec) const { - JSGlobalData& globalData = exec->globalData(); + VM& vm = exec->vm(); ASSERT(!isString()); if (isInt32()) - return jsString(&globalData, globalData.numericStrings.add(asInt32())); + return jsString(&vm, vm.numericStrings.add(asInt32())); if (isDouble()) - return jsString(&globalData, globalData.numericStrings.add(asDouble())); + return jsString(&vm, vm.numericStrings.add(asDouble())); if (isTrue()) - return globalData.smallStrings.trueString(&globalData); + return vm.smallStrings.trueString(); if (isFalse()) - return globalData.smallStrings.falseString(&globalData); + return vm.smallStrings.falseString(); if (isNull()) - return globalData.smallStrings.nullString(&globalData); + return vm.smallStrings.nullString(); if (isUndefined()) - return globalData.smallStrings.undefinedString(&globalData); + return vm.smallStrings.undefinedString(); ASSERT(isCell()); JSValue value = asCell()->toPrimitive(exec, PreferString); diff --git a/Source/JavaScriptCore/runtime/JSValue.h b/Source/JavaScriptCore/runtime/JSCJSValue.h index f6447d0bd..abb4b8109 100644 --- a/Source/JavaScriptCore/runtime/JSValue.h +++ b/Source/JavaScriptCore/runtime/JSCJSValue.h @@ -20,18 +20,19 @@ * */ -#ifndef JSValue_h -#define JSValue_h +#ifndef JSCJSValue_h +#define JSCJSValue_h #include <math.h> #include <stddef.h> // for size_t #include <stdint.h> -#include <wtf/AlwaysInline.h> #include <wtf/Assertions.h> +#include <wtf/Forward.h> #include <wtf/HashMap.h> #include <wtf/HashTraits.h> #include <wtf/MathExtras.h> #include <wtf/StdLibExtras.h> +#include <wtf/TriState.h> namespace JSC { @@ -41,7 +42,7 @@ namespace JSC { class ExecState; class JSCell; -class JSGlobalData; +class VM; class JSGlobalObject; class JSObject; class JSString; @@ -213,6 +214,7 @@ public: bool getPrimitiveNumber(ExecState*, double& number, JSValue&); bool toBoolean(ExecState*) const; + TriState pureToBoolean() const; // toNumber conversion is expected to be side effect free if an exception has // been set in the ExecState already. @@ -245,12 +247,12 @@ public: JSObject* toThisObject(ExecState*) const; - static bool equal(ExecState* exec, JSValue v1, JSValue v2); - static bool equalSlowCase(ExecState* exec, JSValue v1, JSValue v2); - static bool equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2); - static bool strictEqual(ExecState* exec, JSValue v1, JSValue v2); - static bool strictEqualSlowCase(ExecState* exec, JSValue v1, JSValue v2); - static bool strictEqualSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2); + static bool equal(ExecState*, JSValue v1, JSValue v2); + static bool equalSlowCase(ExecState*, JSValue v1, JSValue v2); + static bool equalSlowCaseInline(ExecState*, JSValue v1, JSValue v2); + static bool strictEqual(ExecState*, JSValue v1, JSValue v2); + static bool strictEqualSlowCase(ExecState*, JSValue v1, JSValue v2); + static bool strictEqualSlowCaseInline(ExecState*, JSValue v1, JSValue v2); bool isCell() const; JSCell* asCell() const; @@ -258,7 +260,7 @@ public: JSValue structureOrUndefined() const; - JS_EXPORT_PRIVATE char* description() const; + JS_EXPORT_PRIVATE void dump(PrintStream&) const; JS_EXPORT_PRIVATE JSObject* synthesizePrototype(ExecState*) const; @@ -494,4 +496,4 @@ inline bool operator!=(const JSCell* a, const JSValue b) { return JSValue(a) != } // namespace JSC -#endif // JSValue_h +#endif // JSCJSValue_h diff --git a/Source/JavaScriptCore/runtime/JSCJSValueInlines.h b/Source/JavaScriptCore/runtime/JSCJSValueInlines.h new file mode 100644 index 000000000..e22fe244f --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSCJSValueInlines.h @@ -0,0 +1,810 @@ +/* + * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSValueInlines_h +#define JSValueInlines_h + +#include "InternalFunction.h" +#include "JSCJSValue.h" +#include "JSCellInlines.h" +#include "JSFunction.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::asNumber() const +{ + ASSERT(isNumber()); + return isInt32() ? asInt32() : asDouble(); +} + +inline JSValue jsNaN() +{ + return JSValue(QNaN); +} + +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 && std::signbit(d))) { // true for -0.0 + *this = JSValue(EncodeAsDouble, d); + return; + } + *this = JSValue(static_cast<int32_t>(d)); +} + +inline EncodedJSValue JSValue::encode(JSValue value) +{ + return value.u.asInt64; +} + +inline JSValue JSValue::decode(EncodedJSValue encodedJSValue) +{ + JSValue v; + v.u.asInt64 = encodedJSValue; + return v; +} + +#if USE(JSVALUE32_64) +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); +} + +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)); +} + +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::isEmpty() const +{ + return tag() == EmptyValueTag; +} + +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; +} + +#if ENABLE(LLINT_C_LOOP) +inline JSValue::JSValue(int32_t tag, int32_t payload) +{ + u.asBits.tag = tag; + u.asBits.payload = payload; +} +#endif + +inline bool JSValue::isNumber() const +{ + return isInt32() || isDouble(); +} + +inline bool JSValue::isBoolean() const +{ + return isTrue() || isFalse(); +} + +inline bool JSValue::asBoolean() const +{ + ASSERT(isBoolean()); + return payload(); +} + +#else // !USE(JSVALUE32_64) i.e. USE(JSVALUE64) + +// 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.asInt64 = reinterpret_cast<uintptr_t>(ptr); +} + +inline JSValue::JSValue(const JSCell* ptr) +{ + u.asInt64 = reinterpret_cast<uintptr_t>(const_cast<JSCell*>(ptr)); +} + +inline JSValue::operator bool() const +{ + return u.asInt64; +} + +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::isEmpty() const +{ + return u.asInt64 == ValueEmpty; +} + +inline bool JSValue::isUndefined() const +{ + return asValue() == JSValue(JSUndefined); +} + +inline bool JSValue::isNull() const +{ + return asValue() == JSValue(JSNull); +} + +inline bool JSValue::isTrue() const +{ + return asValue() == JSValue(JSTrue); +} + +inline bool JSValue::isFalse() const +{ + return asValue() == JSValue(JSFalse); +} + +inline bool JSValue::asBoolean() const +{ + ASSERT(isBoolean()); + return asValue() == JSValue(JSTrue); +} + +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 int64_t reinterpretDoubleToInt64(double value) +{ + return bitwise_cast<int64_t>(value); +} +inline double reinterpretInt64ToDouble(int64_t value) +{ + return bitwise_cast<double>(value); +} + +ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d) +{ + u.asInt64 = reinterpretDoubleToInt64(d) + DoubleEncodeOffset; +} + +inline JSValue::JSValue(int i) +{ + u.asInt64 = TagTypeNumber | static_cast<uint32_t>(i); +} + +inline double JSValue::asDouble() const +{ + ASSERT(isDouble()); + return reinterpretInt64ToDouble(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) + +inline bool JSValue::isString() const +{ + return isCell() && asCell()->isString(); +} + +inline bool JSValue::isPrimitive() const +{ + return !isCell() || asCell()->isString(); +} + +inline bool JSValue::isGetterSetter() const +{ + return isCell() && asCell()->isGetterSetter(); +} + +inline bool JSValue::isObject() const +{ + return isCell() && asCell()->isObject(); +} + +inline bool JSValue::getString(ExecState* exec, String& s) const +{ + return isCell() && asCell()->getString(exec, s); +} + +inline String JSValue::getString(ExecState* exec) const +{ + return isCell() ? asCell()->getString(exec) : String(); +} + +template <typename Base> String HandleConverter<Base, Unknown>::getString(ExecState* exec) const +{ + return jsValue().getString(exec); +} + +inline JSObject* JSValue::getObject() const +{ + return isCell() ? asCell()->getObject() : 0; +} + +ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const +{ + if (isInt32()) { + int32_t i = asInt32(); + v = static_cast<uint32_t>(i); + return i >= 0; + } + if (isDouble()) { + double d = asDouble(); + v = static_cast<uint32_t>(d); + return v == d; + } + return false; +} + +inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const +{ + return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue(); +} + +inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value) +{ + if (isInt32()) { + number = asInt32(); + value = *this; + return true; + } + if (isDouble()) { + number = asDouble(); + value = *this; + return true; + } + if (isCell()) + return asCell()->getPrimitiveNumber(exec, number, value); + if (isTrue()) { + number = 1.0; + value = *this; + return true; + } + if (isFalse() || isNull()) { + number = 0.0; + value = *this; + return true; + } + ASSERT(isUndefined()); + number = QNaN; + value = *this; + return true; +} + +ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const +{ + if (isInt32()) + return asInt32(); + if (isDouble()) + return asDouble(); + return toNumberSlowCase(exec); +} + +inline JSObject* JSValue::toObject(ExecState* exec) const +{ + return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject()); +} + +inline JSObject* JSValue::toObject(ExecState* exec, JSGlobalObject* globalObject) const +{ + return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject); +} + +inline bool JSValue::isFunction() const +{ + return isCell() && (asCell()->inherits(&JSFunction::s_info) || asCell()->inherits(&InternalFunction::s_info)); +} + +// this method is here to be after the inline declaration of JSCell::inherits +inline bool JSValue::inherits(const ClassInfo* classInfo) const +{ + return isCell() && asCell()->inherits(classInfo); +} + +inline JSObject* JSValue::toThisObject(ExecState* exec) const +{ + return isCell() ? asCell()->methodTable()->toThisObject(asCell(), exec) : toThisObjectSlowCase(exec); +} + +inline JSValue JSValue::get(ExecState* exec, PropertyName propertyName) const +{ + PropertySlot slot(asValue()); + return get(exec, propertyName, slot); +} + +inline JSValue JSValue::get(ExecState* exec, PropertyName propertyName, PropertySlot& slot) const +{ + if (UNLIKELY(!isCell())) { + JSObject* prototype = synthesizePrototype(exec); + if (!prototype->getPropertySlot(exec, propertyName, slot)) + return jsUndefined(); + return slot.getValue(exec, propertyName); + } + JSCell* cell = asCell(); + while (true) { + if (cell->fastGetOwnPropertySlot(exec, propertyName, slot)) + return slot.getValue(exec, propertyName); + JSValue prototype = asObject(cell)->prototype(); + if (!prototype.isObject()) + return jsUndefined(); + cell = asObject(prototype); + } +} + +inline JSValue JSValue::get(ExecState* exec, unsigned propertyName) const +{ + PropertySlot slot(asValue()); + return get(exec, propertyName, slot); +} + +inline JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const +{ + if (UNLIKELY(!isCell())) { + JSObject* prototype = synthesizePrototype(exec); + if (!prototype->getPropertySlot(exec, propertyName, slot)) + return jsUndefined(); + return slot.getValue(exec, propertyName); + } + JSCell* cell = const_cast<JSCell*>(asCell()); + while (true) { + if (cell->methodTable()->getOwnPropertySlotByIndex(cell, exec, propertyName, slot)) + return slot.getValue(exec, propertyName); + JSValue prototype = asObject(cell)->prototype(); + if (!prototype.isObject()) + return jsUndefined(); + cell = prototype.asCell(); + } +} + +inline void JSValue::put(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) +{ + if (UNLIKELY(!isCell())) { + putToPrimitive(exec, propertyName, value, slot); + return; + } + asCell()->methodTable()->put(asCell(), exec, propertyName, value, slot); +} + +inline void JSValue::putByIndex(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow) +{ + if (UNLIKELY(!isCell())) { + putToPrimitiveByIndex(exec, propertyName, value, shouldThrow); + return; + } + asCell()->methodTable()->putByIndex(asCell(), exec, propertyName, value, shouldThrow); +} + +inline JSValue JSValue::structureOrUndefined() const +{ + if (isCell()) + return JSValue(asCell()->structure()); + return jsUndefined(); +} + +// ECMA 11.9.3 +inline bool JSValue::equal(ExecState* exec, JSValue v1, JSValue v2) +{ + if (v1.isInt32() && v2.isInt32()) + return v1 == v2; + + return equalSlowCase(exec, v1, v2); +} + +ALWAYS_INLINE bool JSValue::equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2) +{ + do { + if (v1.isNumber() && v2.isNumber()) + return v1.asNumber() == v2.asNumber(); + + bool s1 = v1.isString(); + bool s2 = v2.isString(); + if (s1 && s2) + return asString(v1)->value(exec) == asString(v2)->value(exec); + + if (v1.isUndefinedOrNull()) { + if (v2.isUndefinedOrNull()) + return true; + if (!v2.isCell()) + return false; + return v2.asCell()->structure()->masqueradesAsUndefined(exec->lexicalGlobalObject()); + } + + if (v2.isUndefinedOrNull()) { + if (!v1.isCell()) + return false; + return v1.asCell()->structure()->masqueradesAsUndefined(exec->lexicalGlobalObject()); + } + + if (v1.isObject()) { + if (v2.isObject()) + return v1 == v2; + JSValue p1 = v1.toPrimitive(exec); + if (exec->hadException()) + return false; + v1 = p1; + if (v1.isInt32() && v2.isInt32()) + return v1 == v2; + continue; + } + + if (v2.isObject()) { + JSValue p2 = v2.toPrimitive(exec); + if (exec->hadException()) + return false; + v2 = p2; + if (v1.isInt32() && v2.isInt32()) + return v1 == v2; + continue; + } + + if (s1 || s2) { + double d1 = v1.toNumber(exec); + double d2 = v2.toNumber(exec); + return d1 == d2; + } + + if (v1.isBoolean()) { + if (v2.isNumber()) + return static_cast<double>(v1.asBoolean()) == v2.asNumber(); + } else if (v2.isBoolean()) { + if (v1.isNumber()) + return v1.asNumber() == static_cast<double>(v2.asBoolean()); + } + + return v1 == v2; + } while (true); +} + +// ECMA 11.9.3 +ALWAYS_INLINE bool JSValue::strictEqualSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2) +{ + ASSERT(v1.isCell() && v2.isCell()); + + if (v1.asCell()->isString() && v2.asCell()->isString()) + return asString(v1)->value(exec) == asString(v2)->value(exec); + + return v1 == v2; +} + +inline bool JSValue::strictEqual(ExecState* exec, JSValue v1, JSValue v2) +{ + if (v1.isInt32() && v2.isInt32()) + return v1 == v2; + + if (v1.isNumber() && v2.isNumber()) + return v1.asNumber() == v2.asNumber(); + + if (!v1.isCell() || !v2.isCell()) + return v1 == v2; + + return strictEqualSlowCaseInline(exec, v1, v2); +} + +inline TriState JSValue::pureToBoolean() const +{ + if (isInt32()) + return asInt32() ? TrueTriState : FalseTriState; + if (isDouble()) + return isNotZeroAndOrdered(asDouble()) ? TrueTriState : FalseTriState; // false for NaN + if (isCell()) + return asCell()->pureToBoolean(); + return isTrue() ? TrueTriState : FalseTriState; +} + +} // namespace JSC + +#endif // JSValueInlines_h + diff --git a/Source/JavaScriptCore/runtime/JSCell.cpp b/Source/JavaScriptCore/runtime/JSCell.cpp index f6f4d716d..07b333193 100644 --- a/Source/JavaScriptCore/runtime/JSCell.cpp +++ b/Source/JavaScriptCore/runtime/JSCell.cpp @@ -27,6 +27,7 @@ #include "JSString.h" #include "JSObject.h" #include "NumberObject.h" +#include "Operations.h" #include <wtf/MathExtras.h> namespace JSC { @@ -65,13 +66,19 @@ const JSObject* JSCell::getObject() const return isObject() ? static_cast<const JSObject*>(this) : 0; } -CallType JSCell::getCallData(JSCell*, CallData&) +CallType JSCell::getCallData(JSCell*, CallData& callData) { + callData.js.functionExecutable = 0; + callData.js.scope = 0; + callData.native.function = 0; return CallTypeNone; } -ConstructType JSCell::getConstructData(JSCell*, ConstructData&) +ConstructType JSCell::getConstructData(JSCell*, ConstructData& constructData) { + constructData.js.functionExecutable = 0; + constructData.js.scope = 0; + constructData.native.function = 0; return ConstructTypeNone; } @@ -173,23 +180,23 @@ void slowValidateCell(JSCell* cell) JSValue JSCell::defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType) { - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return jsUndefined(); } void JSCell::getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode) { - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } void JSCell::getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode) { - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } String JSCell::className(const JSObject*) { - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return String(); } @@ -200,29 +207,29 @@ const char* JSCell::className() void JSCell::getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode) { - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } bool JSCell::customHasInstance(JSObject*, ExecState*, JSValue) { - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return false; } void JSCell::putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned) { - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } bool JSCell::defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool) { - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return false; } bool JSCell::getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&) { - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return false; } diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h index b28fedd8d..76acb1e55 100644 --- a/Source/JavaScriptCore/runtime/JSCell.h +++ b/Source/JavaScriptCore/runtime/JSCell.h @@ -24,11 +24,9 @@ #define JSCell_h #include "CallData.h" -#include "CallFrame.h" #include "ConstructData.h" #include "Heap.h" #include "JSLock.h" -#include "JSValueInlines.h" #include "SlotVisitor.h" #include "TypedArrayDescriptor.h" #include "WriteBarrier.h" @@ -38,6 +36,7 @@ namespace JSC { class CopyVisitor; +class ExecState; class JSDestructibleObject; class JSGlobalObject; class LLIntOffsetsExtractor; @@ -66,7 +65,7 @@ public: JSCell(CreatingEarlyCellTag); protected: - JSCell(JSGlobalData&, Structure*); + JSCell(VM&, Structure*); JS_EXPORT_PRIVATE static void destroy(JSCell*); public: @@ -79,7 +78,7 @@ public: bool isAPIValueWrapper() const; Structure* structure() const; - void setStructure(JSGlobalData&, Structure*); + void setStructure(VM&, Structure*); void clearStructure() { m_structure.clear(); } const char* className(); @@ -97,6 +96,7 @@ public: JS_EXPORT_PRIVATE JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const; bool toBoolean(ExecState*) const; + TriState pureToBoolean() const; JS_EXPORT_PRIVATE double toNumber(ExecState*) const; JS_EXPORT_PRIVATE JSObject* toObject(ExecState*, JSGlobalObject*) const; @@ -106,6 +106,7 @@ public: // Object operations, with the toObject operation included. const ClassInfo* classInfo() const; const MethodTable* methodTable() const; + const MethodTable* methodTableForDestruction() const; static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); @@ -141,8 +142,8 @@ public: static const TypedArrayType TypedArrayStorageType = TypedArrayNone; protected: - void finishCreation(JSGlobalData&); - void finishCreation(JSGlobalData&, Structure*, CreatingEarlyCellTag); + void finishCreation(VM&); + void finishCreation(VM&, Structure*, CreatingEarlyCellTag); // Base implementation; for non-object classes implements getPropertySlot. static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); @@ -150,12 +151,12 @@ protected: // Dummy implementations of override-able static functions for classes to put in their MethodTable static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType); - static NO_RETURN_DUE_TO_ASSERT void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - static NO_RETURN_DUE_TO_ASSERT void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - static NO_RETURN_DUE_TO_ASSERT void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + static NO_RETURN_DUE_TO_CRASH void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + static NO_RETURN_DUE_TO_CRASH void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + static NO_RETURN_DUE_TO_CRASH void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); static String className(const JSObject*); JS_EXPORT_PRIVATE static bool customHasInstance(JSObject*, ExecState*, JSValue); - static NO_RETURN_DUE_TO_ASSERT void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes); + static NO_RETURN_DUE_TO_CRASH void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes); static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow); static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); @@ -165,174 +166,6 @@ private: WriteBarrier<Structure> m_structure; }; -inline JSCell::JSCell(CreatingEarlyCellTag) -{ -} - -inline void JSCell::finishCreation(JSGlobalData& globalData) -{ -#if ENABLE(GC_VALIDATION) - ASSERT(globalData.isInitializingObject()); - globalData.setInitializingObjectClass(0); -#else - UNUSED_PARAM(globalData); -#endif - ASSERT(m_structure); -} - -inline Structure* JSCell::structure() const -{ - return m_structure.get(); -} - -inline void JSCell::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - MARK_LOG_PARENT(visitor, cell); - - visitor.append(&cell->m_structure); -} - -// --- JSValue inlines ---------------------------- - -inline bool JSValue::isString() const -{ - return isCell() && asCell()->isString(); -} - -inline bool JSValue::isPrimitive() const -{ - return !isCell() || asCell()->isString(); -} - -inline bool JSValue::isGetterSetter() const -{ - return isCell() && asCell()->isGetterSetter(); -} - -inline bool JSValue::isObject() const -{ - return isCell() && asCell()->isObject(); -} - -inline bool JSValue::getString(ExecState* exec, String& s) const -{ - return isCell() && asCell()->getString(exec, s); -} - -inline String JSValue::getString(ExecState* exec) const -{ - return isCell() ? asCell()->getString(exec) : String(); -} - -template <typename Base> String HandleConverter<Base, Unknown>::getString(ExecState* exec) const -{ - return jsValue().getString(exec); -} - -inline JSObject* JSValue::getObject() const -{ - return isCell() ? asCell()->getObject() : 0; -} - -ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const -{ - if (isInt32()) { - int32_t i = asInt32(); - v = static_cast<uint32_t>(i); - return i >= 0; - } - if (isDouble()) { - double d = asDouble(); - v = static_cast<uint32_t>(d); - return v == d; - } - return false; -} - -inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const -{ - return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue(); -} - -inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value) -{ - if (isInt32()) { - number = asInt32(); - value = *this; - return true; - } - if (isDouble()) { - number = asDouble(); - value = *this; - return true; - } - if (isCell()) - return asCell()->getPrimitiveNumber(exec, number, value); - if (isTrue()) { - number = 1.0; - value = *this; - return true; - } - if (isFalse() || isNull()) { - number = 0.0; - value = *this; - return true; - } - ASSERT(isUndefined()); - number = QNaN; - value = *this; - return true; -} - -ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const -{ - if (isInt32()) - return asInt32(); - if (isDouble()) - return asDouble(); - return toNumberSlowCase(exec); -} - -inline JSObject* JSValue::toObject(ExecState* exec) const -{ - return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject()); -} - -inline JSObject* JSValue::toObject(ExecState* exec, JSGlobalObject* globalObject) const -{ - return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject); -} - -template<typename T> -void* allocateCell(Heap& heap, size_t size) -{ - ASSERT(size >= sizeof(T)); -#if ENABLE(GC_VALIDATION) - ASSERT(!heap.globalData()->isInitializingObject()); - heap.globalData()->setInitializingObjectClass(&T::s_info); -#endif - JSCell* result = 0; - if (T::needsDestruction && T::hasImmortalStructure) - result = static_cast<JSCell*>(heap.allocateWithImmortalStructureDestructor(size)); - else if (T::needsDestruction && !T::hasImmortalStructure) - result = static_cast<JSCell*>(heap.allocateWithNormalDestructor(size)); - else - result = static_cast<JSCell*>(heap.allocateWithoutDestructor(size)); - result->clearStructure(); - return result; -} - -template<typename T> -void* allocateCell(Heap& heap) -{ - return allocateCell<T>(heap, sizeof(T)); -} - -inline bool isZapped(const JSCell* cell) -{ - return cell->isZapped(); -} - template<typename To, typename From> inline To jsCast(From* from) { diff --git a/Source/JavaScriptCore/runtime/JSCellInlines.h b/Source/JavaScriptCore/runtime/JSCellInlines.h new file mode 100644 index 000000000..5312cae35 --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSCellInlines.h @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSCellInlines_h +#define JSCellInlines_h + +#include "CallFrame.h" +#include "Handle.h" +#include "JSCell.h" +#include "JSObject.h" +#include "JSString.h" +#include "Structure.h" + +namespace JSC { + +inline JSCell::JSCell(CreatingEarlyCellTag) +{ +} + +inline JSCell::JSCell(VM& vm, Structure* structure) + : m_structure(vm, this, structure) +{ +} + +inline void JSCell::finishCreation(VM& vm) +{ +#if ENABLE(GC_VALIDATION) + ASSERT(vm.isInitializingObject()); + vm.setInitializingObjectClass(0); +#else + UNUSED_PARAM(vm); +#endif + ASSERT(m_structure); +} + +inline void JSCell::finishCreation(VM& vm, Structure* structure, CreatingEarlyCellTag) +{ +#if ENABLE(GC_VALIDATION) + ASSERT(vm.isInitializingObject()); + vm.setInitializingObjectClass(0); + if (structure) +#endif + m_structure.setEarlyValue(vm, this, structure); + // Very first set of allocations won't have a real structure. + ASSERT(m_structure || !vm.structureStructure); +} + +inline Structure* JSCell::structure() const +{ + return m_structure.get(); +} + +inline void JSCell::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + MARK_LOG_PARENT(visitor, cell); + + visitor.append(&cell->m_structure); +} + +template<typename T> +void* allocateCell(Heap& heap, size_t size) +{ + ASSERT(size >= sizeof(T)); +#if ENABLE(GC_VALIDATION) + ASSERT(!heap.vm()->isInitializingObject()); + heap.vm()->setInitializingObjectClass(&T::s_info); +#endif + JSCell* result = 0; + if (T::needsDestruction && T::hasImmortalStructure) + result = static_cast<JSCell*>(heap.allocateWithImmortalStructureDestructor(size)); + else if (T::needsDestruction) + result = static_cast<JSCell*>(heap.allocateWithNormalDestructor(size)); + else + result = static_cast<JSCell*>(heap.allocateWithoutDestructor(size)); + result->clearStructure(); + return result; +} + +template<typename T> +void* allocateCell(Heap& heap) +{ + return allocateCell<T>(heap, sizeof(T)); +} + +inline bool isZapped(const JSCell* cell) +{ + return cell->isZapped(); +} + +inline bool JSCell::isObject() const +{ + return m_structure->isObject(); +} + +inline bool JSCell::isString() const +{ + return m_structure->typeInfo().type() == StringType; +} + +inline bool JSCell::isGetterSetter() const +{ + return m_structure->typeInfo().type() == GetterSetterType; +} + +inline bool JSCell::isProxy() const +{ + return structure()->typeInfo().type() == ProxyType; +} + +inline bool JSCell::isAPIValueWrapper() const +{ + return m_structure->typeInfo().type() == APIValueWrapperType; +} + +inline void JSCell::setStructure(VM& vm, Structure* structure) +{ + ASSERT(structure->typeInfo().overridesVisitChildren() == this->structure()->typeInfo().overridesVisitChildren()); + ASSERT(structure->classInfo() == m_structure->classInfo()); + ASSERT(!m_structure + || m_structure->transitionWatchpointSetHasBeenInvalidated() + || m_structure.get() == structure); + m_structure.set(vm, this, structure); +} + +inline const MethodTable* JSCell::methodTableForDestruction() const +{ + return &classInfo()->methodTable; +} + +inline const MethodTable* JSCell::methodTable() const +{ + if (Structure* rootStructure = m_structure->structure()) + RELEASE_ASSERT(rootStructure == rootStructure->structure()); + + return &classInfo()->methodTable; +} + +inline bool JSCell::inherits(const ClassInfo* info) const +{ + return classInfo()->isSubClassOf(info); +} + +ALWAYS_INLINE bool JSCell::fastGetOwnPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot) +{ + if (!structure()->typeInfo().overridesGetOwnPropertySlot()) + return asObject(this)->inlineGetOwnPropertySlot(exec, propertyName, slot); + return methodTable()->getOwnPropertySlot(this, exec, propertyName, slot); +} + +// Fast call to get a property where we may not yet have converted the string to an +// identifier. The first time we perform a property access with a given string, try +// performing the property map lookup without forming an identifier. We detect this +// case by checking whether the hash has yet been set for this string. +ALWAYS_INLINE JSValue JSCell::fastGetOwnProperty(ExecState* exec, const String& name) +{ + if (!structure()->typeInfo().overridesGetOwnPropertySlot() && !structure()->hasGetterSetterProperties()) { + PropertyOffset offset = name.impl()->hasHash() + ? structure()->get(exec->vm(), Identifier(exec, name)) + : structure()->get(exec->vm(), name); + if (offset != invalidOffset) + return asObject(this)->locationForOffset(offset)->get(); + } + return JSValue(); +} + +inline bool JSCell::toBoolean(ExecState* exec) const +{ + if (isString()) + return static_cast<const JSString*>(this)->toBoolean(); + return !structure()->masqueradesAsUndefined(exec->lexicalGlobalObject()); +} + +inline TriState JSCell::pureToBoolean() const +{ + if (isString()) + return static_cast<const JSString*>(this)->toBoolean() ? TrueTriState : FalseTriState; + return MixedTriState; +} + +} // namespace JSC + +#endif // JSCellInlines_h diff --git a/Source/JavaScriptCore/runtime/JSDateMath.cpp b/Source/JavaScriptCore/runtime/JSDateMath.cpp index cd3948fcf..b69573670 100644 --- a/Source/JavaScriptCore/runtime/JSDateMath.cpp +++ b/Source/JavaScriptCore/runtime/JSDateMath.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2012 Apple Inc. All rights reserved. * Copyright (C) 2009 Google Inc. All rights reserved. * Copyright (C) 2007-2009 Torch Mobile, Inc. * Copyright (C) 2010 &yet, LLC. (nate@andyet.net) @@ -74,6 +74,7 @@ #include "JSObject.h" #include "JSScope.h" +#include "Operations.h" #include <algorithm> #include <limits.h> @@ -126,14 +127,14 @@ static inline int msToWeekDay(double ms) return wd; } -// Get the DST offset for the time passed in. +// Get the combined UTC + DST offset for the time passed in. // // NOTE: The implementation relies on the fact that no time zones have // more than one daylight savings offset change per month. // If this function is called with NaN it returns NaN. -static double getDSTOffset(ExecState* exec, double ms, double utcOffset) +static LocalTimeOffset localTimeOffset(ExecState* exec, double ms) { - DSTOffsetCache& cache = exec->globalData().dstOffsetCache; + LocalTimeOffsetCache& cache = exec->vm().localTimeOffsetCache; double start = cache.start; double end = cache.end; @@ -145,7 +146,7 @@ static double getDSTOffset(ExecState* exec, double ms, double utcOffset) double newEnd = end + cache.increment; if (ms <= newEnd) { - double endOffset = calculateDSTOffset(newEnd, utcOffset); + LocalTimeOffset endOffset = calculateLocalTimeOffset(newEnd); if (cache.offset == endOffset) { // If the offset at the end of the new interval still matches // the offset in the cache, we grow the cached time interval @@ -153,34 +154,33 @@ static double getDSTOffset(ExecState* exec, double ms, double utcOffset) cache.end = newEnd; cache.increment = msPerMonth; return endOffset; + } + LocalTimeOffset offset = calculateLocalTimeOffset(ms); + if (offset == endOffset) { + // The offset at the given time is equal to the offset at the + // new end of the interval, so that means that we've just skipped + // the point in time where the DST offset change occurred. Updated + // the interval to reflect this and reset the increment. + cache.start = ms; + cache.end = newEnd; + cache.increment = msPerMonth; } else { - double offset = calculateDSTOffset(ms, utcOffset); - if (offset == endOffset) { - // The offset at the given time is equal to the offset at the - // new end of the interval, so that means that we've just skipped - // the point in time where the DST offset change occurred. Updated - // the interval to reflect this and reset the increment. - cache.start = ms; - cache.end = newEnd; - cache.increment = msPerMonth; - } else { - // The interval contains a DST offset change and the given time is - // before it. Adjust the increment to avoid a linear search for - // the offset change point and change the end of the interval. - cache.increment /= 3; - cache.end = ms; - } - // Update the offset in the cache and return it. - cache.offset = offset; - return offset; + // The interval contains a DST offset change and the given time is + // before it. Adjust the increment to avoid a linear search for + // the offset change point and change the end of the interval. + cache.increment /= 3; + cache.end = ms; } + // Update the offset in the cache and return it. + cache.offset = offset; + return offset; } } // Compute the DST offset for the time and shrink the cache interval // to only contain the time. This allows fast repeated DST offset // computations for the same time. - double offset = calculateDSTOffset(ms, utcOffset); + LocalTimeOffset offset = calculateLocalTimeOffset(ms); cache.offset = offset; cache.start = ms; cache.end = ms; @@ -188,30 +188,14 @@ static double getDSTOffset(ExecState* exec, double ms, double utcOffset) return offset; } -/* - * Get the difference in milliseconds between this time zone and UTC (GMT) - * NOT including DST. - */ -double getUTCOffset(ExecState* exec) -{ - double utcOffset = exec->globalData().cachedUTCOffset; - if (!isnan(utcOffset)) - return utcOffset; - exec->globalData().cachedUTCOffset = calculateUTCOffset(); - return exec->globalData().cachedUTCOffset; -} - double gregorianDateTimeToMS(ExecState* exec, const GregorianDateTime& t, double milliSeconds, bool inputIsUTC) { double day = dateToDaysFrom1970(t.year(), t.month(), t.monthDay()); double ms = timeToMS(t.hour(), t.minute(), t.second(), milliSeconds); double result = (day * WTF::msPerDay) + ms; - if (!inputIsUTC) { // convert to UTC - double utcOffset = getUTCOffset(exec); - result -= utcOffset; - result -= getDSTOffset(exec, result, utcOffset); - } + if (!inputIsUTC) + result -= localTimeOffset(exec, result).offset; return result; } @@ -219,12 +203,10 @@ double gregorianDateTimeToMS(ExecState* exec, const GregorianDateTime& t, double // input is UTC void msToGregorianDateTime(ExecState* exec, double ms, bool outputIsUTC, GregorianDateTime& tm) { - double dstOff = 0.0; - double utcOff = 0.0; + LocalTimeOffset localTime; if (!outputIsUTC) { - utcOff = getUTCOffset(exec); - dstOff = getDSTOffset(exec, ms, utcOff); - ms += dstOff + utcOff; + localTime = localTimeOffset(exec, ms); + ms += localTime.offset; } const int year = msToYear(ms); @@ -236,8 +218,8 @@ void msToGregorianDateTime(ExecState* exec, double ms, bool outputIsUTC, Gregori tm.setMonthDay(dayInMonthFromDayInYear(tm.yearDay(), isLeapYear(year))); tm.setMonth(monthFromDayInYear(tm.yearDay(), isLeapYear(year))); tm.setYear(year); - tm.setIsDST(dstOff != 0.0); - tm.setUtcOffset(static_cast<long>((dstOff + utcOff) / WTF::msPerSecond)); + tm.setIsDST(localTime.isDST); + tm.setUtcOffset(localTime.offset / WTF::msPerSecond); } double parseDateFromNullTerminatedCharacters(ExecState* exec, const char* dateString) @@ -246,27 +228,25 @@ double parseDateFromNullTerminatedCharacters(ExecState* exec, const char* dateSt bool haveTZ; int offset; double ms = WTF::parseDateFromNullTerminatedCharacters(dateString, haveTZ, offset); - if (isnan(ms)) + if (std::isnan(ms)) return QNaN; // fall back to local timezone - if (!haveTZ) { - double utcOffset = getUTCOffset(exec); - double dstOffset = getDSTOffset(exec, ms, utcOffset); - offset = static_cast<int>((utcOffset + dstOffset) / WTF::msPerMinute); - } + if (!haveTZ) + offset = localTimeOffset(exec, ms).offset / WTF::msPerMinute; + return ms - (offset * WTF::msPerMinute); } double parseDate(ExecState* exec, const String& date) { - if (date == exec->globalData().cachedDateString) - return exec->globalData().cachedDateStringValue; + if (date == exec->vm().cachedDateString) + return exec->vm().cachedDateStringValue; double value = parseES5DateFromNullTerminatedCharacters(date.utf8().data()); - if (isnan(value)) + if (std::isnan(value)) value = parseDateFromNullTerminatedCharacters(exec, date.utf8().data()); - exec->globalData().cachedDateString = date; - exec->globalData().cachedDateStringValue = value; + exec->vm().cachedDateString = date; + exec->vm().cachedDateStringValue = value; return value; } diff --git a/Source/JavaScriptCore/runtime/JSDestructibleObject.h b/Source/JavaScriptCore/runtime/JSDestructibleObject.h index efbe2b4f6..27dc06da5 100644 --- a/Source/JavaScriptCore/runtime/JSDestructibleObject.h +++ b/Source/JavaScriptCore/runtime/JSDestructibleObject.h @@ -3,4 +3,43 @@ #include "JSObject.h" +namespace JSC { + +struct ClassInfo; + +class JSDestructibleObject : public JSNonFinalObject { +public: + typedef JSNonFinalObject Base; + + static const bool needsDestruction = true; + + const ClassInfo* classInfo() const { return m_classInfo; } + + static ptrdiff_t classInfoOffset() { return OBJECT_OFFSETOF(JSDestructibleObject, m_classInfo); } + +protected: + JSDestructibleObject(VM& vm, Structure* structure, Butterfly* butterfly = 0) + : JSNonFinalObject(vm, structure, butterfly) + , m_classInfo(structure->classInfo()) + { + ASSERT(m_classInfo); + } + +private: + const ClassInfo* m_classInfo; +}; + +inline const ClassInfo* JSCell::classInfo() const +{ + if (MarkedBlock::blockFor(this)->destructorType() == MarkedBlock::Normal) + return static_cast<const JSDestructibleObject*>(this)->classInfo(); +#if ENABLE(GC_VALIDATION) + return m_structure.unvalidatedGet()->classInfo(); +#else + return m_structure->classInfo(); +#endif +} + +} // namespace JSC + #endif diff --git a/Source/JavaScriptCore/runtime/JSExportMacros.h b/Source/JavaScriptCore/runtime/JSExportMacros.h index 19e2c286f..77e4b0a33 100644 --- a/Source/JavaScriptCore/runtime/JSExportMacros.h +++ b/Source/JavaScriptCore/runtime/JSExportMacros.h @@ -48,7 +48,7 @@ #else // !USE(EXPORT_MACROS) -#if !PLATFORM(CHROMIUM) && OS(WINDOWS) && !defined(BUILDING_WX__) && !COMPILER(GCC) +#if OS(WINDOWS) && !COMPILER(GCC) #if defined(BUILDING_JavaScriptCore) || defined(STATICALLY_LINKED_WITH_JavaScriptCore) #define JS_EXPORTDATA __declspec(dllexport) diff --git a/Source/JavaScriptCore/runtime/JSFunction.cpp b/Source/JavaScriptCore/runtime/JSFunction.cpp index 0a98e7c13..3b89f6d7a 100644 --- a/Source/JavaScriptCore/runtime/JSFunction.cpp +++ b/Source/JavaScriptCore/runtime/JSFunction.cpp @@ -35,7 +35,9 @@ #include "JSGlobalObject.h" #include "JSNotAnObject.h" #include "Interpreter.h" +#include "ObjectConstructor.h" #include "ObjectPrototype.h" +#include "Operations.h" #include "Parser.h" #include "PropertyNameArray.h" @@ -61,12 +63,12 @@ JSFunction* JSFunction::create(ExecState* exec, JSGlobalObject* globalObject, in #if !ENABLE(JIT) UNUSED_PARAM(intrinsic); #else - if (intrinsic != NoIntrinsic && exec->globalData().canUseJIT()) { + if (intrinsic != NoIntrinsic && exec->vm().canUseJIT()) { ASSERT(nativeConstructor == callHostFunctionAsConstructor); - executable = exec->globalData().getHostFunction(nativeFunction, intrinsic); + executable = exec->vm().getHostFunction(nativeFunction, intrinsic); } else #endif - executable = exec->globalData().getHostFunction(nativeFunction, nativeConstructor); + executable = exec->vm().getHostFunction(nativeFunction, nativeConstructor); JSFunction* function = new (NotNull, allocateCell<JSFunction>(*exec->heap())) JSFunction(exec, globalObject, globalObject->functionStructure()); // Can't do this during initialization because getHostFunction might do a GC allocation. @@ -80,49 +82,49 @@ void JSFunction::destroy(JSCell* cell) } JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* structure) - : Base(exec->globalData(), structure) + : Base(exec->vm(), structure) , m_executable() - , m_scope(exec->globalData(), this, globalObject) + , m_scope(exec->vm(), this, globalObject) // We initialize blind so that changes to the prototype after function creation but before // the optimizer kicks in don't disable optimizations. Once the optimizer kicks in, the // watchpoint will start watching and any changes will both force deoptimization and disable // future attempts to optimize. This is necessary because we are guaranteed that the - // inheritorID is changed exactly once prior to optimizations kicking in. We could be + // allocation profile is changed exactly once prior to optimizations kicking in. We could be // smarter and count the number of times the prototype is clobbered and only optimize if it // was clobbered exactly once, but that seems like overkill. In almost all cases it will be // clobbered once, and if it's clobbered more than once, that will probably only occur // before we started optimizing, anyway. - , m_inheritorIDWatchpoint(InitializedBlind) + , m_allocationProfileWatchpoint(InitializedBlind) { } void JSFunction::finishCreation(ExecState* exec, NativeExecutable* executable, int length, const String& name) { - Base::finishCreation(exec->globalData()); + Base::finishCreation(exec->vm()); ASSERT(inherits(&s_info)); - m_executable.set(exec->globalData(), this, executable); - putDirect(exec->globalData(), exec->globalData().propertyNames->name, jsString(exec, name), DontDelete | ReadOnly | DontEnum); - putDirect(exec->globalData(), exec->propertyNames().length, jsNumber(length), DontDelete | ReadOnly | DontEnum); + m_executable.set(exec->vm(), this, executable); + putDirect(exec->vm(), exec->vm().propertyNames->name, jsString(exec, name), DontDelete | ReadOnly | DontEnum); + putDirect(exec->vm(), exec->propertyNames().length, jsNumber(length), DontDelete | ReadOnly | DontEnum); } -Structure* JSFunction::cacheInheritorID(ExecState* exec) +ObjectAllocationProfile* JSFunction::createAllocationProfile(ExecState* exec, size_t inlineCapacity) { - JSValue prototype = get(exec, exec->globalData().propertyNames->prototype); - if (prototype.isObject()) - m_cachedInheritorID.set(exec->globalData(), this, asObject(prototype)->inheritorID(exec->globalData())); - else - m_cachedInheritorID.set(exec->globalData(), this, globalObject()->emptyObjectStructure()); - return m_cachedInheritorID.get(); + VM& vm = exec->vm(); + JSObject* prototype = jsDynamicCast<JSObject*>(get(exec, vm.propertyNames->prototype)); + if (!prototype) + prototype = globalObject()->objectPrototype(); + m_allocationProfile.initialize(globalObject()->vm(), this, prototype, inlineCapacity); + return &m_allocationProfile; } String JSFunction::name(ExecState* exec) { - return get(exec, exec->globalData().propertyNames->name).toWTFString(exec); + return get(exec, exec->vm().propertyNames->name).toWTFString(exec); } String JSFunction::displayName(ExecState* exec) { - JSValue displayName = getDirect(exec->globalData(), exec->globalData().propertyNames->displayName); + JSValue displayName = getDirect(exec->vm(), exec->vm().propertyNames->displayName); if (displayName && isJSString(displayName)) return asString(displayName)->tryGetValue(); @@ -161,6 +163,7 @@ void JSFunction::visitChildren(JSCell* cell, SlotVisitor& visitor) visitor.append(&thisObject->m_scope); visitor.append(&thisObject->m_executable); + thisObject->m_allocationProfile.visitAggregate(visitor); } CallType JSFunction::getCallData(JSCell* cell, CallData& callData) @@ -218,16 +221,17 @@ bool JSFunction::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); if (propertyName == exec->propertyNames().prototype) { - WriteBarrierBase<Unknown>* location = thisObject->getDirectLocation(exec->globalData(), propertyName); - - if (!location) { - JSObject* prototype = constructEmptyObject(exec, thisObject->globalObject()->emptyObjectStructure()); - prototype->putDirect(exec->globalData(), exec->propertyNames().constructor, thisObject, DontEnum); - thisObject->putDirect(exec->globalData(), exec->propertyNames().prototype, prototype, DontDelete | DontEnum); - location = thisObject->getDirectLocation(exec->globalData(), exec->propertyNames().prototype); + VM& vm = exec->vm(); + PropertyOffset offset = thisObject->getDirectOffset(vm, propertyName); + if (!isValidOffset(offset)) { + JSObject* prototype = constructEmptyObject(exec); + prototype->putDirect(vm, exec->propertyNames().constructor, thisObject, DontEnum); + thisObject->putDirect(vm, exec->propertyNames().prototype, prototype, DontDelete | DontEnum); + offset = thisObject->getDirectOffset(vm, exec->propertyNames().prototype); + ASSERT(isValidOffset(offset)); } - slot.setValue(thisObject, location->get(), thisObject->offsetForLocation(location)); + slot.setValue(thisObject, thisObject->getDirect(offset), offset); } if (propertyName == exec->propertyNames().arguments) { @@ -352,9 +356,9 @@ void JSFunction::put(JSCell* cell, ExecState* exec, PropertyName propertyName, J // following the rules set out in ECMA-262 8.12.9. PropertySlot slot; thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot); - thisObject->m_cachedInheritorID.clear(); - thisObject->m_inheritorIDWatchpoint.notifyWrite(); - // Don't allow this to be cached, since a [[Put]] must clear m_cachedInheritorID. + thisObject->m_allocationProfile.clear(); + thisObject->m_allocationProfileWatchpoint.notifyWrite(); + // Don't allow this to be cached, since a [[Put]] must clear m_allocationProfile. PutPropertySlot dontCache; Base::put(thisObject, exec, propertyName, value, dontCache); return; @@ -378,7 +382,7 @@ bool JSFunction::deleteProperty(JSCell* cell, ExecState* exec, PropertyName prop { JSFunction* thisObject = jsCast<JSFunction*>(cell); // For non-host functions, don't let these properties by deleted - except by DefineOwnProperty. - if (!thisObject->isHostFunction() && !exec->globalData().isInDefineOwnProperty() + if (!thisObject->isHostFunction() && !exec->vm().isInDefineOwnProperty() && (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length || propertyName == exec->propertyNames().name @@ -399,8 +403,8 @@ bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, PropertyNa // following the rules set out in ECMA-262 8.12.9. PropertySlot slot; thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot); - thisObject->m_cachedInheritorID.clear(); - thisObject->m_inheritorIDWatchpoint.notifyWrite(); + thisObject->m_allocationProfile.clear(); + thisObject->m_allocationProfileWatchpoint.notifyWrite(); return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException); } @@ -466,7 +470,6 @@ ConstructType JSFunction::getConstructData(JSCell* cell, ConstructData& construc constructData.js.scope = thisObject->scope(); return ConstructTypeJS; } - String getCalculatedDisplayName(CallFrame* callFrame, JSObject* object) { diff --git a/Source/JavaScriptCore/runtime/JSFunction.h b/Source/JavaScriptCore/runtime/JSFunction.h index 322ee58e3..da50f9581 100644 --- a/Source/JavaScriptCore/runtime/JSFunction.h +++ b/Source/JavaScriptCore/runtime/JSFunction.h @@ -27,6 +27,7 @@ #include "InternalFunction.h" #include "JSDestructibleObject.h" #include "JSScope.h" +#include "ObjectAllocationProfile.h" #include "Watchpoint.h" namespace JSC { @@ -52,7 +53,7 @@ namespace JSC { friend class JIT; friend class DFG::SpeculativeJIT; friend class DFG::JITCompiler; - friend class JSGlobalData; + friend class VM; public: typedef JSDestructibleObject Base; @@ -61,10 +62,10 @@ namespace JSC { static JSFunction* create(ExecState* exec, FunctionExecutable* executable, JSScope* scope) { - JSGlobalData& globalData = exec->globalData(); - JSFunction* function = new (NotNull, allocateCell<JSFunction>(globalData.heap)) JSFunction(globalData, executable, scope); + VM& vm = exec->vm(); + JSFunction* function = new (NotNull, allocateCell<JSFunction>(vm.heap)) JSFunction(vm, executable, scope); ASSERT(function->structure()->globalObject()); - function->finishCreation(globalData); + function->finishCreation(vm); return function; } @@ -88,10 +89,10 @@ namespace JSC { { return m_scope.get(); } - void setScope(JSGlobalData& globalData, JSScope* scope) + void setScope(VM& vm, JSScope* scope) { ASSERT(!isHostFunctionNonInline()); - m_scope.set(globalData, this, scope); + m_scope.set(vm, this, scope); } ExecutableBase* executable() const { return m_executable.get(); } @@ -104,10 +105,10 @@ namespace JSC { static JS_EXPORTDATA const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { ASSERT(globalObject); - return Structure::create(globalData, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), &s_info); } NativeFunction nativeFunction(); @@ -116,53 +117,53 @@ namespace JSC { static ConstructType getConstructData(JSCell*, ConstructData&); static CallType getCallData(JSCell*, CallData&); - static inline size_t offsetOfScopeChain() + static inline ptrdiff_t offsetOfScopeChain() { return OBJECT_OFFSETOF(JSFunction, m_scope); } - static inline size_t offsetOfExecutable() + static inline ptrdiff_t offsetOfExecutable() { return OBJECT_OFFSETOF(JSFunction, m_executable); } - Structure* cachedInheritorID(ExecState* exec) + static inline ptrdiff_t offsetOfAllocationProfile() { - if (UNLIKELY(!m_cachedInheritorID)) - return cacheInheritorID(exec); - return m_cachedInheritorID.get(); + return OBJECT_OFFSETOF(JSFunction, m_allocationProfile); } - Structure* tryGetKnownInheritorID() + ObjectAllocationProfile* allocationProfile(ExecState* exec, unsigned inlineCapacity) { - if (!m_cachedInheritorID) + if (UNLIKELY(m_allocationProfile.isNull())) + return createAllocationProfile(exec, inlineCapacity); + return &m_allocationProfile; + } + + ObjectAllocationProfile* tryGetAllocationProfile() + { + if (m_allocationProfile.isNull()) return 0; - if (m_inheritorIDWatchpoint.hasBeenInvalidated()) + if (m_allocationProfileWatchpoint.hasBeenInvalidated()) return 0; - return m_cachedInheritorID.get(); + return &m_allocationProfile; } - void addInheritorIDWatchpoint(Watchpoint* watchpoint) - { - ASSERT(tryGetKnownInheritorID()); - m_inheritorIDWatchpoint.add(watchpoint); - } - - static size_t offsetOfCachedInheritorID() + void addAllocationProfileWatchpoint(Watchpoint* watchpoint) { - return OBJECT_OFFSETOF(JSFunction, m_cachedInheritorID); + ASSERT(tryGetAllocationProfile()); + m_allocationProfileWatchpoint.add(watchpoint); } protected: const static unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags; JS_EXPORT_PRIVATE JSFunction(ExecState*, JSGlobalObject*, Structure*); - JSFunction(JSGlobalData&, FunctionExecutable*, JSScope*); + JSFunction(VM&, FunctionExecutable*, JSScope*); void finishCreation(ExecState*, NativeExecutable*, int length, const String& name); using Base::finishCreation; - Structure* cacheInheritorID(ExecState*); + ObjectAllocationProfile* createAllocationProfile(ExecState*, size_t inlineCapacity); static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); @@ -187,15 +188,10 @@ namespace JSC { WriteBarrier<ExecutableBase> m_executable; WriteBarrier<JSScope> m_scope; - WriteBarrier<Structure> m_cachedInheritorID; - InlineWatchpointSet m_inheritorIDWatchpoint; + ObjectAllocationProfile m_allocationProfile; + InlineWatchpointSet m_allocationProfileWatchpoint; }; - inline bool JSValue::isFunction() const - { - return isCell() && (asCell()->inherits(&JSFunction::s_info) || asCell()->inherits(&InternalFunction::s_info)); - } - } // namespace JSC #endif // JSFunction_h diff --git a/Source/JavaScriptCore/runtime/JSFunctionInlines.h b/Source/JavaScriptCore/runtime/JSFunctionInlines.h new file mode 100644 index 000000000..4f89acd7b --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSFunctionInlines.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2013 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 JSFunctionInlines_h +#define JSFunctionInlines_h + +#include "Executable.h" +#include "JSFunction.h" + +namespace JSC { + +inline JSFunction::JSFunction(VM& vm, FunctionExecutable* executable, JSScope* scope) + : Base(vm, scope->globalObject()->functionStructure()) + , m_executable(vm, this, executable) + , m_scope(vm, this, scope) + , m_allocationProfileWatchpoint(InitializedBlind) // See comment in JSFunction.cpp concerning the reason for using InitializedBlind as opposed to InitializedWatching. +{ +} + +inline FunctionExecutable* JSFunction::jsExecutable() const +{ + ASSERT(!isHostFunctionNonInline()); + return static_cast<FunctionExecutable*>(m_executable.get()); +} + +inline bool JSFunction::isHostFunction() const +{ + ASSERT(m_executable); + return m_executable->isHostFunction(); +} + +inline NativeFunction JSFunction::nativeFunction() +{ + ASSERT(isHostFunction()); + return static_cast<NativeExecutable*>(m_executable.get())->function(); +} + +inline NativeFunction JSFunction::nativeConstructor() +{ + ASSERT(isHostFunction()); + return static_cast<NativeExecutable*>(m_executable.get())->constructor(); +} + +} // namespace JSC + +#endif // JSFunctionInlines_h + diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp index 6f20f0e93..2fb5d34be 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -47,6 +47,7 @@ #include "FunctionPrototype.h" #include "GetterSetter.h" #include "Interpreter.h" +#include "JSAPIWrapperObject.h" #include "JSActivation.h" #include "JSBoundFunction.h" #include "JSCallbackConstructor.h" @@ -58,6 +59,7 @@ #include "JSNameScope.h" #include "JSONObject.h" #include "JSWithScope.h" +#include "LegacyProfiler.h" #include "Lookup.h" #include "MathObject.h" #include "NameConstructor.h" @@ -67,9 +69,11 @@ #include "NativeErrorPrototype.h" #include "NumberConstructor.h" #include "NumberPrototype.h" +#include "ObjCCallbackFunction.h" #include "ObjectConstructor.h" #include "ObjectPrototype.h" -#include "Profiler.h" +#include "Operations.h" +#include "ParserError.h" #include "RegExpConstructor.h" #include "RegExpMatchesArray.h" #include "RegExpObject.h" @@ -101,14 +105,8 @@ const GlobalObjectMethodTable JSGlobalObject::s_globalObjectMethodTable = { &all @end */ -// Default number of ticks before a timeout check should be done. -static const int initialTickCountThreshold = 255; - -// Preferred number of milliseconds between each timeout check -static const int preferredScriptCheckTimeInterval = 1000; - -JSGlobalObject::JSGlobalObject(JSGlobalData& globalData, Structure* structure, const GlobalObjectMethodTable* globalObjectMethodTable) - : Base(globalData, structure, 0) +JSGlobalObject::JSGlobalObject(VM& vm, Structure* structure, const GlobalObjectMethodTable* globalObjectMethodTable) + : Base(vm, structure, 0) , m_masqueradesAsUndefinedWatchpoint(adoptRef(new WatchpointSet(InitializedWatching))) , m_havingABadTimeWatchpoint(adoptRef(new WatchpointSet(InitializedWatching))) , m_weakRandom(Options::forceWeakRandomSeed() ? Options::forcedWeakRandomSeed() : static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0))) @@ -122,7 +120,7 @@ JSGlobalObject::~JSGlobalObject() if (m_debugger) m_debugger->detach(this); - if (Profiler* profiler = globalData().enabledProfiler()) + if (LegacyProfiler* profiler = vm().enabledProfiler()) profiler->stopProfiling(this); } @@ -131,16 +129,16 @@ void JSGlobalObject::destroy(JSCell* cell) static_cast<JSGlobalObject*>(cell)->JSGlobalObject::~JSGlobalObject(); } -void JSGlobalObject::setGlobalThis(JSGlobalData& globalData, JSObject* globalThis) +void JSGlobalObject::setGlobalThis(VM& vm, JSObject* globalThis) { - m_globalThis.set(globalData, this, globalThis); + m_globalThis.set(vm, this, globalThis); } void JSGlobalObject::init(JSObject* thisValue) { - ASSERT(globalData().apiLock().currentThreadIsHoldingLock()); + ASSERT(vm().apiLock().currentThreadIsHoldingLock()); - setGlobalThis(globalData(), thisValue); + setGlobalThis(vm(), thisValue); JSGlobalObject::globalExec()->init(0, 0, this, CallFrame::noCaller(), 0, 0); m_debugger = 0; @@ -163,14 +161,14 @@ void JSGlobalObject::putDirectVirtual(JSObject* object, ExecState* exec, Propert JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(object); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); - if (symbolTablePutWithAttributes(thisObject, exec->globalData(), propertyName, value, attributes)) + if (symbolTablePutWithAttributes(thisObject, exec->vm(), propertyName, value, attributes)) return; - JSValue valueBefore = thisObject->getDirect(exec->globalData(), propertyName); + JSValue valueBefore = thisObject->getDirect(exec->vm(), propertyName); PutPropertySlot slot; Base::put(thisObject, exec, propertyName, value, slot); if (!valueBefore) { - JSValue valueAfter = thisObject->getDirect(exec->globalData(), propertyName); + JSValue valueAfter = thisObject->getDirect(exec->vm(), propertyName); if (valueAfter) JSObject::putDirectVirtual(thisObject, exec, propertyName, valueAfter, attributes); } @@ -199,128 +197,131 @@ void JSGlobalObject::reset(JSValue prototype) { ExecState* exec = JSGlobalObject::globalExec(); - m_functionPrototype.set(exec->globalData(), this, FunctionPrototype::create(exec, this, FunctionPrototype::createStructure(exec->globalData(), this, jsNull()))); // The real prototype will be set once ObjectPrototype is created. - m_functionStructure.set(exec->globalData(), this, JSFunction::createStructure(exec->globalData(), this, m_functionPrototype.get())); - m_boundFunctionStructure.set(exec->globalData(), this, JSBoundFunction::createStructure(exec->globalData(), this, m_functionPrototype.get())); - m_namedFunctionStructure.set(exec->globalData(), this, Structure::addPropertyTransition(exec->globalData(), m_functionStructure.get(), exec->globalData().propertyNames->name, DontDelete | ReadOnly | DontEnum, 0, m_functionNameOffset)); - m_internalFunctionStructure.set(exec->globalData(), this, InternalFunction::createStructure(exec->globalData(), this, m_functionPrototype.get())); + m_functionPrototype.set(exec->vm(), this, FunctionPrototype::create(exec, this, FunctionPrototype::createStructure(exec->vm(), this, jsNull()))); // The real prototype will be set once ObjectPrototype is created. + m_functionStructure.set(exec->vm(), this, JSFunction::createStructure(exec->vm(), this, m_functionPrototype.get())); + m_boundFunctionStructure.set(exec->vm(), this, JSBoundFunction::createStructure(exec->vm(), this, m_functionPrototype.get())); + m_namedFunctionStructure.set(exec->vm(), this, Structure::addPropertyTransition(exec->vm(), m_functionStructure.get(), exec->vm().propertyNames->name, DontDelete | ReadOnly | DontEnum, 0, m_functionNameOffset)); + m_internalFunctionStructure.set(exec->vm(), this, InternalFunction::createStructure(exec->vm(), this, m_functionPrototype.get())); JSFunction* callFunction = 0; JSFunction* applyFunction = 0; m_functionPrototype->addFunctionProperties(exec, this, &callFunction, &applyFunction); - m_callFunction.set(exec->globalData(), this, callFunction); - m_applyFunction.set(exec->globalData(), this, applyFunction); - m_objectPrototype.set(exec->globalData(), this, ObjectPrototype::create(exec, this, ObjectPrototype::createStructure(exec->globalData(), this, jsNull()))); + m_callFunction.set(exec->vm(), this, callFunction); + m_applyFunction.set(exec->vm(), this, applyFunction); + m_objectPrototype.set(exec->vm(), this, ObjectPrototype::create(exec, this, ObjectPrototype::createStructure(exec->vm(), this, jsNull()))); GetterSetter* protoAccessor = GetterSetter::create(exec); - protoAccessor->setGetter(exec->globalData(), JSFunction::create(exec, this, 0, String(), globalFuncProtoGetter)); - protoAccessor->setSetter(exec->globalData(), JSFunction::create(exec, this, 0, String(), globalFuncProtoSetter)); + protoAccessor->setGetter(exec->vm(), JSFunction::create(exec, this, 0, String(), globalFuncProtoGetter)); + protoAccessor->setSetter(exec->vm(), JSFunction::create(exec, this, 0, String(), globalFuncProtoSetter)); m_objectPrototype->putDirectAccessor(exec, exec->propertyNames().underscoreProto, protoAccessor, Accessor | DontEnum); - m_functionPrototype->structure()->setPrototypeWithoutTransition(exec->globalData(), m_objectPrototype.get()); - - m_nameScopeStructure.set(exec->globalData(), this, JSNameScope::createStructure(exec->globalData(), this, jsNull())); - m_activationStructure.set(exec->globalData(), this, JSActivation::createStructure(exec->globalData(), this, jsNull())); - m_strictEvalActivationStructure.set(exec->globalData(), this, StrictEvalActivation::createStructure(exec->globalData(), this, jsNull())); - m_withScopeStructure.set(exec->globalData(), this, JSWithScope::createStructure(exec->globalData(), this, jsNull())); - - m_emptyObjectStructure.set(exec->globalData(), this, m_objectPrototype->inheritorID(exec->globalData())); - m_nullPrototypeObjectStructure.set(exec->globalData(), this, createEmptyObjectStructure(exec->globalData(), this, jsNull())); - - m_callbackFunctionStructure.set(exec->globalData(), this, JSCallbackFunction::createStructure(exec->globalData(), this, m_functionPrototype.get())); - m_argumentsStructure.set(exec->globalData(), this, Arguments::createStructure(exec->globalData(), this, m_objectPrototype.get())); - m_callbackConstructorStructure.set(exec->globalData(), this, JSCallbackConstructor::createStructure(exec->globalData(), this, m_objectPrototype.get())); - m_callbackObjectStructure.set(exec->globalData(), this, JSCallbackObject<JSDestructibleObject>::createStructure(exec->globalData(), this, m_objectPrototype.get())); + m_functionPrototype->structure()->setPrototypeWithoutTransition(exec->vm(), m_objectPrototype.get()); + + m_nameScopeStructure.set(exec->vm(), this, JSNameScope::createStructure(exec->vm(), this, jsNull())); + m_activationStructure.set(exec->vm(), this, JSActivation::createStructure(exec->vm(), this, jsNull())); + m_strictEvalActivationStructure.set(exec->vm(), this, StrictEvalActivation::createStructure(exec->vm(), this, jsNull())); + m_withScopeStructure.set(exec->vm(), this, JSWithScope::createStructure(exec->vm(), this, jsNull())); + + m_nullPrototypeObjectStructure.set(exec->vm(), this, JSFinalObject::createStructure(vm(), this, jsNull(), JSFinalObject::defaultInlineCapacity())); + + m_callbackFunctionStructure.set(exec->vm(), this, JSCallbackFunction::createStructure(exec->vm(), this, m_functionPrototype.get())); + m_argumentsStructure.set(exec->vm(), this, Arguments::createStructure(exec->vm(), this, m_objectPrototype.get())); + m_callbackConstructorStructure.set(exec->vm(), this, JSCallbackConstructor::createStructure(exec->vm(), this, m_objectPrototype.get())); + m_callbackObjectStructure.set(exec->vm(), this, JSCallbackObject<JSDestructibleObject>::createStructure(exec->vm(), this, m_objectPrototype.get())); +#if JSC_OBJC_API_ENABLED + m_objcCallbackFunctionStructure.set(exec->vm(), this, ObjCCallbackFunction::createStructure(exec->vm(), this, m_functionPrototype.get())); + m_objcWrapperObjectStructure.set(exec->vm(), this, JSCallbackObject<JSAPIWrapperObject>::createStructure(exec->vm(), this, m_objectPrototype.get())); +#endif - m_arrayPrototype.set(exec->globalData(), this, ArrayPrototype::create(exec, this, ArrayPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get()))); + m_arrayPrototype.set(exec->vm(), this, ArrayPrototype::create(exec, this, ArrayPrototype::createStructure(exec->vm(), this, m_objectPrototype.get()))); - m_originalArrayStructureForIndexingShape[UndecidedShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithUndecided)); - m_originalArrayStructureForIndexingShape[Int32Shape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithInt32)); - m_originalArrayStructureForIndexingShape[DoubleShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithDouble)); - m_originalArrayStructureForIndexingShape[ContiguousShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithContiguous)); - m_originalArrayStructureForIndexingShape[ArrayStorageShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithArrayStorage)); - m_originalArrayStructureForIndexingShape[SlowPutArrayStorageShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithSlowPutArrayStorage)); + m_originalArrayStructureForIndexingShape[UndecidedShape >> IndexingShapeShift].set(exec->vm(), this, JSArray::createStructure(exec->vm(), this, m_arrayPrototype.get(), ArrayWithUndecided)); + m_originalArrayStructureForIndexingShape[Int32Shape >> IndexingShapeShift].set(exec->vm(), this, JSArray::createStructure(exec->vm(), this, m_arrayPrototype.get(), ArrayWithInt32)); + m_originalArrayStructureForIndexingShape[DoubleShape >> IndexingShapeShift].set(exec->vm(), this, JSArray::createStructure(exec->vm(), this, m_arrayPrototype.get(), ArrayWithDouble)); + m_originalArrayStructureForIndexingShape[ContiguousShape >> IndexingShapeShift].set(exec->vm(), this, JSArray::createStructure(exec->vm(), this, m_arrayPrototype.get(), ArrayWithContiguous)); + m_originalArrayStructureForIndexingShape[ArrayStorageShape >> IndexingShapeShift].set(exec->vm(), this, JSArray::createStructure(exec->vm(), this, m_arrayPrototype.get(), ArrayWithArrayStorage)); + m_originalArrayStructureForIndexingShape[SlowPutArrayStorageShape >> IndexingShapeShift].set(exec->vm(), this, JSArray::createStructure(exec->vm(), this, m_arrayPrototype.get(), ArrayWithSlowPutArrayStorage)); for (unsigned i = 0; i < NumberOfIndexingShapes; ++i) m_arrayStructureForIndexingShapeDuringAllocation[i] = m_originalArrayStructureForIndexingShape[i]; - m_regExpMatchesArrayStructure.set(exec->globalData(), this, RegExpMatchesArray::createStructure(exec->globalData(), this, m_arrayPrototype.get())); + m_regExpMatchesArrayStructure.set(exec->vm(), this, RegExpMatchesArray::createStructure(exec->vm(), this, m_arrayPrototype.get())); - m_stringPrototype.set(exec->globalData(), this, StringPrototype::create(exec, this, StringPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get()))); - m_stringObjectStructure.set(exec->globalData(), this, StringObject::createStructure(exec->globalData(), this, m_stringPrototype.get())); + m_stringPrototype.set(exec->vm(), this, StringPrototype::create(exec, this, StringPrototype::createStructure(exec->vm(), this, m_objectPrototype.get()))); + m_stringObjectStructure.set(exec->vm(), this, StringObject::createStructure(exec->vm(), this, m_stringPrototype.get())); - m_booleanPrototype.set(exec->globalData(), this, BooleanPrototype::create(exec, this, BooleanPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get()))); - m_booleanObjectStructure.set(exec->globalData(), this, BooleanObject::createStructure(exec->globalData(), this, m_booleanPrototype.get())); + m_booleanPrototype.set(exec->vm(), this, BooleanPrototype::create(exec, this, BooleanPrototype::createStructure(exec->vm(), this, m_objectPrototype.get()))); + m_booleanObjectStructure.set(exec->vm(), this, BooleanObject::createStructure(exec->vm(), this, m_booleanPrototype.get())); - m_numberPrototype.set(exec->globalData(), this, NumberPrototype::create(exec, this, NumberPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get()))); - m_numberObjectStructure.set(exec->globalData(), this, NumberObject::createStructure(exec->globalData(), this, m_numberPrototype.get())); + m_numberPrototype.set(exec->vm(), this, NumberPrototype::create(exec, this, NumberPrototype::createStructure(exec->vm(), this, m_objectPrototype.get()))); + m_numberObjectStructure.set(exec->vm(), this, NumberObject::createStructure(exec->vm(), this, m_numberPrototype.get())); - m_datePrototype.set(exec->globalData(), this, DatePrototype::create(exec, this, DatePrototype::createStructure(exec->globalData(), this, m_objectPrototype.get()))); - m_dateStructure.set(exec->globalData(), this, DateInstance::createStructure(exec->globalData(), this, m_datePrototype.get())); + m_datePrototype.set(exec->vm(), this, DatePrototype::create(exec, this, DatePrototype::createStructure(exec->vm(), this, m_objectPrototype.get()))); + m_dateStructure.set(exec->vm(), this, DateInstance::createStructure(exec->vm(), this, m_datePrototype.get())); - RegExp* emptyRegex = RegExp::create(exec->globalData(), "", NoFlags); + RegExp* emptyRegex = RegExp::create(exec->vm(), "", NoFlags); - m_regExpPrototype.set(exec->globalData(), this, RegExpPrototype::create(exec, this, RegExpPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get()), emptyRegex)); - m_regExpStructure.set(exec->globalData(), this, RegExpObject::createStructure(exec->globalData(), this, m_regExpPrototype.get())); + m_regExpPrototype.set(exec->vm(), this, RegExpPrototype::create(exec, this, RegExpPrototype::createStructure(exec->vm(), this, m_objectPrototype.get()), emptyRegex)); + m_regExpStructure.set(exec->vm(), this, RegExpObject::createStructure(exec->vm(), this, m_regExpPrototype.get())); - m_errorPrototype.set(exec->globalData(), this, ErrorPrototype::create(exec, this, ErrorPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get()))); - m_errorStructure.set(exec->globalData(), this, ErrorInstance::createStructure(exec->globalData(), this, m_errorPrototype.get())); + m_errorPrototype.set(exec->vm(), this, ErrorPrototype::create(exec, this, ErrorPrototype::createStructure(exec->vm(), this, m_objectPrototype.get()))); + m_errorStructure.set(exec->vm(), this, ErrorInstance::createStructure(exec->vm(), this, m_errorPrototype.get())); // Constructors - JSCell* objectConstructor = ObjectConstructor::create(exec, this, ObjectConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), m_objectPrototype.get()); - JSCell* functionConstructor = FunctionConstructor::create(exec, this, FunctionConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), m_functionPrototype.get()); - JSCell* arrayConstructor = ArrayConstructor::create(exec, this, ArrayConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), m_arrayPrototype.get()); - JSCell* stringConstructor = StringConstructor::create(exec, this, StringConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), m_stringPrototype.get()); - JSCell* booleanConstructor = BooleanConstructor::create(exec, this, BooleanConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), m_booleanPrototype.get()); - JSCell* numberConstructor = NumberConstructor::create(exec, this, NumberConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), m_numberPrototype.get()); - JSCell* dateConstructor = DateConstructor::create(exec, this, DateConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), m_datePrototype.get()); - - m_regExpConstructor.set(exec->globalData(), this, RegExpConstructor::create(exec, this, RegExpConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), m_regExpPrototype.get())); - - m_errorConstructor.set(exec->globalData(), this, ErrorConstructor::create(exec, this, ErrorConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), m_errorPrototype.get())); - - Structure* nativeErrorPrototypeStructure = NativeErrorPrototype::createStructure(exec->globalData(), this, m_errorPrototype.get()); - Structure* nativeErrorStructure = NativeErrorConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()); - m_evalErrorConstructor.set(exec->globalData(), this, NativeErrorConstructor::create(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("EvalError"))); - m_rangeErrorConstructor.set(exec->globalData(), this, NativeErrorConstructor::create(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("RangeError"))); - m_referenceErrorConstructor.set(exec->globalData(), this, NativeErrorConstructor::create(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("ReferenceError"))); - m_syntaxErrorConstructor.set(exec->globalData(), this, NativeErrorConstructor::create(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("SyntaxError"))); - m_typeErrorConstructor.set(exec->globalData(), this, NativeErrorConstructor::create(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("TypeError"))); - m_URIErrorConstructor.set(exec->globalData(), this, NativeErrorConstructor::create(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("URIError"))); - - m_objectPrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, objectConstructor, DontEnum); - m_functionPrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, functionConstructor, DontEnum); - m_arrayPrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, arrayConstructor, DontEnum); - m_booleanPrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, booleanConstructor, DontEnum); - m_stringPrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, stringConstructor, DontEnum); - m_numberPrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, numberConstructor, DontEnum); - m_datePrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, dateConstructor, DontEnum); - m_regExpPrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, m_regExpConstructor.get(), DontEnum); - m_errorPrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, m_errorConstructor.get(), DontEnum); - - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().Object, objectConstructor, DontEnum); - putDirectWithoutTransition(exec->globalData(), Identifier(exec, "Function"), functionConstructor, DontEnum); - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().Array, arrayConstructor, DontEnum); - putDirectWithoutTransition(exec->globalData(), Identifier(exec, "Boolean"), booleanConstructor, DontEnum); - putDirectWithoutTransition(exec->globalData(), Identifier(exec, "String"), stringConstructor, DontEnum); - putDirectWithoutTransition(exec->globalData(), Identifier(exec, "Number"), numberConstructor, DontEnum); - putDirectWithoutTransition(exec->globalData(), Identifier(exec, "Date"), dateConstructor, DontEnum); - putDirectWithoutTransition(exec->globalData(), Identifier(exec, "RegExp"), m_regExpConstructor.get(), DontEnum); - putDirectWithoutTransition(exec->globalData(), Identifier(exec, "Error"), m_errorConstructor.get(), DontEnum); - putDirectWithoutTransition(exec->globalData(), Identifier(exec, "EvalError"), m_evalErrorConstructor.get(), DontEnum); - putDirectWithoutTransition(exec->globalData(), Identifier(exec, "RangeError"), m_rangeErrorConstructor.get(), DontEnum); - putDirectWithoutTransition(exec->globalData(), Identifier(exec, "ReferenceError"), m_referenceErrorConstructor.get(), DontEnum); - putDirectWithoutTransition(exec->globalData(), Identifier(exec, "SyntaxError"), m_syntaxErrorConstructor.get(), DontEnum); - putDirectWithoutTransition(exec->globalData(), Identifier(exec, "TypeError"), m_typeErrorConstructor.get(), DontEnum); - putDirectWithoutTransition(exec->globalData(), Identifier(exec, "URIError"), m_URIErrorConstructor.get(), DontEnum); - - m_evalFunction.set(exec->globalData(), this, JSFunction::create(exec, this, 1, exec->propertyNames().eval.string(), globalFuncEval)); - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().eval, m_evalFunction.get(), DontEnum); - - putDirectWithoutTransition(exec->globalData(), Identifier(exec, "JSON"), JSONObject::create(exec, this, JSONObject::createStructure(exec->globalData(), this, m_objectPrototype.get())), DontEnum); - putDirectWithoutTransition(exec->globalData(), Identifier(exec, "Math"), MathObject::create(exec, this, MathObject::createStructure(exec->globalData(), this, m_objectPrototype.get())), DontEnum); + JSCell* objectConstructor = ObjectConstructor::create(exec, this, ObjectConstructor::createStructure(exec->vm(), this, m_functionPrototype.get()), m_objectPrototype.get()); + JSCell* functionConstructor = FunctionConstructor::create(exec, this, FunctionConstructor::createStructure(exec->vm(), this, m_functionPrototype.get()), m_functionPrototype.get()); + JSCell* arrayConstructor = ArrayConstructor::create(exec, this, ArrayConstructor::createStructure(exec->vm(), this, m_functionPrototype.get()), m_arrayPrototype.get()); + JSCell* stringConstructor = StringConstructor::create(exec, this, StringConstructor::createStructure(exec->vm(), this, m_functionPrototype.get()), m_stringPrototype.get()); + JSCell* booleanConstructor = BooleanConstructor::create(exec, this, BooleanConstructor::createStructure(exec->vm(), this, m_functionPrototype.get()), m_booleanPrototype.get()); + JSCell* numberConstructor = NumberConstructor::create(exec, this, NumberConstructor::createStructure(exec->vm(), this, m_functionPrototype.get()), m_numberPrototype.get()); + JSCell* dateConstructor = DateConstructor::create(exec, this, DateConstructor::createStructure(exec->vm(), this, m_functionPrototype.get()), m_datePrototype.get()); + + m_regExpConstructor.set(exec->vm(), this, RegExpConstructor::create(exec, this, RegExpConstructor::createStructure(exec->vm(), this, m_functionPrototype.get()), m_regExpPrototype.get())); + + m_errorConstructor.set(exec->vm(), this, ErrorConstructor::create(exec, this, ErrorConstructor::createStructure(exec->vm(), this, m_functionPrototype.get()), m_errorPrototype.get())); + + Structure* nativeErrorPrototypeStructure = NativeErrorPrototype::createStructure(exec->vm(), this, m_errorPrototype.get()); + Structure* nativeErrorStructure = NativeErrorConstructor::createStructure(exec->vm(), this, m_functionPrototype.get()); + m_evalErrorConstructor.set(exec->vm(), this, NativeErrorConstructor::create(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("EvalError"))); + m_rangeErrorConstructor.set(exec->vm(), this, NativeErrorConstructor::create(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("RangeError"))); + m_referenceErrorConstructor.set(exec->vm(), this, NativeErrorConstructor::create(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("ReferenceError"))); + m_syntaxErrorConstructor.set(exec->vm(), this, NativeErrorConstructor::create(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("SyntaxError"))); + m_typeErrorConstructor.set(exec->vm(), this, NativeErrorConstructor::create(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("TypeError"))); + m_URIErrorConstructor.set(exec->vm(), this, NativeErrorConstructor::create(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("URIError"))); + + m_objectPrototype->putDirectWithoutTransition(exec->vm(), exec->propertyNames().constructor, objectConstructor, DontEnum); + m_functionPrototype->putDirectWithoutTransition(exec->vm(), exec->propertyNames().constructor, functionConstructor, DontEnum); + m_arrayPrototype->putDirectWithoutTransition(exec->vm(), exec->propertyNames().constructor, arrayConstructor, DontEnum); + m_booleanPrototype->putDirectWithoutTransition(exec->vm(), exec->propertyNames().constructor, booleanConstructor, DontEnum); + m_stringPrototype->putDirectWithoutTransition(exec->vm(), exec->propertyNames().constructor, stringConstructor, DontEnum); + m_numberPrototype->putDirectWithoutTransition(exec->vm(), exec->propertyNames().constructor, numberConstructor, DontEnum); + m_datePrototype->putDirectWithoutTransition(exec->vm(), exec->propertyNames().constructor, dateConstructor, DontEnum); + m_regExpPrototype->putDirectWithoutTransition(exec->vm(), exec->propertyNames().constructor, m_regExpConstructor.get(), DontEnum); + m_errorPrototype->putDirectWithoutTransition(exec->vm(), exec->propertyNames().constructor, m_errorConstructor.get(), DontEnum); + + putDirectWithoutTransition(exec->vm(), exec->propertyNames().Object, objectConstructor, DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().Function, functionConstructor, DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().Array, arrayConstructor, DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().Boolean, booleanConstructor, DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().String, stringConstructor, DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().Number, numberConstructor, DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().Date, dateConstructor, DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().RegExp, m_regExpConstructor.get(), DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().Error, m_errorConstructor.get(), DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().EvalError, m_evalErrorConstructor.get(), DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().RangeError, m_rangeErrorConstructor.get(), DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().ReferenceError, m_referenceErrorConstructor.get(), DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().SyntaxError, m_syntaxErrorConstructor.get(), DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().TypeError, m_typeErrorConstructor.get(), DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().URIError, m_URIErrorConstructor.get(), DontEnum); + + m_evalFunction.set(exec->vm(), this, JSFunction::create(exec, this, 1, exec->propertyNames().eval.string(), globalFuncEval)); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().eval, m_evalFunction.get(), DontEnum); + + putDirectWithoutTransition(exec->vm(), exec->propertyNames().JSON, JSONObject::create(exec, this, JSONObject::createStructure(exec->vm(), this, m_objectPrototype.get())), DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().Math, MathObject::create(exec, this, MathObject::createStructure(exec->vm(), this, m_objectPrototype.get())), DontEnum); GlobalPropertyInfo staticGlobals[] = { - GlobalPropertyInfo(Identifier(exec, "NaN"), jsNaN(), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(Identifier(exec, "Infinity"), jsNumber(std::numeric_limits<double>::infinity()), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(Identifier(exec, "undefined"), jsUndefined(), DontEnum | DontDelete | ReadOnly) + GlobalPropertyInfo(exec->propertyNames().NaN, jsNaN(), DontEnum | DontDelete | ReadOnly), + GlobalPropertyInfo(exec->propertyNames().Infinity, jsNumber(std::numeric_limits<double>::infinity()), DontEnum | DontDelete | ReadOnly), + GlobalPropertyInfo(exec->propertyNames().undefinedKeyword, jsUndefined(), DontEnum | DontDelete | ReadOnly) }; addStaticGlobals(staticGlobals, WTF_ARRAY_LENGTH(staticGlobals)); @@ -330,15 +331,15 @@ void JSGlobalObject::reset(JSValue prototype) m_specialPointers[Special::ArrayConstructor] = arrayConstructor; if (m_experimentsEnabled) { - NamePrototype* privateNamePrototype = NamePrototype::create(exec, NamePrototype::createStructure(exec->globalData(), this, m_objectPrototype.get())); - m_privateNameStructure.set(exec->globalData(), this, NameInstance::createStructure(exec->globalData(), this, privateNamePrototype)); + NamePrototype* privateNamePrototype = NamePrototype::create(exec, NamePrototype::createStructure(exec->vm(), this, m_objectPrototype.get())); + m_privateNameStructure.set(exec->vm(), this, NameInstance::createStructure(exec->vm(), this, privateNamePrototype)); - JSCell* privateNameConstructor = NameConstructor::create(exec, this, NameConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), privateNamePrototype); - privateNamePrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, privateNameConstructor, DontEnum); - putDirectWithoutTransition(exec->globalData(), Identifier(exec, "Name"), privateNameConstructor, DontEnum); + JSCell* privateNameConstructor = NameConstructor::create(exec, this, NameConstructor::createStructure(exec->vm(), this, m_functionPrototype.get()), privateNamePrototype); + privateNamePrototype->putDirectWithoutTransition(exec->vm(), exec->propertyNames().constructor, privateNameConstructor, DontEnum); + putDirectWithoutTransition(exec->vm(), Identifier(exec, "Name"), privateNameConstructor, DontEnum); } - resetPrototype(exec->globalData(), prototype); + resetPrototype(exec->vm(), prototype); } // Private namespace for helpers for JSGlobalObject::haveABadTime() @@ -404,9 +405,9 @@ void ObjectsWithBrokenIndexingFinder::operator()(JSCell* cell) } // end private namespace for helpers for JSGlobalObject::haveABadTime() -void JSGlobalObject::haveABadTime(JSGlobalData& globalData) +void JSGlobalObject::haveABadTime(VM& vm) { - ASSERT(&globalData == &this->globalData()); + ASSERT(&vm == &this->vm()); if (isHavingABadTime()) return; @@ -420,18 +421,18 @@ void JSGlobalObject::haveABadTime(JSGlobalData& globalData) // Make sure that all JSArray allocations that load the appropriate structure from // this object now load a structure that uses SlowPut. for (unsigned i = 0; i < NumberOfIndexingShapes; ++i) - m_arrayStructureForIndexingShapeDuringAllocation[i].set(globalData, this, originalArrayStructureForIndexingType(ArrayWithSlowPutArrayStorage)); + m_arrayStructureForIndexingShapeDuringAllocation[i].set(vm, this, originalArrayStructureForIndexingType(ArrayWithSlowPutArrayStorage)); // Make sure that all objects that have indexed storage switch to the slow kind of // indexed storage. MarkedArgumentBuffer foundObjects; // Use MarkedArgumentBuffer because switchToSlowPutArrayStorage() may GC. ObjectsWithBrokenIndexingFinder finder(foundObjects, this); - globalData.heap.objectSpace().forEachLiveCell(finder); + vm.heap.objectSpace().forEachLiveCell(finder); while (!foundObjects.isEmpty()) { JSObject* object = asObject(foundObjects.last()); foundObjects.removeLast(); ASSERT(hasBrokenIndexing(object)); - object->switchToSlowPutArrayStorage(globalData); + object->switchToSlowPutArrayStorage(vm); } } @@ -447,20 +448,20 @@ void JSGlobalObject::createThrowTypeError(ExecState* exec) { JSFunction* thrower = JSFunction::create(exec, this, 0, String(), globalFuncThrowTypeError); GetterSetter* getterSetter = GetterSetter::create(exec); - getterSetter->setGetter(exec->globalData(), thrower); - getterSetter->setSetter(exec->globalData(), thrower); - m_throwTypeErrorGetterSetter.set(exec->globalData(), this, getterSetter); + getterSetter->setGetter(exec->vm(), thrower); + getterSetter->setSetter(exec->vm(), thrower); + m_throwTypeErrorGetterSetter.set(exec->vm(), this, getterSetter); } // Set prototype, and also insert the object prototype at the end of the chain. -void JSGlobalObject::resetPrototype(JSGlobalData& globalData, JSValue prototype) +void JSGlobalObject::resetPrototype(VM& vm, JSValue prototype) { - setPrototype(globalData, prototype); + setPrototype(vm, prototype); JSObject* oldLastInPrototypeChain = lastInPrototypeChain(this); JSObject* objectPrototype = m_objectPrototype.get(); if (oldLastInPrototypeChain != objectPrototype) - oldLastInPrototypeChain->setPrototype(globalData, objectPrototype); + oldLastInPrototypeChain->setPrototype(vm, objectPrototype); } void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) @@ -510,8 +511,11 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) visitor.append(&thisObject->m_callbackConstructorStructure); visitor.append(&thisObject->m_callbackFunctionStructure); visitor.append(&thisObject->m_callbackObjectStructure); +#if JSC_OBJC_API_ENABLED + visitor.append(&thisObject->m_objcCallbackFunctionStructure); + visitor.append(&thisObject->m_objcWrapperObjectStructure); +#endif visitor.append(&thisObject->m_dateStructure); - visitor.append(&thisObject->m_emptyObjectStructure); visitor.append(&thisObject->m_nullPrototypeObjectStructure); visitor.append(&thisObject->m_errorStructure); visitor.append(&thisObject->m_functionStructure); @@ -546,7 +550,7 @@ void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count) int index = symbolTable()->size(); SymbolTableEntry newEntry(index, global.attributes); symbolTable()->add(global.identifier.impl(), newEntry); - registerAt(index).set(globalData(), this, global.value); + registerAt(index).set(vm(), this, global.value); } } @@ -571,28 +575,29 @@ void JSGlobalObject::clearRareData(JSCell* cell) jsCast<JSGlobalObject*>(cell)->m_rareData.clear(); } -DynamicGlobalObjectScope::DynamicGlobalObjectScope(JSGlobalData& globalData, JSGlobalObject* dynamicGlobalObject) - : m_dynamicGlobalObjectSlot(globalData.dynamicGlobalObject) +DynamicGlobalObjectScope::DynamicGlobalObjectScope(VM& vm, JSGlobalObject* dynamicGlobalObject) + : m_dynamicGlobalObjectSlot(vm.dynamicGlobalObject) , m_savedDynamicGlobalObject(m_dynamicGlobalObjectSlot) { if (!m_dynamicGlobalObjectSlot) { #if ENABLE(ASSEMBLER) if (ExecutableAllocator::underMemoryPressure()) - globalData.heap.deleteAllCompiledCode(); + vm.heap.deleteAllCompiledCode(); #endif m_dynamicGlobalObjectSlot = dynamicGlobalObject; // Reset the date cache between JS invocations to force the VM // to observe time zone changes. - globalData.resetDateCache(); + vm.resetDateCache(); } + // Clear the exception stack between entries + vm.clearExceptionStack(); } void slowValidateCell(JSGlobalObject* globalObject) { - if (!globalObject->isGlobalObject()) - CRASH(); + RELEASE_ASSERT(globalObject->isGlobalObject()); ASSERT_GC_OBJECT_INHERITS(globalObject, &JSGlobalObject::s_info); } @@ -602,7 +607,7 @@ UnlinkedProgramCodeBlock* JSGlobalObject::createProgramCodeBlock(CallFrame* call JSParserStrictness strictness = executable->isStrictMode() ? JSParseStrict : JSParseNormal; DebuggerMode debuggerMode = hasDebugger() ? DebuggerOn : DebuggerOff; ProfilerMode profilerMode = hasProfiler() ? ProfilerOn : ProfilerOff; - UnlinkedProgramCodeBlock* unlinkedCode = globalData().codeCache()->getProgramCodeBlock(globalData(), executable, executable->source(), strictness, debuggerMode, profilerMode, error); + UnlinkedProgramCodeBlock* unlinkedCode = vm().codeCache()->getProgramCodeBlock(vm(), executable, executable->source(), strictness, debuggerMode, profilerMode, error); if (hasDebugger()) debugger()->sourceParsed(callFrame, executable->source().provider(), error.m_line, error.m_message); @@ -615,13 +620,13 @@ UnlinkedProgramCodeBlock* JSGlobalObject::createProgramCodeBlock(CallFrame* call return unlinkedCode; } -UnlinkedEvalCodeBlock* JSGlobalObject::createEvalCodeBlock(CallFrame* callFrame, EvalExecutable* executable, JSObject** exception) +UnlinkedEvalCodeBlock* JSGlobalObject::createEvalCodeBlock(CodeCache* cache, CallFrame* callFrame, JSScope* scope, EvalExecutable* executable, JSObject** exception) { ParserError error; JSParserStrictness strictness = executable->isStrictMode() ? JSParseStrict : JSParseNormal; DebuggerMode debuggerMode = hasDebugger() ? DebuggerOn : DebuggerOff; ProfilerMode profilerMode = hasProfiler() ? ProfilerOn : ProfilerOff; - UnlinkedEvalCodeBlock* unlinkedCode = globalData().codeCache()->getEvalCodeBlock(globalData(), executable, executable->source(), strictness, debuggerMode, profilerMode, error); + UnlinkedEvalCodeBlock* unlinkedCode = cache->getEvalCodeBlock(vm(), scope, executable, executable->source(), strictness, debuggerMode, profilerMode, error); if (hasDebugger()) debugger()->sourceParsed(callFrame, executable->source().provider(), error.m_line, error.m_message); @@ -634,20 +639,4 @@ UnlinkedEvalCodeBlock* JSGlobalObject::createEvalCodeBlock(CallFrame* callFrame, return unlinkedCode; } -UnlinkedFunctionExecutable* JSGlobalObject::createFunctionExecutableFromGlobalCode(CallFrame* callFrame, const Identifier& name, const SourceCode& code, JSObject** exception) -{ - ParserError error; - UnlinkedFunctionExecutable* executable = globalData().codeCache()->getFunctionExecutableFromGlobalCode(globalData(), name, code, error); - if (hasDebugger()) - debugger()->sourceParsed(callFrame, code.provider(), error.m_line, error.m_message); - - if (error.m_type != ParserError::ErrorNone) { - *exception = error.toErrorObject(this, code); - return 0; - } - - return executable; -} - - } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h index e6edd0be7..a2c99fccb 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.h +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h @@ -24,564 +24,524 @@ #include "ArrayAllocationProfile.h" #include "JSArray.h" -#include "JSGlobalData.h" +#include "JSClassRef.h" +#include "VM.h" #include "JSSegmentedVariableObject.h" #include "JSWeakObjectMapRefInternal.h" #include "NumberPrototype.h" #include "SpecialPointer.h" #include "StringPrototype.h" #include "StructureChain.h" +#include "StructureRareDataInlines.h" #include "Watchpoint.h" +#include <JavaScriptCore/JSBase.h> #include <wtf/HashSet.h> #include <wtf/OwnPtr.h> #include <wtf/RandomNumber.h> +struct OpaqueJSClass; +struct OpaqueJSClassContextData; + namespace JSC { - class ArrayPrototype; - class BooleanPrototype; - class DatePrototype; - class Debugger; - class ErrorConstructor; - class ErrorPrototype; - class EvalCodeBlock; - class EvalExecutable; - class FunctionCodeBlock; - class FunctionExecutable; - class FunctionPrototype; - class GetterSetter; - class GlobalCodeBlock; - class JSStack; - class LLIntOffsetsExtractor; - class NativeErrorConstructor; - class ProgramCodeBlock; - class ProgramExecutable; - class RegExpConstructor; - class RegExpPrototype; - class SourceCode; - struct ActivationStackNode; - struct HashTable; - - typedef Vector<ExecState*, 16> ExecStateStack; +class ArrayPrototype; +class BooleanPrototype; +class DatePrototype; +class Debugger; +class ErrorConstructor; +class ErrorPrototype; +class EvalCodeBlock; +class EvalExecutable; +class FunctionCodeBlock; +class FunctionExecutable; +class FunctionPrototype; +class GetterSetter; +class GlobalCodeBlock; +class JSStack; +class LLIntOffsetsExtractor; +class NativeErrorConstructor; +class ProgramCodeBlock; +class ProgramExecutable; +class RegExpConstructor; +class RegExpPrototype; +class SourceCode; +struct ActivationStackNode; +struct HashTable; + +typedef Vector<ExecState*, 16> ExecStateStack; - struct GlobalObjectMethodTable { - typedef bool (*AllowsAccessFromFunctionPtr)(const JSGlobalObject*, ExecState*); - AllowsAccessFromFunctionPtr allowsAccessFrom; - - typedef bool (*SupportsProfilingFunctionPtr)(const JSGlobalObject*); - SupportsProfilingFunctionPtr supportsProfiling; - - typedef bool (*SupportsRichSourceInfoFunctionPtr)(const JSGlobalObject*); - SupportsRichSourceInfoFunctionPtr supportsRichSourceInfo; - - typedef bool (*ShouldInterruptScriptFunctionPtr)(const JSGlobalObject*); - ShouldInterruptScriptFunctionPtr shouldInterruptScript; - - typedef bool (*JavaScriptExperimentsEnabledFunctionPtr)(const JSGlobalObject*); - JavaScriptExperimentsEnabledFunctionPtr javaScriptExperimentsEnabled; - }; - - class JSGlobalObject : public JSSegmentedVariableObject { - private: - typedef HashSet<RefPtr<OpaqueJSWeakObjectMap> > WeakMapSet; - - struct JSGlobalObjectRareData { - JSGlobalObjectRareData() - : profileGroup(0) - { - } - - WeakMapSet weakMaps; - unsigned profileGroup; - }; - - protected: - - Register m_globalCallFrame[JSStack::CallFrameHeaderSize]; - - WriteBarrier<JSObject> m_globalThis; - - 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<GetterSetter> m_throwTypeErrorGetterSetter; - - 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<ErrorPrototype> m_errorPrototype; - - WriteBarrier<Structure> m_withScopeStructure; - WriteBarrier<Structure> m_strictEvalActivationStructure; - WriteBarrier<Structure> m_activationStructure; - WriteBarrier<Structure> m_nameScopeStructure; - WriteBarrier<Structure> m_argumentsStructure; - - // Lists the actual structures used for having these particular indexing shapes. - WriteBarrier<Structure> m_originalArrayStructureForIndexingShape[NumberOfIndexingShapes]; - // Lists the structures we should use during allocation for these particular indexing shapes. - WriteBarrier<Structure> m_arrayStructureForIndexingShapeDuringAllocation[NumberOfIndexingShapes]; - - WriteBarrier<Structure> m_booleanObjectStructure; - WriteBarrier<Structure> m_callbackConstructorStructure; - WriteBarrier<Structure> m_callbackFunctionStructure; - WriteBarrier<Structure> m_callbackObjectStructure; - WriteBarrier<Structure> m_dateStructure; - WriteBarrier<Structure> m_emptyObjectStructure; - WriteBarrier<Structure> m_nullPrototypeObjectStructure; - WriteBarrier<Structure> m_errorStructure; - WriteBarrier<Structure> m_functionStructure; - WriteBarrier<Structure> m_boundFunctionStructure; - WriteBarrier<Structure> m_namedFunctionStructure; - PropertyOffset m_functionNameOffset; - WriteBarrier<Structure> m_numberObjectStructure; - WriteBarrier<Structure> m_privateNameStructure; - WriteBarrier<Structure> m_regExpMatchesArrayStructure; - WriteBarrier<Structure> m_regExpStructure; - WriteBarrier<Structure> m_stringObjectStructure; - WriteBarrier<Structure> m_internalFunctionStructure; - - void* m_specialPointers[Special::TableSize]; // Special pointers used by the LLInt and JIT. - - Debugger* m_debugger; - - RefPtr<WatchpointSet> m_masqueradesAsUndefinedWatchpoint; - RefPtr<WatchpointSet> m_havingABadTimeWatchpoint; - - OwnPtr<JSGlobalObjectRareData> m_rareData; - - WeakRandom m_weakRandom; - - bool m_evalEnabled; - String m_evalDisabledErrorMessage; - bool m_experimentsEnabled; - - static JS_EXPORTDATA const GlobalObjectMethodTable s_globalObjectMethodTable; - const GlobalObjectMethodTable* m_globalObjectMethodTable; - - void createRareDataIfNeeded() - { - if (m_rareData) - return; - m_rareData = adoptPtr(new JSGlobalObjectRareData); - } - - public: - typedef JSSegmentedVariableObject Base; - - static JSGlobalObject* create(JSGlobalData& globalData, Structure* structure) - { - JSGlobalObject* globalObject = new (NotNull, allocateCell<JSGlobalObject>(globalData.heap)) JSGlobalObject(globalData, structure); - globalObject->finishCreation(globalData); - globalData.heap.addFinalizer(globalObject, destroy); - return globalObject; - } - - static JS_EXPORTDATA const ClassInfo s_info; - - bool hasDebugger() const { return m_debugger; } - bool hasProfiler() const { return globalObjectMethodTable()->supportsProfiling(this); } - - protected: - JS_EXPORT_PRIVATE explicit JSGlobalObject(JSGlobalData&, Structure*, const GlobalObjectMethodTable* = 0); - - void finishCreation(JSGlobalData& globalData) - { - Base::finishCreation(globalData); - structure()->setGlobalObject(globalData, this); - m_experimentsEnabled = m_globalObjectMethodTable->javaScriptExperimentsEnabled(this); - init(this); - } - - void finishCreation(JSGlobalData& globalData, JSObject* thisValue) - { - Base::finishCreation(globalData); - structure()->setGlobalObject(globalData, this); - m_experimentsEnabled = m_globalObjectMethodTable->javaScriptExperimentsEnabled(this); - init(thisValue); - } - - public: - JS_EXPORT_PRIVATE ~JSGlobalObject(); - JS_EXPORT_PRIVATE static void destroy(JSCell*); - // We don't need a destructor because we use a finalizer instead. - static const bool needsDestruction = false; - - JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); +struct GlobalObjectMethodTable { + typedef bool (*AllowsAccessFromFunctionPtr)(const JSGlobalObject*, ExecState*); + AllowsAccessFromFunctionPtr allowsAccessFrom; - JS_EXPORT_PRIVATE static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); - JS_EXPORT_PRIVATE static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); - bool hasOwnPropertyForWrite(ExecState*, PropertyName); - JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); + typedef bool (*SupportsProfilingFunctionPtr)(const JSGlobalObject*); + SupportsProfilingFunctionPtr supportsProfiling; - JS_EXPORT_PRIVATE static void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes); + typedef bool (*SupportsRichSourceInfoFunctionPtr)(const JSGlobalObject*); + SupportsRichSourceInfoFunctionPtr supportsRichSourceInfo; - JS_EXPORT_PRIVATE static void defineGetter(JSObject*, ExecState*, PropertyName, JSObject* getterFunc, unsigned attributes); - JS_EXPORT_PRIVATE static void defineSetter(JSObject*, ExecState*, PropertyName, JSObject* setterFunc, unsigned attributes); - JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow); + typedef bool (*ShouldInterruptScriptFunctionPtr)(const JSGlobalObject*); + ShouldInterruptScriptFunctionPtr shouldInterruptScript; - // We use this in the code generator as we perform symbol table - // lookups prior to initializing the properties - bool symbolTableHasProperty(PropertyName); + typedef bool (*JavaScriptExperimentsEnabledFunctionPtr)(const JSGlobalObject*); + JavaScriptExperimentsEnabledFunctionPtr javaScriptExperimentsEnabled; +}; - // The following accessors return pristine values, even if a script - // replaces the global object's associated property. +class JSGlobalObject : public JSSegmentedVariableObject { +private: + typedef HashSet<RefPtr<OpaqueJSWeakObjectMap> > WeakMapSet; + typedef HashMap<OpaqueJSClass*, OwnPtr<OpaqueJSClassContextData> > OpaqueJSClassDataMap; - 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(); } - GetterSetter* throwTypeErrorGetterSetter(ExecState* exec) + struct JSGlobalObjectRareData { + JSGlobalObjectRareData() + : profileGroup(0) { - if (!m_throwTypeErrorGetterSetter) - createThrowTypeError(exec); - return m_throwTypeErrorGetterSetter.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(); } - ErrorPrototype* errorPrototype() const { return m_errorPrototype.get(); } - - Structure* withScopeStructure() const { return m_withScopeStructure.get(); } - Structure* strictEvalActivationStructure() const { return m_strictEvalActivationStructure.get(); } - Structure* activationStructure() const { return m_activationStructure.get(); } - Structure* nameScopeStructure() const { return m_nameScopeStructure.get(); } - Structure* argumentsStructure() const { return m_argumentsStructure.get(); } - Structure* originalArrayStructureForIndexingType(IndexingType indexingType) const - { - ASSERT(indexingType & IsArray); - return m_originalArrayStructureForIndexingShape[(indexingType & IndexingShapeMask) >> IndexingShapeShift].get(); - } - Structure* arrayStructureForIndexingTypeDuringAllocation(IndexingType indexingType) const - { - ASSERT(indexingType & IsArray); - return m_arrayStructureForIndexingShapeDuringAllocation[(indexingType & IndexingShapeMask) >> IndexingShapeShift].get(); - } - Structure* arrayStructureForProfileDuringAllocation(ArrayAllocationProfile* profile) const - { - return arrayStructureForIndexingTypeDuringAllocation(ArrayAllocationProfile::selectIndexingTypeFor(profile)); - } - - bool isOriginalArrayStructure(Structure* structure) - { - return originalArrayStructureForIndexingType(structure->indexingType() | IsArray) == structure; - } + WeakMapSet weakMaps; + unsigned profileGroup; - 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* nullPrototypeObjectStructure() const { return m_nullPrototypeObjectStructure.get(); } - Structure* errorStructure() const { return m_errorStructure.get(); } - Structure* functionStructure() const { return m_functionStructure.get(); } - Structure* boundFunctionStructure() const { return m_boundFunctionStructure.get(); } - Structure* namedFunctionStructure() const { return m_namedFunctionStructure.get(); } - PropertyOffset functionNameOffset() const { return m_functionNameOffset; } - Structure* numberObjectStructure() const { return m_numberObjectStructure.get(); } - Structure* privateNameStructure() const { return m_privateNameStructure.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* actualPointerFor(Special::Pointer pointer) - { - ASSERT(pointer < Special::TableSize); - return m_specialPointers[pointer]; - } + OpaqueJSClassDataMap opaqueJSClassData; + }; - WatchpointSet* masqueradesAsUndefinedWatchpoint() { return m_masqueradesAsUndefinedWatchpoint.get(); } - WatchpointSet* havingABadTimeWatchpoint() { return m_havingABadTimeWatchpoint.get(); } +protected: + + Register m_globalCallFrame[JSStack::CallFrameHeaderSize]; + + WriteBarrier<JSObject> m_globalThis; + + 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<GetterSetter> m_throwTypeErrorGetterSetter; + + 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<ErrorPrototype> m_errorPrototype; + + WriteBarrier<Structure> m_withScopeStructure; + WriteBarrier<Structure> m_strictEvalActivationStructure; + WriteBarrier<Structure> m_activationStructure; + WriteBarrier<Structure> m_nameScopeStructure; + WriteBarrier<Structure> m_argumentsStructure; - bool isHavingABadTime() const - { - return m_havingABadTimeWatchpoint->hasBeenInvalidated(); - } + // Lists the actual structures used for having these particular indexing shapes. + WriteBarrier<Structure> m_originalArrayStructureForIndexingShape[NumberOfIndexingShapes]; + // Lists the structures we should use during allocation for these particular indexing shapes. + WriteBarrier<Structure> m_arrayStructureForIndexingShapeDuringAllocation[NumberOfIndexingShapes]; - void haveABadTime(JSGlobalData&); + WriteBarrier<Structure> m_booleanObjectStructure; + WriteBarrier<Structure> m_callbackConstructorStructure; + WriteBarrier<Structure> m_callbackFunctionStructure; + WriteBarrier<Structure> m_callbackObjectStructure; +#if JSC_OBJC_API_ENABLED + WriteBarrier<Structure> m_objcCallbackFunctionStructure; + WriteBarrier<Structure> m_objcWrapperObjectStructure; +#endif + WriteBarrier<Structure> m_dateStructure; + WriteBarrier<Structure> m_nullPrototypeObjectStructure; + WriteBarrier<Structure> m_errorStructure; + WriteBarrier<Structure> m_functionStructure; + WriteBarrier<Structure> m_boundFunctionStructure; + WriteBarrier<Structure> m_namedFunctionStructure; + PropertyOffset m_functionNameOffset; + WriteBarrier<Structure> m_numberObjectStructure; + WriteBarrier<Structure> m_privateNameStructure; + WriteBarrier<Structure> m_regExpMatchesArrayStructure; + WriteBarrier<Structure> m_regExpStructure; + WriteBarrier<Structure> m_stringObjectStructure; + WriteBarrier<Structure> m_internalFunctionStructure; - bool arrayPrototypeChainIsSane(); - - void setProfileGroup(unsigned value) { createRareDataIfNeeded(); m_rareData->profileGroup = value; } - unsigned profileGroup() const - { - if (!m_rareData) - return 0; - return m_rareData->profileGroup; - } + void* m_specialPointers[Special::TableSize]; // Special pointers used by the LLInt and JIT. - Debugger* debugger() const { return m_debugger; } - void setDebugger(Debugger* debugger) { m_debugger = debugger; } + Debugger* m_debugger; - const GlobalObjectMethodTable* globalObjectMethodTable() const { return m_globalObjectMethodTable; } + RefPtr<WatchpointSet> m_masqueradesAsUndefinedWatchpoint; + RefPtr<WatchpointSet> m_havingABadTimeWatchpoint; - static bool allowsAccessFrom(const JSGlobalObject*, ExecState*) { return true; } - static bool supportsProfiling(const JSGlobalObject*) { return false; } - static bool supportsRichSourceInfo(const JSGlobalObject*) { return true; } + OwnPtr<JSGlobalObjectRareData> m_rareData; - JS_EXPORT_PRIVATE ExecState* globalExec(); + WeakRandom m_weakRandom; - static bool shouldInterruptScript(const JSGlobalObject*) { return true; } - static bool javaScriptExperimentsEnabled(const JSGlobalObject*) { return false; } + bool m_evalEnabled; + String m_evalDisabledErrorMessage; + bool m_experimentsEnabled; - bool isDynamicScope(bool& requiresDynamicChecks) const; + static JS_EXPORTDATA const GlobalObjectMethodTable s_globalObjectMethodTable; + const GlobalObjectMethodTable* m_globalObjectMethodTable; - bool evalEnabled() const { return m_evalEnabled; } - const String& evalDisabledErrorMessage() const { return m_evalDisabledErrorMessage; } - void setEvalEnabled(bool enabled, const String& errorMessage = String()) - { - m_evalEnabled = enabled; - m_evalDisabledErrorMessage = errorMessage; - } - - void resetPrototype(JSGlobalData&, JSValue prototype); - - JSGlobalData& globalData() const { return *Heap::heap(this)->globalData(); } - JSObject* globalThis() const; + void createRareDataIfNeeded() + { + if (m_rareData) + return; + m_rareData = adoptPtr(new JSGlobalObjectRareData); + } + +public: + typedef JSSegmentedVariableObject Base; - static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) - { - return Structure::create(globalData, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), &s_info); - } + static JSGlobalObject* create(VM& vm, Structure* structure) + { + JSGlobalObject* globalObject = new (NotNull, allocateCell<JSGlobalObject>(vm.heap)) JSGlobalObject(vm, structure); + globalObject->finishCreation(vm); + vm.heap.addFinalizer(globalObject, destroy); + return globalObject; + } - void registerWeakMap(OpaqueJSWeakObjectMap* map) - { - createRareDataIfNeeded(); - m_rareData->weakMaps.add(map); - } + static JS_EXPORTDATA const ClassInfo s_info; - void unregisterWeakMap(OpaqueJSWeakObjectMap* map) - { - if (m_rareData) - m_rareData->weakMaps.remove(map); - } + bool hasDebugger() const { return m_debugger; } + bool hasProfiler() const { return globalObjectMethodTable()->supportsProfiling(this); } - double weakRandomNumber() { return m_weakRandom.get(); } - unsigned weakRandomInteger() { return m_weakRandom.getUint32(); } +protected: + JS_EXPORT_PRIVATE explicit JSGlobalObject(VM&, Structure*, const GlobalObjectMethodTable* = 0); - UnlinkedProgramCodeBlock* createProgramCodeBlock(CallFrame*, ProgramExecutable*, JSObject** exception); - UnlinkedEvalCodeBlock* createEvalCodeBlock(CallFrame*, EvalExecutable*, JSObject** exception); - UnlinkedFunctionExecutable* createFunctionExecutableFromGlobalCode(CallFrame*, const Identifier&, const SourceCode&, JSObject** exception); + void finishCreation(VM& vm) + { + Base::finishCreation(vm); + structure()->setGlobalObject(vm, this); + m_experimentsEnabled = m_globalObjectMethodTable->javaScriptExperimentsEnabled(this); + init(this); + } - protected: + void finishCreation(VM& vm, JSObject* thisValue) + { + Base::finishCreation(vm); + structure()->setGlobalObject(vm, this); + m_experimentsEnabled = m_globalObjectMethodTable->javaScriptExperimentsEnabled(this); + init(thisValue); + } - static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags; +public: + JS_EXPORT_PRIVATE ~JSGlobalObject(); + JS_EXPORT_PRIVATE static void destroy(JSCell*); + // We don't need a destructor because we use a finalizer instead. + static const bool needsDestruction = false; - struct GlobalPropertyInfo { - GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a) - : identifier(i) - , value(v) - , attributes(a) - { - } + JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); - const Identifier identifier; - JSValue value; - unsigned attributes; - }; - JS_EXPORT_PRIVATE void addStaticGlobals(GlobalPropertyInfo*, int count); + JS_EXPORT_PRIVATE static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); + JS_EXPORT_PRIVATE static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); + bool hasOwnPropertyForWrite(ExecState*, PropertyName); + JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); - JS_EXPORT_PRIVATE static JSC::JSObject* toThisObject(JSC::JSCell*, JSC::ExecState*); + JS_EXPORT_PRIVATE static void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes); - JS_EXPORT_PRIVATE void setGlobalThis(JSGlobalData&, JSObject* globalThis); + JS_EXPORT_PRIVATE static void defineGetter(JSObject*, ExecState*, PropertyName, JSObject* getterFunc, unsigned attributes); + JS_EXPORT_PRIVATE static void defineSetter(JSObject*, ExecState*, PropertyName, JSObject* setterFunc, unsigned attributes); + JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow); - private: - friend class LLIntOffsetsExtractor; - - // FIXME: Fold reset into init. - JS_EXPORT_PRIVATE void init(JSObject* thisValue); - void reset(JSValue prototype); + // We use this in the code generator as we perform symbol table + // lookups prior to initializing the properties + bool symbolTableHasProperty(PropertyName); - void createThrowTypeError(ExecState*); + // The following accessors return pristine values, even if a script + // replaces the global object's associated property. - JS_EXPORT_PRIVATE static void clearRareData(JSCell*); - }; + RegExpConstructor* regExpConstructor() const { return m_regExpConstructor.get(); } - JSGlobalObject* asGlobalObject(JSValue); + 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(); } - inline JSGlobalObject* asGlobalObject(JSValue value) + JSFunction* evalFunction() const { return m_evalFunction.get(); } + JSFunction* callFunction() const { return m_callFunction.get(); } + JSFunction* applyFunction() const { return m_applyFunction.get(); } + GetterSetter* throwTypeErrorGetterSetter(ExecState* exec) { - ASSERT(asObject(value)->isGlobalObject()); - return jsCast<JSGlobalObject*>(asObject(value)); + if (!m_throwTypeErrorGetterSetter) + createThrowTypeError(exec); + return m_throwTypeErrorGetterSetter.get(); } - inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, PropertyName propertyName) + 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(); } + ErrorPrototype* errorPrototype() const { return m_errorPrototype.get(); } + + Structure* withScopeStructure() const { return m_withScopeStructure.get(); } + Structure* strictEvalActivationStructure() const { return m_strictEvalActivationStructure.get(); } + Structure* activationStructure() const { return m_activationStructure.get(); } + Structure* nameScopeStructure() const { return m_nameScopeStructure.get(); } + Structure* argumentsStructure() const { return m_argumentsStructure.get(); } + Structure* originalArrayStructureForIndexingType(IndexingType indexingType) const { - PropertySlot slot; - if (Base::getOwnPropertySlot(this, exec, propertyName, slot)) - return true; - bool slotIsWriteable; - return symbolTableGet(this, propertyName, slot, slotIsWriteable); + ASSERT(indexingType & IsArray); + return m_originalArrayStructureForIndexingShape[(indexingType & IndexingShapeMask) >> IndexingShapeShift].get(); } - - inline bool JSGlobalObject::symbolTableHasProperty(PropertyName propertyName) + Structure* arrayStructureForIndexingTypeDuringAllocation(IndexingType indexingType) const { - SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.publicName()); - return !entry.isNull(); + ASSERT(indexingType & IsArray); + return m_arrayStructureForIndexingShapeDuringAllocation[(indexingType & IndexingShapeMask) >> IndexingShapeShift].get(); } - - inline JSValue Structure::prototypeForLookup(JSGlobalObject* globalObject) const + Structure* arrayStructureForProfileDuringAllocation(ArrayAllocationProfile* profile) const { - if (isObject()) - return m_prototype.get(); - - ASSERT(typeInfo().type() == StringType); - return globalObject->stringPrototype(); + return arrayStructureForIndexingTypeDuringAllocation(ArrayAllocationProfile::selectIndexingTypeFor(profile)); } - - inline JSValue Structure::prototypeForLookup(ExecState* exec) const + + bool isOriginalArrayStructure(Structure* structure) { - return prototypeForLookup(exec->lexicalGlobalObject()); + return originalArrayStructureForIndexingType(structure->indexingType() | IsArray) == structure; } - - inline StructureChain* Structure::prototypeChain(JSGlobalData& globalData, JSGlobalObject* globalObject) const + + 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(); } +#if JSC_OBJC_API_ENABLED + Structure* objcCallbackFunctionStructure() const { return m_objcCallbackFunctionStructure.get(); } + Structure* objcWrapperObjectStructure() const { return m_objcWrapperObjectStructure.get(); } +#endif + Structure* dateStructure() const { return m_dateStructure.get(); } + Structure* nullPrototypeObjectStructure() const { return m_nullPrototypeObjectStructure.get(); } + Structure* errorStructure() const { return m_errorStructure.get(); } + Structure* functionStructure() const { return m_functionStructure.get(); } + Structure* boundFunctionStructure() const { return m_boundFunctionStructure.get(); } + Structure* namedFunctionStructure() const { return m_namedFunctionStructure.get(); } + PropertyOffset functionNameOffset() const { return m_functionNameOffset; } + Structure* numberObjectStructure() const { return m_numberObjectStructure.get(); } + Structure* privateNameStructure() const { return m_privateNameStructure.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* actualPointerFor(Special::Pointer pointer) { - // We cache our prototype chain so our clients can share it. - if (!isValid(globalObject, m_cachedPrototypeChain.get())) { - JSValue prototype = prototypeForLookup(globalObject); - m_cachedPrototypeChain.set(globalData, this, StructureChain::create(globalData, prototype.isNull() ? 0 : asObject(prototype)->structure())); - } - return m_cachedPrototypeChain.get(); + ASSERT(pointer < Special::TableSize); + return m_specialPointers[pointer]; } - inline StructureChain* Structure::prototypeChain(ExecState* exec) const + WatchpointSet* masqueradesAsUndefinedWatchpoint() { return m_masqueradesAsUndefinedWatchpoint.get(); } + WatchpointSet* havingABadTimeWatchpoint() { return m_havingABadTimeWatchpoint.get(); } + + bool isHavingABadTime() const { - return prototypeChain(exec->globalData(), exec->lexicalGlobalObject()); + return m_havingABadTimeWatchpoint->hasBeenInvalidated(); } + + void haveABadTime(VM&); + + bool arrayPrototypeChainIsSane(); - inline bool Structure::isValid(JSGlobalObject* globalObject, StructureChain* cachedPrototypeChain) const - { - if (!cachedPrototypeChain) - return false; - - JSValue prototype = prototypeForLookup(globalObject); - WriteBarrier<Structure>* cachedStructure = cachedPrototypeChain->head(); - while(*cachedStructure && !prototype.isNull()) { - if (asObject(prototype)->structure() != cachedStructure->get()) - return false; - ++cachedStructure; - prototype = asObject(prototype)->prototype(); - } - return prototype.isNull() && !*cachedStructure; + void setProfileGroup(unsigned value) { createRareDataIfNeeded(); m_rareData->profileGroup = value; } + unsigned profileGroup() const + { + if (!m_rareData) + return 0; + return m_rareData->profileGroup; } - inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const - { - return isValid(exec->lexicalGlobalObject(), cachedPrototypeChain); - } + Debugger* debugger() const { return m_debugger; } + void setDebugger(Debugger* debugger) { m_debugger = debugger; } - inline JSGlobalObject* ExecState::dynamicGlobalObject() - { - if (this == lexicalGlobalObject()->globalExec()) - return lexicalGlobalObject(); + const GlobalObjectMethodTable* globalObjectMethodTable() const { return m_globalObjectMethodTable; } - // For any ExecState that's not a globalExec, the - // dynamic global object must be set since code is running - ASSERT(globalData().dynamicGlobalObject); - return globalData().dynamicGlobalObject; - } + static bool allowsAccessFrom(const JSGlobalObject*, ExecState*) { return true; } + static bool supportsProfiling(const JSGlobalObject*) { return false; } + static bool supportsRichSourceInfo(const JSGlobalObject*) { return true; } - inline JSObject* constructEmptyObject(ExecState* exec, JSGlobalObject* globalObject) - { - return constructEmptyObject(exec, globalObject->emptyObjectStructure()); - } + JS_EXPORT_PRIVATE ExecState* globalExec(); - inline JSObject* constructEmptyObject(ExecState* exec) - { - return constructEmptyObject(exec, exec->lexicalGlobalObject()); - } + static bool shouldInterruptScript(const JSGlobalObject*) { return true; } + static bool javaScriptExperimentsEnabled(const JSGlobalObject*) { return false; } - inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, unsigned initialLength = 0) - { - return ArrayAllocationProfile::updateLastAllocationFor(profile, JSArray::create(exec->globalData(), initialLength >= MIN_SPARSE_ARRAY_INDEX ? globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage) : globalObject->arrayStructureForProfileDuringAllocation(profile), initialLength)); - } + bool isDynamicScope(bool& requiresDynamicChecks) const; - inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, unsigned initialLength = 0) + bool evalEnabled() const { return m_evalEnabled; } + const String& evalDisabledErrorMessage() const { return m_evalDisabledErrorMessage; } + void setEvalEnabled(bool enabled, const String& errorMessage = String()) { - return constructEmptyArray(exec, profile, exec->lexicalGlobalObject(), initialLength); + m_evalEnabled = enabled; + m_evalDisabledErrorMessage = errorMessage; } - - inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const ArgList& values) + + void resetPrototype(VM&, JSValue prototype); + + VM& vm() const { return *Heap::heap(this)->vm(); } + JSObject* globalThis() const; + + static Structure* createStructure(VM& vm, JSValue prototype) { - return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject->arrayStructureForProfileDuringAllocation(profile), values)); + return Structure::create(vm, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), &s_info); } - inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const ArgList& values) + void registerWeakMap(OpaqueJSWeakObjectMap* map) { - return constructArray(exec, profile, exec->lexicalGlobalObject(), values); + createRareDataIfNeeded(); + m_rareData->weakMaps.add(map); } - inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const JSValue* values, unsigned length) + void unregisterWeakMap(OpaqueJSWeakObjectMap* map) { - return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject->arrayStructureForProfileDuringAllocation(profile), values, length)); + if (m_rareData) + m_rareData->weakMaps.remove(map); } - inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, unsigned length) + OpaqueJSClassDataMap& opaqueJSClassData() { - return constructArray(exec, profile, exec->lexicalGlobalObject(), values, length); + createRareDataIfNeeded(); + return m_rareData->opaqueJSClassData; } - class DynamicGlobalObjectScope { - WTF_MAKE_NONCOPYABLE(DynamicGlobalObjectScope); - public: - JS_EXPORT_PRIVATE DynamicGlobalObjectScope(JSGlobalData&, JSGlobalObject*); + double weakRandomNumber() { return m_weakRandom.get(); } + unsigned weakRandomInteger() { return m_weakRandom.getUint32(); } + + UnlinkedProgramCodeBlock* createProgramCodeBlock(CallFrame*, ProgramExecutable*, JSObject** exception); + UnlinkedEvalCodeBlock* createEvalCodeBlock(CodeCache*, CallFrame*, JSScope*, EvalExecutable*, JSObject** exception); + +protected: - ~DynamicGlobalObjectScope() + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags; + + struct GlobalPropertyInfo { + GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a) + : identifier(i) + , value(v) + , attributes(a) { - m_dynamicGlobalObjectSlot = m_savedDynamicGlobalObject; } - private: - JSGlobalObject*& m_dynamicGlobalObjectSlot; - JSGlobalObject* m_savedDynamicGlobalObject; + const Identifier identifier; + JSValue value; + unsigned attributes; }; + JS_EXPORT_PRIVATE void addStaticGlobals(GlobalPropertyInfo*, int count); - inline bool JSGlobalObject::isDynamicScope(bool&) const - { - return true; - } + JS_EXPORT_PRIVATE static JSC::JSObject* toThisObject(JSC::JSCell*, JSC::ExecState*); - inline JSObject* JSScope::globalThis() - { - return globalObject()->globalThis(); - } + JS_EXPORT_PRIVATE void setGlobalThis(VM&, JSObject* globalThis); - inline JSObject* JSGlobalObject::globalThis() const - { - return m_globalThis.get(); +private: + friend class LLIntOffsetsExtractor; + + // FIXME: Fold reset into init. + JS_EXPORT_PRIVATE void init(JSObject* thisValue); + void reset(JSValue prototype); + + void createThrowTypeError(ExecState*); + + JS_EXPORT_PRIVATE static void clearRareData(JSCell*); +}; + +JSGlobalObject* asGlobalObject(JSValue); + +inline JSGlobalObject* asGlobalObject(JSValue value) +{ + ASSERT(asObject(value)->isGlobalObject()); + return jsCast<JSGlobalObject*>(asObject(value)); +} + +inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, PropertyName propertyName) +{ + PropertySlot slot; + if (Base::getOwnPropertySlot(this, exec, propertyName, slot)) + return true; + bool slotIsWriteable; + return symbolTableGet(this, propertyName, slot, slotIsWriteable); +} + +inline bool JSGlobalObject::symbolTableHasProperty(PropertyName propertyName) +{ + SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.publicName()); + return !entry.isNull(); +} + +inline JSGlobalObject* ExecState::dynamicGlobalObject() +{ + if (this == lexicalGlobalObject()->globalExec()) + return lexicalGlobalObject(); + + // For any ExecState that's not a globalExec, the + // dynamic global object must be set since code is running + ASSERT(vm().dynamicGlobalObject); + return vm().dynamicGlobalObject; +} + +inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, unsigned initialLength = 0) +{ + return ArrayAllocationProfile::updateLastAllocationFor(profile, JSArray::create(exec->vm(), initialLength >= MIN_SPARSE_ARRAY_INDEX ? globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage) : globalObject->arrayStructureForProfileDuringAllocation(profile), initialLength)); +} + +inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, unsigned initialLength = 0) +{ + return constructEmptyArray(exec, profile, exec->lexicalGlobalObject(), initialLength); +} + +inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const ArgList& values) +{ + return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject->arrayStructureForProfileDuringAllocation(profile), values)); +} + +inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const ArgList& values) +{ + return constructArray(exec, profile, exec->lexicalGlobalObject(), values); +} + +inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const JSValue* values, unsigned length) +{ + return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject->arrayStructureForProfileDuringAllocation(profile), values, length)); +} + +inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, unsigned length) +{ + return constructArray(exec, profile, exec->lexicalGlobalObject(), values, length); +} + +class DynamicGlobalObjectScope { + WTF_MAKE_NONCOPYABLE(DynamicGlobalObjectScope); +public: + JS_EXPORT_PRIVATE DynamicGlobalObjectScope(VM&, JSGlobalObject*); + + ~DynamicGlobalObjectScope() + { + m_dynamicGlobalObjectSlot = m_savedDynamicGlobalObject; } +private: + JSGlobalObject*& m_dynamicGlobalObjectSlot; + JSGlobalObject* m_savedDynamicGlobalObject; +}; + +inline bool JSGlobalObject::isDynamicScope(bool&) const +{ + return true; +} + +inline JSObject* JSScope::globalThis() +{ + return globalObject()->globalThis(); +} + +inline JSObject* JSGlobalObject::globalThis() const +{ + return m_globalThis.get(); +} + } // namespace JSC #endif // JSGlobalObject_h diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp index 1010ad2b7..0efaf84bc 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp @@ -34,6 +34,7 @@ #include "Lexer.h" #include "LiteralParser.h" #include "Nodes.h" +#include "Operations.h" #include "Parser.h" #include <wtf/dtoa.h> #include <stdio.h> @@ -363,7 +364,7 @@ static double jsHexIntegerLiteral(const CharType*& data, const CharType* end) template <typename CharType> static double jsStrDecimalLiteral(const CharType*& data, const CharType* end) { - ASSERT(data < end); + RELEASE_ASSERT(data < end); size_t parsedLength; double number = parseDouble(data, end - data, parsedLength); @@ -514,7 +515,7 @@ EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec) } JSGlobalObject* calleeGlobalObject = exec->callee()->globalObject(); - EvalExecutable* eval = EvalExecutable::create(exec, makeSource(s), false); + EvalExecutable* eval = EvalExecutable::create(exec, exec->vm().codeCache(), makeSource(s), false); JSObject* error = eval->compile(exec, calleeGlobalObject); if (error) return throwVMError(exec, error); @@ -559,13 +560,13 @@ EncodedJSValue JSC_HOST_CALL globalFuncParseFloat(ExecState* exec) EncodedJSValue JSC_HOST_CALL globalFuncIsNaN(ExecState* exec) { - return JSValue::encode(jsBoolean(isnan(exec->argument(0).toNumber(exec)))); + return JSValue::encode(jsBoolean(std::isnan(exec->argument(0).toNumber(exec)))); } EncodedJSValue JSC_HOST_CALL globalFuncIsFinite(ExecState* exec) { double n = exec->argument(0).toNumber(exec); - return JSValue::encode(jsBoolean(isfinite(n))); + return JSValue::encode(jsBoolean(std::isfinite(n))); } EncodedJSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState* exec) @@ -735,7 +736,7 @@ EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState* exec) if (!thisObject->isExtensible()) return throwVMError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError)); - if (!thisObject->setPrototypeWithCycleCheck(exec->globalData(), value)) + if (!thisObject->setPrototypeWithCycleCheck(exec->vm(), value)) throwError(exec, createError(exec, "cyclic __proto__ value")); return JSValue::encode(jsUndefined()); } diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h index 757c9dcac..f4512e405 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h +++ b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h @@ -24,39 +24,39 @@ #ifndef JSGlobalObjectFunctions_h #define JSGlobalObjectFunctions_h -#include "JSValue.h" +#include "JSCJSValue.h" #include <wtf/unicode/Unicode.h> namespace JSC { - class ArgList; - class ExecState; - class JSObject; - - // FIXME: These functions should really be in JSGlobalObject.cpp, but putting them there - // is a 0.5% reduction. - - EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState*); - EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState*); - EncodedJSValue JSC_HOST_CALL globalFuncParseFloat(ExecState*); - EncodedJSValue JSC_HOST_CALL globalFuncIsNaN(ExecState*); - EncodedJSValue JSC_HOST_CALL globalFuncIsFinite(ExecState*); - EncodedJSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState*); - EncodedJSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState*); - EncodedJSValue JSC_HOST_CALL globalFuncEncodeURI(ExecState*); - EncodedJSValue JSC_HOST_CALL globalFuncEncodeURIComponent(ExecState*); - EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState*); - EncodedJSValue JSC_HOST_CALL globalFuncUnescape(ExecState*); - EncodedJSValue JSC_HOST_CALL globalFuncThrowTypeError(ExecState*); - EncodedJSValue JSC_HOST_CALL globalFuncProtoGetter(ExecState*); - EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState*); - - static const double mantissaOverflowLowerBound = 9007199254740992.0; - double parseIntOverflow(const LChar*, int length, int radix); - ALWAYS_INLINE double parseIntOverflow(const char* s, int length, int radix) { return parseIntOverflow(reinterpret_cast<const LChar*>(s), length, radix); } - double parseIntOverflow(const UChar*, int length, int radix); - bool isStrWhiteSpace(UChar); - double jsToNumber(const WTF::String&); +class ArgList; +class ExecState; +class JSObject; + +// FIXME: These functions should really be in JSGlobalObject.cpp, but putting them there +// is a 0.5% reduction. + +EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState*); +EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState*); +EncodedJSValue JSC_HOST_CALL globalFuncParseFloat(ExecState*); +EncodedJSValue JSC_HOST_CALL globalFuncIsNaN(ExecState*); +EncodedJSValue JSC_HOST_CALL globalFuncIsFinite(ExecState*); +EncodedJSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState*); +EncodedJSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState*); +EncodedJSValue JSC_HOST_CALL globalFuncEncodeURI(ExecState*); +EncodedJSValue JSC_HOST_CALL globalFuncEncodeURIComponent(ExecState*); +EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState*); +EncodedJSValue JSC_HOST_CALL globalFuncUnescape(ExecState*); +EncodedJSValue JSC_HOST_CALL globalFuncThrowTypeError(ExecState*); +EncodedJSValue JSC_HOST_CALL globalFuncProtoGetter(ExecState*); +EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState*); + +static const double mantissaOverflowLowerBound = 9007199254740992.0; +double parseIntOverflow(const LChar*, int length, int radix); +ALWAYS_INLINE double parseIntOverflow(const char* s, int length, int radix) { return parseIntOverflow(reinterpret_cast<const LChar*>(s), length, radix); } +double parseIntOverflow(const UChar*, int length, int radix); +bool isStrWhiteSpace(UChar); +double jsToNumber(const WTF::String&); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSLock.cpp b/Source/JavaScriptCore/runtime/JSLock.cpp index 5e3d12c92..4baa2a603 100644 --- a/Source/JavaScriptCore/runtime/JSLock.cpp +++ b/Source/JavaScriptCore/runtime/JSLock.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2005, 2008, 2012 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -25,7 +25,7 @@ #include "CallFrame.h" #include "JSGlobalObject.h" #include "JSObject.h" - +#include "Operations.h" #if USE(PTHREADS) #include <pthread.h> @@ -51,32 +51,40 @@ void GlobalJSLock::initialize() } JSLockHolder::JSLockHolder(ExecState* exec) - : m_globalData(&exec->globalData()) + : m_vm(&exec->vm()) +{ + init(); +} + +JSLockHolder::JSLockHolder(VM* vm) + : m_vm(vm) { - m_globalData->apiLock().lock(); + init(); } -JSLockHolder::JSLockHolder(JSGlobalData* globalData) - : m_globalData(globalData) +JSLockHolder::JSLockHolder(VM& vm) + : m_vm(&vm) { - m_globalData->apiLock().lock(); + init(); } -JSLockHolder::JSLockHolder(JSGlobalData& globalData) - : m_globalData(&globalData) +void JSLockHolder::init() { - m_globalData->apiLock().lock(); + m_vm->apiLock().lock(); } JSLockHolder::~JSLockHolder() { - m_globalData->apiLock().unlock(); + RefPtr<JSLock> apiLock(&m_vm->apiLock()); + m_vm.clear(); + apiLock->unlock(); } -JSLock::JSLock() +JSLock::JSLock(VM* vm) : m_ownerThread(0) , m_lockCount(0) , m_lockDropDepth(0) + , m_vm(vm) { m_spinLock.Init(); } @@ -85,6 +93,12 @@ JSLock::~JSLock() { } +void JSLock::willDestroyVM(VM* vm) +{ + ASSERT_UNUSED(vm, m_vm == vm); + m_vm = 0; +} + void JSLock::lock() { ThreadIdentifier currentThread = WTF::currentThread(); @@ -119,12 +133,12 @@ void JSLock::unlock() void JSLock::lock(ExecState* exec) { - exec->globalData().apiLock().lock(); + exec->vm().apiLock().lock(); } void JSLock::unlock(ExecState* exec) { - exec->globalData().apiLock().unlock(); + exec->vm().apiLock().unlock(); } bool JSLock::currentThreadIsHoldingLock() @@ -201,21 +215,21 @@ void JSLock::grabAllLocks(unsigned lockCount) JSLock::DropAllLocks::DropAllLocks(ExecState* exec) : m_lockCount(0) - , m_globalData(&exec->globalData()) + , m_vm(&exec->vm()) { - m_lockCount = m_globalData->apiLock().dropAllLocks(); + m_lockCount = m_vm->apiLock().dropAllLocks(); } -JSLock::DropAllLocks::DropAllLocks(JSGlobalData* globalData) +JSLock::DropAllLocks::DropAllLocks(VM* vm) : m_lockCount(0) - , m_globalData(globalData) + , m_vm(vm) { - m_lockCount = m_globalData->apiLock().dropAllLocks(); + m_lockCount = m_vm->apiLock().dropAllLocks(); } JSLock::DropAllLocks::~DropAllLocks() { - m_globalData->apiLock().grabAllLocks(m_lockCount); + m_vm->apiLock().grabAllLocks(m_lockCount); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSLock.h b/Source/JavaScriptCore/runtime/JSLock.h index 4c42dc0ae..83bcc2425 100644 --- a/Source/JavaScriptCore/runtime/JSLock.h +++ b/Source/JavaScriptCore/runtime/JSLock.h @@ -49,10 +49,10 @@ namespace JSC { // thread acquired it to begin with. class ExecState; - class JSGlobalData; + class VM; // This class is used to protect the initialization of the legacy single - // shared JSGlobalData. + // shared VM. class GlobalJSLock { WTF_MAKE_NONCOPYABLE(GlobalJSLock); public: @@ -66,19 +66,21 @@ namespace JSC { class JSLockHolder { public: - JS_EXPORT_PRIVATE JSLockHolder(JSGlobalData*); - JS_EXPORT_PRIVATE JSLockHolder(JSGlobalData&); + JS_EXPORT_PRIVATE JSLockHolder(VM*); + JS_EXPORT_PRIVATE JSLockHolder(VM&); JS_EXPORT_PRIVATE JSLockHolder(ExecState*); JS_EXPORT_PRIVATE ~JSLockHolder(); private: - RefPtr<JSGlobalData> m_globalData; + void init(); + + RefPtr<VM> m_vm; }; - class JSLock { + class JSLock : public ThreadSafeRefCounted<JSLock> { WTF_MAKE_NONCOPYABLE(JSLock); public: - JSLock(); + JSLock(VM*); JS_EXPORT_PRIVATE ~JSLock(); JS_EXPORT_PRIVATE void lock(); @@ -86,8 +88,10 @@ namespace JSC { static void lock(ExecState*); static void unlock(ExecState*); - static void lock(JSGlobalData&); - static void unlock(JSGlobalData&); + static void lock(VM&); + static void unlock(VM&); + + VM* vm() { return m_vm; } JS_EXPORT_PRIVATE bool currentThreadIsHoldingLock(); @@ -95,16 +99,18 @@ namespace JSC { unsigned dropAllLocksUnconditionally(); void grabAllLocks(unsigned lockCount); + void willDestroyVM(VM*); + class DropAllLocks { WTF_MAKE_NONCOPYABLE(DropAllLocks); public: JS_EXPORT_PRIVATE DropAllLocks(ExecState* exec); - JS_EXPORT_PRIVATE DropAllLocks(JSGlobalData*); + JS_EXPORT_PRIVATE DropAllLocks(VM*); JS_EXPORT_PRIVATE ~DropAllLocks(); private: intptr_t m_lockCount; - RefPtr<JSGlobalData> m_globalData; + RefPtr<VM> m_vm; }; private: @@ -113,6 +119,7 @@ namespace JSC { ThreadIdentifier m_ownerThread; intptr_t m_lockCount; unsigned m_lockDropDepth; + VM* m_vm; }; } // namespace diff --git a/Source/JavaScriptCore/runtime/JSNameScope.cpp b/Source/JavaScriptCore/runtime/JSNameScope.cpp index 335631fd0..53468d6a8 100644 --- a/Source/JavaScriptCore/runtime/JSNameScope.cpp +++ b/Source/JavaScriptCore/runtime/JSNameScope.cpp @@ -27,6 +27,7 @@ #include "JSNameScope.h" #include "Error.h" +#include "Operations.h" namespace JSC { @@ -69,7 +70,7 @@ void JSNameScope::put(JSCell* cell, ExecState* exec, PropertyName propertyName, if (symbolTablePut(thisObject, exec, propertyName, value, slot.isStrictMode())) return; - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } bool JSNameScope::getOwnPropertySlot(JSCell* cell, ExecState*, PropertyName propertyName, PropertySlot& slot) diff --git a/Source/JavaScriptCore/runtime/JSNameScope.h b/Source/JavaScriptCore/runtime/JSNameScope.h index e67370d92..43763296c 100644 --- a/Source/JavaScriptCore/runtime/JSNameScope.h +++ b/Source/JavaScriptCore/runtime/JSNameScope.h @@ -56,15 +56,15 @@ public: static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(NameScopeObjectType, StructureFlags), &s_info); } + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(NameScopeObjectType, StructureFlags), &s_info); } static const ClassInfo s_info; protected: void finishCreation(ExecState* exec, const Identifier& identifier, JSValue value, unsigned attributes) { - Base::finishCreation(exec->globalData()); - m_registerStore.set(exec->globalData(), this, value); + Base::finishCreation(exec->vm()); + m_registerStore.set(exec->vm(), this, value); symbolTable()->add(identifier.impl(), SymbolTableEntry(-1, attributes)); } @@ -73,7 +73,7 @@ protected: private: JSNameScope(ExecState* exec, JSScope* next) : Base( - exec->globalData(), + exec->vm(), exec->lexicalGlobalObject()->nameScopeStructure(), reinterpret_cast<Register*>(&m_registerStore + 1), next diff --git a/Source/JavaScriptCore/runtime/JSNotAnObject.cpp b/Source/JavaScriptCore/runtime/JSNotAnObject.cpp index 53592ba2b..0e4332eb4 100644 --- a/Source/JavaScriptCore/runtime/JSNotAnObject.cpp +++ b/Source/JavaScriptCore/runtime/JSNotAnObject.cpp @@ -30,7 +30,7 @@ #include "config.h" #include "JSNotAnObject.h" -#include <wtf/UnusedParam.h> +#include "Operations.h" namespace JSC { diff --git a/Source/JavaScriptCore/runtime/JSNotAnObject.h b/Source/JavaScriptCore/runtime/JSNotAnObject.h index 3636c9bd4..4ec73ac09 100644 --- a/Source/JavaScriptCore/runtime/JSNotAnObject.h +++ b/Source/JavaScriptCore/runtime/JSNotAnObject.h @@ -39,7 +39,7 @@ namespace JSC { class JSNotAnObject : public JSNonFinalObject { private: JSNotAnObject(ExecState* exec) - : JSNonFinalObject(exec->globalData(), exec->globalData().notAnObjectStructure.get()) + : JSNonFinalObject(exec->vm(), exec->vm().notAnObjectStructure.get()) { } @@ -49,13 +49,13 @@ namespace JSC { static JSNotAnObject* create(ExecState* exec) { JSNotAnObject* object = new (NotNull, allocateCell<JSNotAnObject>(*exec->heap())) JSNotAnObject(exec); - object->finishCreation(exec->globalData()); + object->finishCreation(exec->vm()); return object; } - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } static const ClassInfo s_info; diff --git a/Source/JavaScriptCore/runtime/JSONObject.cpp b/Source/JavaScriptCore/runtime/JSONObject.cpp index e051ec7d9..91b412ec3 100644 --- a/Source/JavaScriptCore/runtime/JSONObject.cpp +++ b/Source/JavaScriptCore/runtime/JSONObject.cpp @@ -35,6 +35,8 @@ #include "Local.h" #include "LocalScope.h" #include "Lookup.h" +#include "ObjectConstructor.h" +#include "Operations.h" #include "PropertyNameArray.h" #include <wtf/MathExtras.h> #include <wtf/text/StringBuilder.h> @@ -53,13 +55,13 @@ static EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*); namespace JSC { JSONObject::JSONObject(JSGlobalObject* globalObject, Structure* structure) - : JSNonFinalObject(globalObject->globalData(), structure) + : JSNonFinalObject(globalObject->vm(), structure) { } void JSONObject::finishCreation(JSGlobalObject* globalObject) { - Base::finishCreation(globalObject->globalData()); + Base::finishCreation(globalObject->vm()); ASSERT(inherits(&s_info)); } @@ -88,7 +90,7 @@ public: private: class Holder { public: - Holder(JSGlobalData&, JSObject*); + Holder(VM&, JSObject*); JSObject* object() const { return m_object.get(); } @@ -125,7 +127,7 @@ private: CallData m_replacerCallData; const String m_gap; - Vector<Holder, 16> m_holderStack; + Vector<Holder, 16, UnsafeVectorOverflow> m_holderStack; String m_repeatedGap; String m_indent; }; @@ -215,7 +217,7 @@ Stringifier::Stringifier(ExecState* exec, const Local<Unknown>& replacer, const if (m_replacer.asObject()->inherits(&JSArray::s_info)) { m_usingArrayReplacer = true; Handle<JSObject> array = m_replacer.asObject(); - unsigned length = array->get(exec, exec->globalData().propertyNames->length).toUInt32(exec); + unsigned length = array->get(exec, exec->vm().propertyNames->length).toUInt32(exec); for (unsigned i = 0; i < length; ++i) { JSValue name = array->get(exec, i); if (exec->hadException()) @@ -238,18 +240,18 @@ Local<Unknown> Stringifier::stringify(Handle<Unknown> value) { JSObject* object = constructEmptyObject(m_exec); if (m_exec->hadException()) - return Local<Unknown>(m_exec->globalData(), jsNull()); + return Local<Unknown>(m_exec->vm(), jsNull()); - PropertyNameForFunctionCall emptyPropertyName(m_exec->globalData().propertyNames->emptyIdentifier); - object->putDirect(m_exec->globalData(), m_exec->globalData().propertyNames->emptyIdentifier, value.get()); + PropertyNameForFunctionCall emptyPropertyName(m_exec->vm().propertyNames->emptyIdentifier); + object->putDirect(m_exec->vm(), m_exec->vm().propertyNames->emptyIdentifier, value.get()); StringBuilder result; if (appendStringifiedValue(result, value.get(), object, emptyPropertyName) != StringifySucceeded) - return Local<Unknown>(m_exec->globalData(), jsUndefined()); + return Local<Unknown>(m_exec->vm(), jsUndefined()); if (m_exec->hadException()) - return Local<Unknown>(m_exec->globalData(), jsNull()); + return Local<Unknown>(m_exec->vm(), jsNull()); - return Local<Unknown>(m_exec->globalData(), jsString(m_exec, result.toString())); + return Local<Unknown>(m_exec->vm(), jsString(m_exec, result.toString())); } template <typename CharType> @@ -318,10 +320,10 @@ void Stringifier::appendQuotedString(StringBuilder& builder, const String& value inline JSValue Stringifier::toJSON(JSValue value, const PropertyNameForFunctionCall& propertyName) { ASSERT(!m_exec->hadException()); - if (!value.isObject() || !asObject(value)->hasProperty(m_exec, m_exec->globalData().propertyNames->toJSON)) + if (!value.isObject() || !asObject(value)->hasProperty(m_exec, m_exec->vm().propertyNames->toJSON)) return value; - JSValue toJSONFunction = asObject(value)->get(m_exec, m_exec->globalData().propertyNames->toJSON); + JSValue toJSONFunction = asObject(value)->get(m_exec, m_exec->vm().propertyNames->toJSON); if (m_exec->hadException()) return jsNull(); @@ -385,7 +387,7 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder& if (value.isNumber()) { double number = value.asNumber(); - if (!isfinite(number)) + if (!std::isfinite(number)) builder.appendLiteral("null"); else builder.append(String::numberToStringECMAScript(number)); @@ -414,25 +416,14 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder& } } bool holderStackWasEmpty = m_holderStack.isEmpty(); - m_holderStack.append(Holder(m_exec->globalData(), object)); + m_holderStack.append(Holder(m_exec->vm(), object)); if (!holderStackWasEmpty) return StringifySucceeded; - // If this is the outermost call, then loop to handle everything on the holder stack. - TimeoutChecker localTimeoutChecker(m_exec->globalData().timeoutChecker); - localTimeoutChecker.reset(); - unsigned tickCount = localTimeoutChecker.ticksUntilNextCheck(); do { while (m_holderStack.last().appendNextProperty(*this, builder)) { if (m_exec->hadException()) return StringifyFailed; - if (!--tickCount) { - if (localTimeoutChecker.didTimeOut(m_exec)) { - throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData())); - return StringifyFailed; - } - tickCount = localTimeoutChecker.ticksUntilNextCheck(); - } } m_holderStack.removeLast(); } while (!m_holderStack.isEmpty()); @@ -468,8 +459,8 @@ inline void Stringifier::startNewLine(StringBuilder& builder) const builder.append(m_indent); } -inline Stringifier::Holder::Holder(JSGlobalData& globalData, JSObject* object) - : m_object(globalData, object) +inline Stringifier::Holder::Holder(VM& vm, JSObject* object) + : m_object(vm, object) , m_isArray(object->inherits(&JSArray::s_info)) , m_index(0) #ifndef NDEBUG @@ -488,7 +479,7 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui if (!m_index) { if (m_isArray) { m_isJSArray = isJSArray(m_object.get()); - m_size = m_object->get(exec, exec->globalData().propertyNames->length).toUInt32(exec); + m_size = m_object->get(exec, exec->vm().propertyNames->length).toUInt32(exec); builder.append('['); } else { if (stringifier.m_usingArrayReplacer) @@ -613,7 +604,7 @@ class Walker { public: Walker(ExecState* exec, Handle<JSObject> function, CallType callType, CallData callData) : m_exec(exec) - , m_function(exec->globalData(), function) + , m_function(exec->vm(), function) , m_callType(callType) , m_callData(callData) { @@ -636,26 +627,22 @@ private: CallData m_callData; }; -// We clamp recursion well beyond anything reasonable, but we also have a timeout check -// to guard against "infinite" execution by inserting arbitrarily large objects. +// We clamp recursion well beyond anything reasonable. static const unsigned maximumFilterRecursion = 40000; enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember, ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember }; NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) { - Vector<PropertyNameArray, 16> propertyStack; - Vector<uint32_t, 16> indexStack; - LocalStack<JSObject, 16> objectStack(m_exec->globalData()); - LocalStack<JSArray, 16> arrayStack(m_exec->globalData()); + Vector<PropertyNameArray, 16, UnsafeVectorOverflow> propertyStack; + Vector<uint32_t, 16, UnsafeVectorOverflow> indexStack; + LocalStack<JSObject, 16> objectStack(m_exec->vm()); + LocalStack<JSArray, 16> arrayStack(m_exec->vm()); - Vector<WalkerState, 16> stateStack; + Vector<WalkerState, 16, UnsafeVectorOverflow> stateStack; WalkerState state = StateUnknown; JSValue inValue = unfiltered; JSValue outValue = jsNull(); - TimeoutChecker localTimeoutChecker(m_exec->globalData().timeoutChecker); - localTimeoutChecker.reset(); - unsigned tickCount = localTimeoutChecker.ticksUntilNextCheck(); while (1) { switch (state) { arrayStartState: @@ -672,12 +659,6 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) } arrayStartVisitMember: case ArrayStartVisitMember: { - if (!--tickCount) { - if (localTimeoutChecker.didTimeOut(m_exec)) - return throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData())); - tickCount = localTimeoutChecker.ticksUntilNextCheck(); - } - JSArray* array = arrayStack.peek(); uint32_t index = indexStack.last(); if (index == array->length()) { @@ -731,12 +712,6 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) } objectStartVisitMember: case ObjectStartVisitMember: { - if (!--tickCount) { - if (localTimeoutChecker.didTimeOut(m_exec)) - return throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData())); - tickCount = localTimeoutChecker.ticksUntilNextCheck(); - } - JSObject* object = objectStack.peek(); uint32_t index = indexStack.last(); PropertyNameArray& properties = propertyStack.last(); @@ -794,16 +769,10 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) state = stateStack.last(); stateStack.removeLast(); - - if (!--tickCount) { - if (localTimeoutChecker.didTimeOut(m_exec)) - return throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData())); - tickCount = localTimeoutChecker.ticksUntilNextCheck(); - } } JSObject* finalHolder = constructEmptyObject(m_exec); PutPropertySlot slot; - finalHolder->methodTable()->put(finalHolder, m_exec, m_exec->globalData().propertyNames->emptyIdentifier, outValue, slot); + finalHolder->methodTable()->put(finalHolder, m_exec, m_exec->vm().propertyNames->emptyIdentifier, outValue, slot); return callReviver(finalHolder, jsEmptyString(m_exec), outValue); } @@ -817,7 +786,7 @@ EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState* exec) return JSValue::encode(jsNull()); JSValue unfiltered; - LocalScope scope(exec->globalData()); + LocalScope scope(exec->vm()); if (source.is8Bit()) { LiteralParser<LChar> jsonParser(exec, source.characters8(), source.length(), StrictJSON); unfiltered = jsonParser.tryLiteralParse(); @@ -838,7 +807,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, Local<JSObject>(exec->globalData(), asObject(function)), callType, callData).walk(unfiltered)); + return JSValue::encode(Walker(exec, Local<JSObject>(exec->vm(), asObject(function)), callType, callData).walk(unfiltered)); } // ECMA-262 v5 15.12.3 @@ -846,17 +815,17 @@ EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState* exec) { if (!exec->argumentCount()) return throwVMError(exec, createError(exec, ASCIILiteral("No input to stringify"))); - 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)); + LocalScope scope(exec->vm()); + Local<Unknown> value(exec->vm(), exec->argument(0)); + Local<Unknown> replacer(exec->vm(), exec->argument(1)); + Local<Unknown> space(exec->vm(), exec->argument(2)); return JSValue::encode(Stringifier(exec, replacer, space).stringify(value).get()); } String JSONStringify(ExecState* exec, JSValue value, unsigned indent) { - 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)); + LocalScope scope(exec->vm()); + Local<Unknown> result = Stringifier(exec, Local<Unknown>(exec->vm(), jsNull()), Local<Unknown>(exec->vm(), jsNumber(indent))).stringify(Local<Unknown>(exec->vm(), value)); if (result.isUndefinedOrNull()) return String(); return result.getString(exec); diff --git a/Source/JavaScriptCore/runtime/JSONObject.h b/Source/JavaScriptCore/runtime/JSONObject.h index b537b9144..c02809083 100644 --- a/Source/JavaScriptCore/runtime/JSONObject.h +++ b/Source/JavaScriptCore/runtime/JSONObject.h @@ -43,9 +43,9 @@ namespace JSC { return object; } - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } static const ClassInfo s_info; diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp index e6f95bdfa..48fc23186 100644 --- a/Source/JavaScriptCore/runtime/JSObject.cpp +++ b/Source/JavaScriptCore/runtime/JSObject.cpp @@ -1,7 +1,7 @@ /* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2012, 2013 Apple Inc. All rights reserved. * Copyright (C) 2007 Eric Seidel (eric@webkit.org) * * This library is free software; you can redistribute it and/or @@ -30,6 +30,7 @@ #include "CopyVisitorInlines.h" #include "DatePrototype.h" #include "ErrorConstructor.h" +#include "Executable.h" #include "GetterSetter.h" #include "IndexingHeaderInlines.h" #include "JSFunction.h" @@ -133,9 +134,9 @@ ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butt case ALL_CONTIGUOUS_INDEXING_TYPES: case ALL_INT32_INDEXING_TYPES: case ALL_DOUBLE_INDEXING_TYPES: { - currentTarget = newButterfly->contiguous(); - currentSource = butterfly->contiguous(); - ASSERT(newButterfly->publicLength() <= newButterfly->vectorLength()); + currentTarget = newButterfly->contiguous().data(); + currentSource = butterfly->contiguous().data(); + RELEASE_ASSERT(newButterfly->publicLength() <= newButterfly->vectorLength()); count = newButterfly->vectorLength(); break; } @@ -189,7 +190,7 @@ ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* but // Mark the array if appropriate. switch (structure->indexingType()) { case ALL_CONTIGUOUS_INDEXING_TYPES: - visitor.appendValues(butterfly->contiguous(), butterfly->publicLength()); + visitor.appendValues(butterfly->contiguous().data(), butterfly->publicLength()); break; case ALL_ARRAY_STORAGE_INDEXING_TYPES: visitor.appendValues(butterfly->arrayStorage()->m_vector, butterfly->arrayStorage()->vectorLength()); @@ -328,7 +329,7 @@ bool JSObject::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned } default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); break; } @@ -341,7 +342,7 @@ void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSV JSObject* thisObject = jsCast<JSObject*>(cell); ASSERT(value); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); - JSGlobalData& globalData = exec->globalData(); + VM& vm = exec->vm(); // Try indexed put first. This is required for correctness, since loads on property names that appear like // valid indices will never look in the named property storage. @@ -357,8 +358,8 @@ void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSV for (JSObject* obj = thisObject; !obj->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) { prototype = obj->prototype(); if (prototype.isNull()) { - ASSERT(!thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->globalData(), propertyName)); - if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getCallableObject(value)) + ASSERT(!thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName)); + if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot, getCallableObject(value)) && slot.isStrictMode()) throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError)); return; @@ -370,19 +371,19 @@ void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSV for (obj = thisObject; ; obj = asObject(prototype)) { unsigned attributes; JSCell* specificValue; - PropertyOffset offset = obj->structure()->get(globalData, propertyName, attributes, specificValue); + PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes, specificValue); if (isValidOffset(offset)) { if (attributes & ReadOnly) { - ASSERT(thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->globalData(), propertyName) || obj == thisObject); + ASSERT(thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject); if (slot.isStrictMode()) throwError(exec, createTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError))); return; } - JSValue gs = obj->getDirectOffset(offset); + JSValue gs = obj->getDirect(offset); if (gs.isGetterSetter()) { ASSERT(attributes & Accessor); - ASSERT(thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->globalData(), propertyName) || obj == thisObject); + ASSERT(thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject); JSObject* setterFunc = asGetterSetter(gs)->setter(); if (!setterFunc) { if (slot.isStrictMode()) @@ -411,8 +412,8 @@ void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSV break; } - ASSERT(!thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->globalData(), propertyName) || obj == thisObject); - if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getCallableObject(value)) && slot.isStrictMode()) + ASSERT(!thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject); + if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot, getCallableObject(value)) && slot.isStrictMode()) throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError)); return; } @@ -432,7 +433,7 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, break; case ALL_UNDECIDED_INDEXING_TYPES: { - thisObject->convertUndecidedForValue(exec->globalData(), value); + thisObject->convertUndecidedForValue(exec->vm(), value); // Reloop. putByIndex(cell, exec, propertyName, value, shouldThrow); return; @@ -440,7 +441,7 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, case ALL_INT32_INDEXING_TYPES: { if (!value.isInt32()) { - thisObject->convertInt32ForValue(exec->globalData(), value); + thisObject->convertInt32ForValue(exec->vm(), value); putByIndex(cell, exec, propertyName, value, shouldThrow); return; } @@ -451,7 +452,7 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, Butterfly* butterfly = thisObject->m_butterfly; if (propertyName >= butterfly->vectorLength()) break; - butterfly->contiguous()[propertyName].set(exec->globalData(), thisObject, value); + butterfly->contiguous()[propertyName].set(exec->vm(), thisObject, value); if (propertyName >= butterfly->publicLength()) butterfly->setPublicLength(propertyName + 1); return; @@ -459,14 +460,14 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, case ALL_DOUBLE_INDEXING_TYPES: { if (!value.isNumber()) { - thisObject->convertDoubleToContiguous(exec->globalData()); + thisObject->convertDoubleToContiguous(exec->vm()); // Reloop. putByIndex(cell, exec, propertyName, value, shouldThrow); return; } double valueAsDouble = value.asNumber(); if (valueAsDouble != valueAsDouble) { - thisObject->convertDoubleToContiguous(exec->globalData()); + thisObject->convertDoubleToContiguous(exec->vm()); // Reloop. putByIndex(cell, exec, propertyName, value, shouldThrow); return; @@ -498,7 +499,7 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, } else if (!valueSlot) ++storage->m_numValuesInVector; - valueSlot.set(exec->globalData(), thisObject, value); + valueSlot.set(exec->vm(), thisObject, value); return; } @@ -525,23 +526,23 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, ++storage->m_numValuesInVector; } - valueSlot.set(exec->globalData(), thisObject, value); + valueSlot.set(exec->vm(), thisObject, value); return; } default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } thisObject->putByIndexBeyondVectorLength(exec, propertyName, value, shouldThrow); } -ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(JSGlobalData& globalData, ArrayStorage* storage) +ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(VM& vm, ArrayStorage* storage) { SparseArrayValueMap* map = storage->m_sparseMap.get(); if (!map) - map = allocateSparseIndexMap(globalData); + map = allocateSparseIndexMap(vm); if (map->sparseMode()) return storage; @@ -554,34 +555,34 @@ ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists // This will always be a new entry in the map, so no need to check we can write, // and attributes are default so no need to set them. if (value) - map->add(this, i).iterator->value.set(globalData, this, value); + map->add(this, i).iterator->value.set(vm, this, value); } - Butterfly* newButterfly = storage->butterfly()->resizeArray(globalData, structure(), 0, ArrayStorage::sizeFor(0)); - if (!newButterfly) - CRASH(); + Butterfly* newButterfly = storage->butterfly()->resizeArray(vm, structure(), 0, ArrayStorage::sizeFor(0)); + RELEASE_ASSERT(newButterfly); m_butterfly = newButterfly; newButterfly->arrayStorage()->m_indexBias = 0; newButterfly->arrayStorage()->setVectorLength(0); - newButterfly->arrayStorage()->m_sparseMap.set(globalData, this, map); + newButterfly->arrayStorage()->m_sparseMap.set(vm, this, map); return newButterfly->arrayStorage(); } -void JSObject::enterDictionaryIndexingMode(JSGlobalData& globalData) +void JSObject::enterDictionaryIndexingMode(VM& vm) { switch (structure()->indexingType()) { + case ALL_BLANK_INDEXING_TYPES: case ALL_UNDECIDED_INDEXING_TYPES: case ALL_INT32_INDEXING_TYPES: case ALL_DOUBLE_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: // NOTE: this is horribly inefficient, as it will perform two conversions. We could optimize // this case if we ever cared. - enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, ensureArrayStorageSlow(globalData)); + enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, ensureArrayStorageSlow(vm)); break; case ALL_ARRAY_STORAGE_INDEXING_TYPES: - enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage()); + enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, m_butterfly->arrayStorage()); break; default: @@ -589,20 +590,20 @@ void JSObject::enterDictionaryIndexingMode(JSGlobalData& globalData) } } -void JSObject::notifyPresenceOfIndexedAccessors(JSGlobalData& globalData) +void JSObject::notifyPresenceOfIndexedAccessors(VM& vm) { if (mayInterceptIndexedAccesses()) return; - setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AddIndexedAccessors)); + setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AddIndexedAccessors)); - if (!mayBeUsedAsPrototype(globalData)) + if (!vm.prototypeMap.isPrototype(this)) return; - globalObject()->haveABadTime(globalData); + globalObject()->haveABadTime(vm); } -Butterfly* JSObject::createInitialIndexedStorage(JSGlobalData& globalData, unsigned length, size_t elementSize) +Butterfly* JSObject::createInitialIndexedStorage(VM& vm, unsigned length, size_t elementSize) { ASSERT(length < MAX_ARRAY_INDEX); IndexingType oldType = structure()->indexingType(); @@ -611,105 +612,105 @@ Butterfly* JSObject::createInitialIndexedStorage(JSGlobalData& globalData, unsig ASSERT(!indexingShouldBeSparse()); unsigned vectorLength = std::max(length, BASE_VECTOR_LEN); Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(m_butterfly, - globalData, structure(), structure()->outOfLineCapacity(), false, 0, + vm, structure(), structure()->outOfLineCapacity(), false, 0, elementSize * vectorLength); newButterfly->setPublicLength(length); newButterfly->setVectorLength(vectorLength); return newButterfly; } -Butterfly* JSObject::createInitialUndecided(JSGlobalData& globalData, unsigned length) +Butterfly* JSObject::createInitialUndecided(VM& vm, unsigned length) { - Butterfly* newButterfly = createInitialIndexedStorage(globalData, length, sizeof(EncodedJSValue)); - Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateUndecided); - setButterfly(globalData, newButterfly, newStructure); + Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue)); + Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateUndecided); + setButterfly(vm, newButterfly, newStructure); return newButterfly; } -WriteBarrier<Unknown>* JSObject::createInitialInt32(JSGlobalData& globalData, unsigned length) +ContiguousJSValues JSObject::createInitialInt32(VM& vm, unsigned length) { - Butterfly* newButterfly = createInitialIndexedStorage(globalData, length, sizeof(EncodedJSValue)); - Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateInt32); - setButterfly(globalData, newButterfly, newStructure); + Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue)); + Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateInt32); + setButterfly(vm, newButterfly, newStructure); return newButterfly->contiguousInt32(); } -double* JSObject::createInitialDouble(JSGlobalData& globalData, unsigned length) +ContiguousDoubles JSObject::createInitialDouble(VM& vm, unsigned length) { - Butterfly* newButterfly = createInitialIndexedStorage(globalData, length, sizeof(double)); + Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(double)); for (unsigned i = newButterfly->vectorLength(); i--;) newButterfly->contiguousDouble()[i] = QNaN; - Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateDouble); - setButterfly(globalData, newButterfly, newStructure); + Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateDouble); + setButterfly(vm, newButterfly, newStructure); return newButterfly->contiguousDouble(); } -WriteBarrier<Unknown>* JSObject::createInitialContiguous(JSGlobalData& globalData, unsigned length) +ContiguousJSValues JSObject::createInitialContiguous(VM& vm, unsigned length) { - Butterfly* newButterfly = createInitialIndexedStorage(globalData, length, sizeof(EncodedJSValue)); - Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous); - setButterfly(globalData, newButterfly, newStructure); + Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue)); + Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateContiguous); + setButterfly(vm, newButterfly, newStructure); return newButterfly->contiguous(); } -ArrayStorage* JSObject::createArrayStorage(JSGlobalData& globalData, unsigned length, unsigned vectorLength) +ArrayStorage* JSObject::createArrayStorage(VM& vm, unsigned length, unsigned vectorLength) { IndexingType oldType = structure()->indexingType(); ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType)); Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(m_butterfly, - globalData, structure(), structure()->outOfLineCapacity(), false, 0, + vm, structure(), structure()->outOfLineCapacity(), false, 0, ArrayStorage::sizeFor(vectorLength)); - if (!newButterfly) - CRASH(); + RELEASE_ASSERT(newButterfly); + ArrayStorage* result = newButterfly->arrayStorage(); result->setLength(length); result->setVectorLength(vectorLength); result->m_sparseMap.clear(); result->m_numValuesInVector = 0; result->m_indexBias = 0; - Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), structure()->suggestedArrayStorageTransition()); - setButterfly(globalData, newButterfly, newStructure); + Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), structure()->suggestedArrayStorageTransition()); + setButterfly(vm, newButterfly, newStructure); return result; } -ArrayStorage* JSObject::createInitialArrayStorage(JSGlobalData& globalData) +ArrayStorage* JSObject::createInitialArrayStorage(VM& vm) { - return createArrayStorage(globalData, 0, BASE_VECTOR_LEN); + return createArrayStorage(vm, 0, BASE_VECTOR_LEN); } -WriteBarrier<Unknown>* JSObject::convertUndecidedToInt32(JSGlobalData& globalData) +ContiguousJSValues JSObject::convertUndecidedToInt32(VM& vm) { ASSERT(hasUndecided(structure()->indexingType())); - setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateInt32)); + setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateInt32)); return m_butterfly->contiguousInt32(); } -double* JSObject::convertUndecidedToDouble(JSGlobalData& globalData) +ContiguousDoubles JSObject::convertUndecidedToDouble(VM& vm) { ASSERT(hasUndecided(structure()->indexingType())); for (unsigned i = m_butterfly->vectorLength(); i--;) m_butterfly->contiguousDouble()[i] = QNaN; - setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateDouble)); + setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble)); return m_butterfly->contiguousDouble(); } -WriteBarrier<Unknown>* JSObject::convertUndecidedToContiguous(JSGlobalData& globalData) +ContiguousJSValues JSObject::convertUndecidedToContiguous(VM& vm) { ASSERT(hasUndecided(structure()->indexingType())); - setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous)); + setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous)); return m_butterfly->contiguous(); } -ArrayStorage* JSObject::constructConvertedArrayStorageWithoutCopyingElements(JSGlobalData& globalData, unsigned neededLength) +ArrayStorage* JSObject::constructConvertedArrayStorageWithoutCopyingElements(VM& vm, unsigned neededLength) { unsigned publicLength = m_butterfly->publicLength(); unsigned propertyCapacity = structure()->outOfLineCapacity(); unsigned propertySize = structure()->outOfLineSize(); Butterfly* newButterfly = Butterfly::createUninitialized( - globalData, 0, propertyCapacity, true, ArrayStorage::sizeFor(neededLength)); + vm, 0, propertyCapacity, true, ArrayStorage::sizeFor(neededLength)); memcpy( newButterfly->propertyStorage() - propertySize, @@ -726,29 +727,29 @@ ArrayStorage* JSObject::constructConvertedArrayStorageWithoutCopyingElements(JSG return newStorage; } -ArrayStorage* JSObject::convertUndecidedToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength) +ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength) { ASSERT(hasUndecided(structure()->indexingType())); - ArrayStorage* storage = constructConvertedArrayStorageWithoutCopyingElements(globalData, neededLength); + ArrayStorage* storage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength); // No need to copy elements. - Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition); - setButterfly(globalData, storage->butterfly(), newStructure); + Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition); + setButterfly(vm, storage->butterfly(), newStructure); return storage; } -ArrayStorage* JSObject::convertUndecidedToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition) +ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm, NonPropertyTransition transition) { - return convertUndecidedToArrayStorage(globalData, transition, m_butterfly->vectorLength()); + return convertUndecidedToArrayStorage(vm, transition, m_butterfly->vectorLength()); } -ArrayStorage* JSObject::convertUndecidedToArrayStorage(JSGlobalData& globalData) +ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm) { - return convertUndecidedToArrayStorage(globalData, structure()->suggestedArrayStorageTransition()); + return convertUndecidedToArrayStorage(vm, structure()->suggestedArrayStorageTransition()); } -double* JSObject::convertInt32ToDouble(JSGlobalData& globalData) +ContiguousDoubles JSObject::convertInt32ToDouble(VM& vm) { ASSERT(hasInt32(structure()->indexingType())); @@ -764,23 +765,23 @@ double* JSObject::convertInt32ToDouble(JSGlobalData& globalData) *currentAsDouble = v.asInt32(); } - setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateDouble)); + setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble)); return m_butterfly->contiguousDouble(); } -WriteBarrier<Unknown>* JSObject::convertInt32ToContiguous(JSGlobalData& globalData) +ContiguousJSValues JSObject::convertInt32ToContiguous(VM& vm) { ASSERT(hasInt32(structure()->indexingType())); - setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous)); + setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous)); return m_butterfly->contiguous(); } -ArrayStorage* JSObject::convertInt32ToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength) +ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength) { ASSERT(hasInt32(structure()->indexingType())); - ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(globalData, neededLength); + ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength); for (unsigned i = m_butterfly->publicLength(); i--;) { JSValue v = m_butterfly->contiguous()[i].get(); if (!v) @@ -789,22 +790,23 @@ ArrayStorage* JSObject::convertInt32ToArrayStorage(JSGlobalData& globalData, Non newStorage->m_numValuesInVector++; } - Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition); - setButterfly(globalData, newStorage->butterfly(), newStructure); + Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition); + setButterfly(vm, newStorage->butterfly(), newStructure); return newStorage; } -ArrayStorage* JSObject::convertInt32ToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition) +ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm, NonPropertyTransition transition) { - return convertInt32ToArrayStorage(globalData, transition, m_butterfly->vectorLength()); + return convertInt32ToArrayStorage(vm, transition, m_butterfly->vectorLength()); } -ArrayStorage* JSObject::convertInt32ToArrayStorage(JSGlobalData& globalData) +ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm) { - return convertInt32ToArrayStorage(globalData, structure()->suggestedArrayStorageTransition()); + return convertInt32ToArrayStorage(vm, structure()->suggestedArrayStorageTransition()); } -WriteBarrier<Unknown>* JSObject::convertDoubleToContiguous(JSGlobalData& globalData) +template<JSObject::DoubleToContiguousMode mode> +ContiguousJSValues JSObject::genericConvertDoubleToContiguous(VM& vm) { ASSERT(hasDouble(structure()->indexingType())); @@ -816,18 +818,38 @@ WriteBarrier<Unknown>* JSObject::convertDoubleToContiguous(JSGlobalData& globalD currentAsValue->clear(); continue; } - currentAsValue->setWithoutWriteBarrier(JSValue(JSValue::EncodeAsDouble, value)); + JSValue v; + switch (mode) { + case EncodeValueAsDouble: + v = JSValue(JSValue::EncodeAsDouble, value); + break; + case RageConvertDoubleToValue: + v = jsNumber(value); + break; + } + ASSERT(v.isNumber()); + currentAsValue->setWithoutWriteBarrier(v); } - setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous)); + setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous)); return m_butterfly->contiguous(); } -ArrayStorage* JSObject::convertDoubleToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength) +ContiguousJSValues JSObject::convertDoubleToContiguous(VM& vm) +{ + return genericConvertDoubleToContiguous<EncodeValueAsDouble>(vm); +} + +ContiguousJSValues JSObject::rageConvertDoubleToContiguous(VM& vm) +{ + return genericConvertDoubleToContiguous<RageConvertDoubleToValue>(vm); +} + +ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength) { ASSERT(hasDouble(structure()->indexingType())); - ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(globalData, neededLength); + ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength); for (unsigned i = m_butterfly->publicLength(); i--;) { double value = m_butterfly->contiguousDouble()[i]; if (value != value) @@ -836,26 +858,26 @@ ArrayStorage* JSObject::convertDoubleToArrayStorage(JSGlobalData& globalData, No newStorage->m_numValuesInVector++; } - Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition); - setButterfly(globalData, newStorage->butterfly(), newStructure); + Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition); + setButterfly(vm, newStorage->butterfly(), newStructure); return newStorage; } -ArrayStorage* JSObject::convertDoubleToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition) +ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm, NonPropertyTransition transition) { - return convertDoubleToArrayStorage(globalData, transition, m_butterfly->vectorLength()); + return convertDoubleToArrayStorage(vm, transition, m_butterfly->vectorLength()); } -ArrayStorage* JSObject::convertDoubleToArrayStorage(JSGlobalData& globalData) +ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm) { - return convertDoubleToArrayStorage(globalData, structure()->suggestedArrayStorageTransition()); + return convertDoubleToArrayStorage(vm, structure()->suggestedArrayStorageTransition()); } -ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength) +ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength) { ASSERT(hasContiguous(structure()->indexingType())); - ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(globalData, neededLength); + ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength); for (unsigned i = m_butterfly->publicLength(); i--;) { JSValue v = m_butterfly->contiguous()[i].get(); if (!v) @@ -864,200 +886,220 @@ ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData newStorage->m_numValuesInVector++; } - Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition); - setButterfly(globalData, newStorage->butterfly(), newStructure); + Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition); + setButterfly(vm, newStorage->butterfly(), newStructure); return newStorage; } -ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition) +ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm, NonPropertyTransition transition) { - return convertContiguousToArrayStorage(globalData, transition, m_butterfly->vectorLength()); + return convertContiguousToArrayStorage(vm, transition, m_butterfly->vectorLength()); } -ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData) +ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm) { - return convertContiguousToArrayStorage(globalData, structure()->suggestedArrayStorageTransition()); + return convertContiguousToArrayStorage(vm, structure()->suggestedArrayStorageTransition()); } -void JSObject::convertUndecidedForValue(JSGlobalData& globalData, JSValue value) +void JSObject::convertUndecidedForValue(VM& vm, JSValue value) { if (value.isInt32()) { - convertUndecidedToInt32(globalData); + convertUndecidedToInt32(vm); return; } if (value.isDouble()) { - convertUndecidedToDouble(globalData); + convertUndecidedToDouble(vm); return; } - convertUndecidedToContiguous(globalData); + convertUndecidedToContiguous(vm); } -void JSObject::convertInt32ForValue(JSGlobalData& globalData, JSValue value) +void JSObject::convertInt32ForValue(VM& vm, JSValue value) { ASSERT(!value.isInt32()); if (value.isDouble()) { - convertInt32ToDouble(globalData); + convertInt32ToDouble(vm); return; } - convertInt32ToContiguous(globalData); + convertInt32ToContiguous(vm); } -void JSObject::setIndexQuicklyToUndecided(JSGlobalData& globalData, unsigned index, JSValue value) +void JSObject::setIndexQuicklyToUndecided(VM& vm, unsigned index, JSValue value) { ASSERT(index < m_butterfly->publicLength()); ASSERT(index < m_butterfly->vectorLength()); - convertUndecidedForValue(globalData, value); - setIndexQuickly(globalData, index, value); + convertUndecidedForValue(vm, value); + setIndexQuickly(vm, index, value); } -void JSObject::convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(JSGlobalData& globalData, unsigned index, JSValue value) +void JSObject::convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(VM& vm, unsigned index, JSValue value) { ASSERT(!value.isInt32()); - convertInt32ForValue(globalData, value); - setIndexQuickly(globalData, index, value); + convertInt32ForValue(vm, value); + setIndexQuickly(vm, index, value); } -void JSObject::convertDoubleToContiguousWhilePerformingSetIndex(JSGlobalData& globalData, unsigned index, JSValue value) +void JSObject::convertDoubleToContiguousWhilePerformingSetIndex(VM& vm, unsigned index, JSValue value) { ASSERT(!value.isNumber() || value.asNumber() != value.asNumber()); - convertDoubleToContiguous(globalData); - setIndexQuickly(globalData, index, value); + convertDoubleToContiguous(vm); + setIndexQuickly(vm, index, value); } -WriteBarrier<Unknown>* JSObject::ensureInt32Slow(JSGlobalData& globalData) +ContiguousJSValues JSObject::ensureInt32Slow(VM& vm) { + ASSERT(inherits(&s_info)); + switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing())) - return 0; - return createInitialInt32(globalData, 0); + return ContiguousJSValues(); + return createInitialInt32(vm, 0); case ALL_UNDECIDED_INDEXING_TYPES: - return convertUndecidedToInt32(globalData); + return convertUndecidedToInt32(vm); case ALL_DOUBLE_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return 0; + return ContiguousJSValues(); default: CRASH(); - return 0; + return ContiguousJSValues(); } } -double* JSObject::ensureDoubleSlow(JSGlobalData& globalData) +ContiguousDoubles JSObject::ensureDoubleSlow(VM& vm) { + ASSERT(inherits(&s_info)); + switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing())) - return 0; - return createInitialDouble(globalData, 0); + return ContiguousDoubles(); + return createInitialDouble(vm, 0); case ALL_UNDECIDED_INDEXING_TYPES: - return convertUndecidedToDouble(globalData); + return convertUndecidedToDouble(vm); case ALL_INT32_INDEXING_TYPES: - return convertInt32ToDouble(globalData); + return convertInt32ToDouble(vm); case ALL_CONTIGUOUS_INDEXING_TYPES: case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return 0; + return ContiguousDoubles(); default: CRASH(); - return 0; + return ContiguousDoubles(); } } -WriteBarrier<Unknown>* JSObject::ensureContiguousSlow(JSGlobalData& globalData) +ContiguousJSValues JSObject::ensureContiguousSlow(VM& vm, DoubleToContiguousMode mode) { + ASSERT(inherits(&s_info)); + switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing())) - return 0; - return createInitialContiguous(globalData, 0); + return ContiguousJSValues(); + return createInitialContiguous(vm, 0); case ALL_UNDECIDED_INDEXING_TYPES: - return convertUndecidedToContiguous(globalData); + return convertUndecidedToContiguous(vm); case ALL_INT32_INDEXING_TYPES: - return convertInt32ToContiguous(globalData); + return convertInt32ToContiguous(vm); case ALL_DOUBLE_INDEXING_TYPES: - return convertDoubleToContiguous(globalData); + if (mode == RageConvertDoubleToValue) + return rageConvertDoubleToContiguous(vm); + return convertDoubleToContiguous(vm); case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return 0; + return ContiguousJSValues(); default: CRASH(); - return 0; + return ContiguousJSValues(); } } -ArrayStorage* JSObject::ensureArrayStorageSlow(JSGlobalData& globalData) +ContiguousJSValues JSObject::ensureContiguousSlow(VM& vm) { + return ensureContiguousSlow(vm, EncodeValueAsDouble); +} + +ContiguousJSValues JSObject::rageEnsureContiguousSlow(VM& vm) +{ + return ensureContiguousSlow(vm, RageConvertDoubleToValue); +} + +ArrayStorage* JSObject::ensureArrayStorageSlow(VM& vm) +{ + ASSERT(inherits(&s_info)); + switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: if (UNLIKELY(indexingShouldBeSparse())) - return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData); - return createInitialArrayStorage(globalData); + return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm); + return createInitialArrayStorage(vm); case ALL_UNDECIDED_INDEXING_TYPES: ASSERT(!indexingShouldBeSparse()); ASSERT(!structure()->needsSlowPutIndexing()); - return convertUndecidedToArrayStorage(globalData); + return convertUndecidedToArrayStorage(vm); case ALL_INT32_INDEXING_TYPES: ASSERT(!indexingShouldBeSparse()); ASSERT(!structure()->needsSlowPutIndexing()); - return convertInt32ToArrayStorage(globalData); + return convertInt32ToArrayStorage(vm); case ALL_DOUBLE_INDEXING_TYPES: ASSERT(!indexingShouldBeSparse()); ASSERT(!structure()->needsSlowPutIndexing()); - return convertDoubleToArrayStorage(globalData); + return convertDoubleToArrayStorage(vm); case ALL_CONTIGUOUS_INDEXING_TYPES: ASSERT(!indexingShouldBeSparse()); ASSERT(!structure()->needsSlowPutIndexing()); - return convertContiguousToArrayStorage(globalData); + return convertContiguousToArrayStorage(vm); default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return 0; } } -ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(JSGlobalData& globalData) +ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(VM& vm) { switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: { - createArrayStorage(globalData, 0, 0); - SparseArrayValueMap* map = allocateSparseIndexMap(globalData); + createArrayStorage(vm, 0, 0); + SparseArrayValueMap* map = allocateSparseIndexMap(vm); map->setSparseMode(); return arrayStorage(); } case ALL_UNDECIDED_INDEXING_TYPES: - return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertUndecidedToArrayStorage(globalData)); + return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertUndecidedToArrayStorage(vm)); case ALL_INT32_INDEXING_TYPES: - return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertInt32ToArrayStorage(globalData)); + return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertInt32ToArrayStorage(vm)); case ALL_DOUBLE_INDEXING_TYPES: - return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertDoubleToArrayStorage(globalData)); + return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertDoubleToArrayStorage(vm)); case ALL_CONTIGUOUS_INDEXING_TYPES: - return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertContiguousToArrayStorage(globalData)); + return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertContiguousToArrayStorage(vm)); case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage()); + return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, m_butterfly->arrayStorage()); default: CRASH(); @@ -1065,29 +1107,29 @@ ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(J } } -void JSObject::switchToSlowPutArrayStorage(JSGlobalData& globalData) +void JSObject::switchToSlowPutArrayStorage(VM& vm) { switch (structure()->indexingType()) { case ALL_UNDECIDED_INDEXING_TYPES: - convertUndecidedToArrayStorage(globalData, AllocateSlowPutArrayStorage); + convertUndecidedToArrayStorage(vm, AllocateSlowPutArrayStorage); break; case ALL_INT32_INDEXING_TYPES: - convertInt32ToArrayStorage(globalData, AllocateSlowPutArrayStorage); + convertInt32ToArrayStorage(vm, AllocateSlowPutArrayStorage); break; case ALL_DOUBLE_INDEXING_TYPES: - convertDoubleToArrayStorage(globalData, AllocateSlowPutArrayStorage); + convertDoubleToArrayStorage(vm, AllocateSlowPutArrayStorage); break; case ALL_CONTIGUOUS_INDEXING_TYPES: - convertContiguousToArrayStorage(globalData, AllocateSlowPutArrayStorage); + convertContiguousToArrayStorage(vm, AllocateSlowPutArrayStorage); break; case NonArrayWithArrayStorage: case ArrayWithArrayStorage: { - Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), SwitchToSlowPutArrayStorage); - setStructure(globalData, newStructure); + Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), SwitchToSlowPutArrayStorage); + setStructure(vm, newStructure); break; } @@ -1101,23 +1143,23 @@ void JSObject::putDirectVirtual(JSObject* object, ExecState* exec, PropertyName { ASSERT(!value.isGetterSetter() && !(attributes & Accessor)); PutPropertySlot slot; - object->putDirectInternal<PutModeDefineOwnProperty>(exec->globalData(), propertyName, value, attributes, slot, getCallableObject(value)); + object->putDirectInternal<PutModeDefineOwnProperty>(exec->vm(), propertyName, value, attributes, slot, getCallableObject(value)); } -void JSObject::setPrototype(JSGlobalData& globalData, JSValue prototype) +void JSObject::setPrototype(VM& vm, JSValue prototype) { ASSERT(prototype); if (prototype.isObject()) - asObject(prototype)->notifyUsedAsPrototype(globalData); + vm.prototypeMap.addPrototype(asObject(prototype)); - Structure* newStructure = Structure::changePrototypeTransition(globalData, structure(), prototype); - setStructure(globalData, newStructure); + Structure* newStructure = Structure::changePrototypeTransition(vm, structure(), prototype); + setStructure(vm, newStructure); if (!newStructure->anyObjectInChainMayInterceptIndexedAccesses()) return; - if (mayBeUsedAsPrototype(globalData)) { - newStructure->globalObject()->haveABadTime(globalData); + if (vm.prototypeMap.isPrototype(this)) { + newStructure->globalObject()->haveABadTime(vm); return; } @@ -1127,10 +1169,10 @@ void JSObject::setPrototype(JSGlobalData& globalData, JSValue prototype) if (shouldUseSlowPut(structure()->indexingType())) return; - switchToSlowPutArrayStorage(globalData); + switchToSlowPutArrayStorage(vm); } -bool JSObject::setPrototypeWithCycleCheck(JSGlobalData& globalData, JSValue prototype) +bool JSObject::setPrototypeWithCycleCheck(VM& vm, JSValue prototype) { JSValue checkFor = this; if (this->isGlobalObject()) @@ -1142,33 +1184,10 @@ bool JSObject::setPrototypeWithCycleCheck(JSGlobalData& globalData, JSValue prot return false; nextPrototype = asObject(nextPrototype)->prototype(); } - setPrototype(globalData, prototype); + setPrototype(vm, prototype); return true; } -void JSObject::resetInheritorID(JSGlobalData& globalData) -{ - PropertyOffset offset = structure()->get(globalData, globalData.m_inheritorIDKey); - if (!isValidOffset(offset)) - return; - - putDirectOffset(globalData, offset, jsUndefined()); -} - -Structure* JSObject::inheritorID(JSGlobalData& globalData) -{ - if (WriteBarrierBase<Unknown>* location = getDirectLocation(globalData, globalData.m_inheritorIDKey)) { - JSValue value = location->get(); - if (value.isCell()) { - Structure* inheritorID = jsCast<Structure*>(value); - ASSERT(inheritorID->isEmpty()); - return inheritorID; - } - ASSERT(value.isUndefined()); - } - return createInheritorID(globalData); -} - bool JSObject::allowsAccessFrom(ExecState* exec) { JSGlobalObject* globalObject = this->globalObject(); @@ -1185,21 +1204,21 @@ void JSObject::putDirectAccessor(ExecState* exec, PropertyName propertyName, JSV return; } - JSGlobalData& globalData = exec->globalData(); + VM& vm = exec->vm(); PutPropertySlot slot; - putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, attributes, slot, getCallableObject(value)); + putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot, getCallableObject(value)); // 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) - setStructure(globalData, Structure::attributeChangeTransition(globalData, structure(), propertyName, attributes)); + setStructure(vm, Structure::attributeChangeTransition(vm, structure(), propertyName, attributes)); if (attributes & ReadOnly) structure()->setContainsReadOnlyProperties(); - structure()->setHasGetterSetterProperties(propertyName == globalData.propertyNames->underscoreProto); + structure()->setHasGetterSetterProperties(propertyName == vm.propertyNames->underscoreProto); } bool JSObject::hasProperty(ExecState* exec, PropertyName propertyName) const @@ -1228,19 +1247,22 @@ bool JSObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName proper unsigned attributes; JSCell* specificValue; - if (isValidOffset(thisObject->structure()->get(exec->globalData(), propertyName, attributes, specificValue))) { - if (attributes & DontDelete && !exec->globalData().isInDefineOwnProperty()) + if (isValidOffset(thisObject->structure()->get(exec->vm(), propertyName, attributes, specificValue))) { + if (attributes & DontDelete && !exec->vm().isInDefineOwnProperty()) return false; - thisObject->removeDirect(exec->globalData(), propertyName); + thisObject->removeDirect(exec->vm(), propertyName); return true; } // Look in the static hashtable of properties const HashEntry* entry = thisObject->findPropertyHashEntry(exec, propertyName); - if (entry && entry->attributes() & DontDelete && !exec->globalData().isInDefineOwnProperty()) - return false; // this builtin property can't be deleted + if (entry) { + if (entry->attributes() & DontDelete && !exec->vm().isInDefineOwnProperty()) + return false; // this builtin property can't be deleted + + putEntry(exec, entry, propertyName, jsUndefined(), thisObject); + } - // FIXME: Should the code here actually do some deletion? return true; } @@ -1301,7 +1323,7 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i) } default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return false; } } @@ -1378,7 +1400,7 @@ bool JSObject::hasInstance(ExecState* exec, JSValue value) return defaultHasInstance(exec, value, get(exec, exec->propertyNames().prototype)); if (info.implementsHasInstance()) return methodTable()->customHasInstance(this, exec, value); - throwError(exec, createInvalidParamError(exec, "instanceof" , this)); + throwError(exec, createInvalidParameterError(exec, "instanceof" , this)); return false; } @@ -1411,7 +1433,7 @@ bool JSObject::propertyIsEnumerable(ExecState* exec, const Identifier& propertyN bool JSObject::getPropertySpecificValue(ExecState* exec, PropertyName propertyName, JSCell*& specificValue) const { unsigned attributes; - if (isValidOffset(structure()->get(exec->globalData(), propertyName, attributes, specificValue))) + if (isValidOffset(structure()->get(exec->vm(), propertyName, attributes, specificValue))) return true; // This could be a function within the static table? - should probably @@ -1488,13 +1510,13 @@ void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNa } if (SparseArrayValueMap* map = storage->m_sparseMap.get()) { - Vector<unsigned> keys; - keys.reserveCapacity(map->size()); + Vector<unsigned, 0, UnsafeVectorOverflow> keys; + keys.reserveInitialCapacity(map->size()); SparseArrayValueMap::const_iterator end = map->end(); for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) { if (mode == IncludeDontEnumProperties || !(it->value.attributes & DontEnum)) - keys.append(static_cast<unsigned>(it->key)); + keys.uncheckedAppend(static_cast<unsigned>(it->key)); } std::sort(keys.begin(), keys.end()); @@ -1505,7 +1527,7 @@ void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNa } default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } object->methodTable()->getOwnNonIndexPropertyNames(object, exec, propertyNames, mode); @@ -1516,7 +1538,7 @@ void JSObject::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, Pr getClassPropertyNames(exec, object->classInfo(), propertyNames, mode, object->staticFunctionsReified()); bool canCachePropertiesFromStructure = !propertyNames.size(); - object->structure()->getPropertyNamesFromStructure(exec->globalData(), propertyNames, mode); + object->structure()->getPropertyNamesFromStructure(exec->vm(), propertyNames, mode); if (canCachePropertiesFromStructure) propertyNames.setNumCacheableSlotsForObject(object, propertyNames.size()); @@ -1543,27 +1565,27 @@ JSObject* JSObject::toThisObject(JSCell* cell, ExecState*) return jsCast<JSObject*>(cell); } -void JSObject::seal(JSGlobalData& globalData) +void JSObject::seal(VM& vm) { - if (isSealed(globalData)) + if (isSealed(vm)) return; - preventExtensions(globalData); - setStructure(globalData, Structure::sealTransition(globalData, structure())); + preventExtensions(vm); + setStructure(vm, Structure::sealTransition(vm, structure())); } -void JSObject::freeze(JSGlobalData& globalData) +void JSObject::freeze(VM& vm) { - if (isFrozen(globalData)) + if (isFrozen(vm)) return; - preventExtensions(globalData); - setStructure(globalData, Structure::freezeTransition(globalData, structure())); + preventExtensions(vm); + setStructure(vm, Structure::freezeTransition(vm, structure())); } -void JSObject::preventExtensions(JSGlobalData& globalData) +void JSObject::preventExtensions(VM& vm) { - enterDictionaryIndexingMode(globalData); + enterDictionaryIndexingMode(vm); if (isExtensible()) - setStructure(globalData, Structure::preventExtensionsTransition(globalData, structure())); + setStructure(vm, Structure::preventExtensionsTransition(vm, structure())); } // This presently will flatten to an uncachable dictionary; this is suitable @@ -1571,7 +1593,7 @@ void JSObject::preventExtensions(JSGlobalData& globalData) void JSObject::reifyStaticFunctionsForDelete(ExecState* exec) { ASSERT(!staticFunctionsReified()); - JSGlobalData& globalData = exec->globalData(); + VM& vm = exec->vm(); // If this object's ClassInfo has no static properties, then nothing to reify! // We can safely set the flag to avoid the expensive check again in the future. @@ -1581,46 +1603,46 @@ void JSObject::reifyStaticFunctionsForDelete(ExecState* exec) } if (!structure()->isUncacheableDictionary()) - setStructure(globalData, Structure::toUncacheableDictionaryTransition(globalData, structure())); + setStructure(vm, Structure::toUncacheableDictionaryTransition(vm, structure())); for (const ClassInfo* info = classInfo(); info; info = info->parentClass) { const HashTable* hashTable = info->propHashTable(globalObject()->globalExec()); if (!hashTable) continue; PropertySlot slot; - for (HashTable::ConstIterator iter = hashTable->begin(globalData); iter != hashTable->end(globalData); ++iter) { + for (HashTable::ConstIterator iter = hashTable->begin(vm); iter != hashTable->end(vm); ++iter) { if (iter->attributes() & Function) - setUpStaticFunctionSlot(globalObject()->globalExec(), *iter, this, Identifier(&globalData, iter->key()), slot); + setUpStaticFunctionSlot(globalObject()->globalExec(), *iter, this, Identifier(&vm, iter->key()), slot); } } structure()->setStaticFunctionsReified(); } -bool JSObject::removeDirect(JSGlobalData& globalData, PropertyName propertyName) +bool JSObject::removeDirect(VM& vm, PropertyName propertyName) { - if (!isValidOffset(structure()->get(globalData, propertyName))) + if (!isValidOffset(structure()->get(vm, propertyName))) return false; PropertyOffset offset; if (structure()->isUncacheableDictionary()) { - offset = structure()->removePropertyWithoutTransition(globalData, propertyName); + offset = structure()->removePropertyWithoutTransition(vm, propertyName); if (offset == invalidOffset) return false; - putUndefinedAtDirectOffset(offset); + putDirectUndefined(offset); return true; } - setStructure(globalData, Structure::removePropertyTransition(globalData, structure(), propertyName, offset)); + setStructure(vm, Structure::removePropertyTransition(vm, structure(), propertyName, offset)); if (offset == invalidOffset) return false; - putUndefinedAtDirectOffset(offset); + putDirectUndefined(offset); return true; } NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, PropertyOffset offset) { - if (JSObject* getterFunction = asGetterSetter(getDirectOffset(offset))->getter()) { + if (JSObject* getterFunction = asGetterSetter(getDirect(offset))->getter()) { if (!structure()->isDictionary()) slot.setCacheableGetterSlot(this, getterFunction, offset); else @@ -1629,49 +1651,13 @@ NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, PropertyO slot.setUndefined(); } -void JSObject::notifyUsedAsPrototype(JSGlobalData& globalData) -{ - PropertyOffset offset = structure()->get(globalData, globalData.m_inheritorIDKey); - if (isValidOffset(offset)) - return; - - PutPropertySlot slot; - putDirectInternal<PutModeDefineOwnProperty>(globalData, globalData.m_inheritorIDKey, jsUndefined(), DontEnum, slot, 0); - - // Note that this method makes the somewhat odd decision to not check if this - // object currently has indexed accessors. We could do that check here, and if - // indexed accessors were found, we could tell the global object to have a bad - // time. But we avoid this, to allow the following to be always fast: - // - // 1) Create an object. - // 2) Give it a setter or read-only property that happens to have a numeric name. - // 3) Allocate objects that use this object as a prototype. - // - // This avoids anyone having a bad time. Even if the instance objects end up - // having indexed storage, the creation of indexed storage leads to a prototype - // chain walk that detects the presence of indexed setters and then does the - // right thing. As a result, having a bad time only happens if you add an - // indexed setter (or getter, or read-only field) to an object that is already - // used as a prototype. -} - -Structure* JSObject::createInheritorID(JSGlobalData& globalData) -{ - Structure* inheritorID = createEmptyObjectStructure(globalData, globalObject(), this); - ASSERT(inheritorID->isEmpty()); - - PutPropertySlot slot; - putDirectInternal<PutModeDefineOwnProperty>(globalData, globalData.m_inheritorIDKey, inheritorID, DontEnum, slot, 0); - return inheritorID; -} - void JSObject::putIndexedDescriptor(ExecState* exec, SparseArrayEntry* entryInMap, PropertyDescriptor& descriptor, PropertyDescriptor& oldDescriptor) { if (descriptor.isDataDescriptor()) { if (descriptor.value()) - entryInMap->set(exec->globalData(), this, descriptor.value()); + entryInMap->set(exec->vm(), this, descriptor.value()); else if (oldDescriptor.isAccessorDescriptor()) - entryInMap->set(exec->globalData(), this, jsUndefined()); + entryInMap->set(exec->vm(), this, jsUndefined()); entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~Accessor; return; } @@ -1690,11 +1676,11 @@ void JSObject::putIndexedDescriptor(ExecState* exec, SparseArrayEntry* entryInMa GetterSetter* accessor = GetterSetter::create(exec); if (getter) - accessor->setGetter(exec->globalData(), getter); + accessor->setGetter(exec->vm(), getter); if (setter) - accessor->setSetter(exec->globalData(), setter); + accessor->setSetter(exec->vm(), setter); - entryInMap->set(exec->globalData(), this, accessor); + entryInMap->set(exec->vm(), this, accessor); entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~ReadOnly; return; } @@ -1718,14 +1704,14 @@ bool JSObject::defineOwnIndexedProperty(ExecState* exec, unsigned index, Propert return putDirectIndex(exec, index, descriptor.value(), 0, throwException ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow); } - ensureArrayStorageExistsAndEnterDictionaryIndexingMode(exec->globalData()); + ensureArrayStorageExistsAndEnterDictionaryIndexingMode(exec->vm()); } if (descriptor.attributes() & (ReadOnly | Accessor)) - notifyPresenceOfIndexedAccessors(exec->globalData()); + notifyPresenceOfIndexedAccessors(exec->vm()); SparseArrayValueMap* map = m_butterfly->arrayStorage()->m_sparseMap.get(); - ASSERT(map); + RELEASE_ASSERT(map); // 1. Let current be the result of calling the [[GetOwnProperty]] internal method of O with property name P. SparseArrayValueMap::AddResult result = map->add(this, index); @@ -1825,10 +1811,10 @@ bool JSObject::defineOwnIndexedProperty(ExecState* exec, unsigned index, Propert return true; } -SparseArrayValueMap* JSObject::allocateSparseIndexMap(JSGlobalData& globalData) +SparseArrayValueMap* JSObject::allocateSparseIndexMap(VM& vm) { - SparseArrayValueMap* result = SparseArrayValueMap::create(globalData); - arrayStorage()->m_sparseMap.set(globalData, this, result); + SparseArrayValueMap* result = SparseArrayValueMap::create(vm); + arrayStorage()->m_sparseMap.set(vm, this, result); return result; } @@ -1882,23 +1868,23 @@ void JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, un // or equal to the vector length. ASSERT(i >= m_butterfly->vectorLength()); - JSGlobalData& globalData = exec->globalData(); + VM& vm = exec->vm(); if (i >= MAX_ARRAY_INDEX - 1 || (i >= MIN_SPARSE_ARRAY_INDEX && !isDenseEnoughForVector(i, countElements<indexingShape>(m_butterfly)))) { ASSERT(i <= MAX_ARRAY_INDEX); - ensureArrayStorageSlow(globalData); - SparseArrayValueMap* map = allocateSparseIndexMap(globalData); + ensureArrayStorageSlow(vm); + SparseArrayValueMap* map = allocateSparseIndexMap(vm); map->putEntry(exec, this, i, value, false); ASSERT(i >= arrayStorage()->length()); arrayStorage()->setLength(i + 1); return; } - ensureLength(globalData, i + 1); + ensureLength(vm, i + 1); - ASSERT(i < m_butterfly->vectorLength()); + RELEASE_ASSERT(i < m_butterfly->vectorLength()); switch (indexingShape) { case Int32Shape: ASSERT(value.isInt32()); @@ -1914,7 +1900,7 @@ void JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, un } case ContiguousShape: - m_butterfly->contiguous()[i].set(globalData, this, value); + m_butterfly->contiguous()[i].set(vm, this, value); break; default: @@ -1924,7 +1910,7 @@ void JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, un void JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, bool shouldThrow, ArrayStorage* storage) { - JSGlobalData& globalData = exec->globalData(); + VM& vm = exec->vm(); // i should be a valid array index that is outside of the current vector. ASSERT(i <= MAX_ARRAY_INDEX); @@ -1942,15 +1928,15 @@ void JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, uns storage->setLength(i + 1); // Check that it is sensible to still be using a vector, and then try to grow the vector. - if (LIKELY((isDenseEnoughForVector(i, storage->m_numValuesInVector)) && increaseVectorLength(globalData, i + 1))) { + if (LIKELY((isDenseEnoughForVector(i, storage->m_numValuesInVector)) && increaseVectorLength(vm, i + 1))) { // success! - reread m_storage since it has likely been reallocated, and store to the vector. storage = arrayStorage(); - storage->m_vector[i].set(globalData, this, value); + storage->m_vector[i].set(vm, this, value); ++storage->m_numValuesInVector; return; } // We don't want to, or can't use a vector to hold this property - allocate a sparse map & add the value. - map = allocateSparseIndexMap(exec->globalData()); + map = allocateSparseIndexMap(exec->vm()); map->putEntry(exec, this, i, value, shouldThrow); return; } @@ -1971,7 +1957,7 @@ void JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, uns // We are currently using a map - check whether we still want to be doing so. // We will continue to use a sparse map if SparseMode is set, a vector would be too sparse, or if allocation fails. unsigned numValuesInArray = storage->m_numValuesInVector + map->size(); - if (map->sparseMode() || !isDenseEnoughForVector(length, numValuesInArray) || !increaseVectorLength(exec->globalData(), length)) { + if (map->sparseMode() || !isDenseEnoughForVector(length, numValuesInArray) || !increaseVectorLength(exec->vm(), length)) { map->putEntry(exec, this, i, value, shouldThrow); return; } @@ -1984,19 +1970,19 @@ void JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, uns WriteBarrier<Unknown>* vector = storage->m_vector; SparseArrayValueMap::const_iterator end = map->end(); for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) - vector[it->key].set(globalData, this, it->value.getNonSparseMode()); + vector[it->key].set(vm, this, it->value.getNonSparseMode()); deallocateSparseIndexMap(); // Store the new property into the vector. WriteBarrier<Unknown>& valueSlot = vector[i]; if (!valueSlot) ++storage->m_numValuesInVector; - valueSlot.set(globalData, this, value); + valueSlot.set(vm, this, value); } void JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue value, bool shouldThrow) { - JSGlobalData& globalData = exec->globalData(); + VM& vm = exec->vm(); // i should be a valid array index that is outside of the current vector. ASSERT(i <= MAX_ARRAY_INDEX); @@ -2006,22 +1992,22 @@ void JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue if (indexingShouldBeSparse()) { putByIndexBeyondVectorLengthWithArrayStorage( exec, i, value, shouldThrow, - ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData)); + ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm)); break; } if (i >= MIN_SPARSE_ARRAY_INDEX) { putByIndexBeyondVectorLengthWithArrayStorage( - exec, i, value, shouldThrow, createArrayStorage(globalData, 0, 0)); + exec, i, value, shouldThrow, createArrayStorage(vm, 0, 0)); break; } if (structure()->needsSlowPutIndexing()) { - ArrayStorage* storage = createArrayStorage(globalData, i + 1, getNewVectorLength(0, 0, i + 1)); - storage->m_vector[i].set(globalData, this, value); + ArrayStorage* storage = createArrayStorage(vm, i + 1, getNewVectorLength(0, 0, i + 1)); + storage->m_vector[i].set(vm, this, value); storage->m_numValuesInVector++; break; } - createInitialContiguous(globalData, i + 1)[i].set(globalData, this, value); + createInitialContiguous(vm, i + 1)[i].set(vm, this, value); break; } @@ -2060,13 +2046,13 @@ void JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue break; default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } } bool JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, unsigned attributes, PutDirectIndexMode mode, ArrayStorage* storage) { - JSGlobalData& globalData = exec->globalData(); + VM& vm = exec->vm(); // i should be a valid array index that is outside of the current vector. ASSERT(hasArrayStorage(structure()->indexingType())); @@ -2089,15 +2075,15 @@ bool JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, if (LIKELY( !attributes && (isDenseEnoughForVector(i, storage->m_numValuesInVector)) - && increaseVectorLength(globalData, i + 1))) { + && increaseVectorLength(vm, i + 1))) { // success! - reread m_storage since it has likely been reallocated, and store to the vector. storage = arrayStorage(); - storage->m_vector[i].set(globalData, this, value); + storage->m_vector[i].set(vm, this, value); ++storage->m_numValuesInVector; return true; } // We don't want to, or can't use a vector to hold this property - allocate a sparse map & add the value. - map = allocateSparseIndexMap(exec->globalData()); + map = allocateSparseIndexMap(exec->vm()); return map->putDirect(exec, this, i, value, attributes, mode); } @@ -2118,7 +2104,7 @@ bool JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, // We are currently using a map - check whether we still want to be doing so. // We will continue to use a sparse map if SparseMode is set, a vector would be too sparse, or if allocation fails. unsigned numValuesInArray = storage->m_numValuesInVector + map->size(); - if (map->sparseMode() || attributes || !isDenseEnoughForVector(length, numValuesInArray) || !increaseVectorLength(exec->globalData(), length)) + if (map->sparseMode() || attributes || !isDenseEnoughForVector(length, numValuesInArray) || !increaseVectorLength(exec->vm(), length)) return map->putDirect(exec, this, i, value, attributes, mode); // Reread m_storage after increaseVectorLength, update m_numValuesInVector. @@ -2129,51 +2115,51 @@ bool JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, WriteBarrier<Unknown>* vector = storage->m_vector; SparseArrayValueMap::const_iterator end = map->end(); for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) - vector[it->key].set(globalData, this, it->value.getNonSparseMode()); + vector[it->key].set(vm, this, it->value.getNonSparseMode()); deallocateSparseIndexMap(); // Store the new property into the vector. WriteBarrier<Unknown>& valueSlot = vector[i]; if (!valueSlot) ++storage->m_numValuesInVector; - valueSlot.set(globalData, this, value); + valueSlot.set(vm, this, value); return true; } bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue value, unsigned attributes, PutDirectIndexMode mode) { - JSGlobalData& globalData = exec->globalData(); + VM& vm = exec->vm(); // i should be a valid array index that is outside of the current vector. ASSERT(i <= MAX_ARRAY_INDEX); if (attributes & (ReadOnly | Accessor)) - notifyPresenceOfIndexedAccessors(globalData); + notifyPresenceOfIndexedAccessors(vm); switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: { if (indexingShouldBeSparse() || attributes) { return putDirectIndexBeyondVectorLengthWithArrayStorage( exec, i, value, attributes, mode, - ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData)); + ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm)); } if (i >= MIN_SPARSE_ARRAY_INDEX) { return putDirectIndexBeyondVectorLengthWithArrayStorage( - exec, i, value, attributes, mode, createArrayStorage(globalData, 0, 0)); + exec, i, value, attributes, mode, createArrayStorage(vm, 0, 0)); } if (structure()->needsSlowPutIndexing()) { - ArrayStorage* storage = createArrayStorage(globalData, i + 1, getNewVectorLength(0, 0, i + 1)); - storage->m_vector[i].set(globalData, this, value); + ArrayStorage* storage = createArrayStorage(vm, i + 1, getNewVectorLength(0, 0, i + 1)); + storage->m_vector[i].set(vm, this, value); storage->m_numValuesInVector++; return true; } - createInitialContiguous(globalData, i + 1)[i].set(globalData, this, value); + createInitialContiguous(vm, i + 1)[i].set(vm, this, value); return true; } case ALL_UNDECIDED_INDEXING_TYPES: { - convertUndecidedForValue(exec->globalData(), value); + convertUndecidedForValue(exec->vm(), value); // Reloop. return putDirectIndex(exec, i, value, attributes, mode); } @@ -2181,10 +2167,10 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV case ALL_INT32_INDEXING_TYPES: { if (attributes & (ReadOnly | Accessor)) { return putDirectIndexBeyondVectorLengthWithArrayStorage( - exec, i, value, attributes, mode, convertInt32ToArrayStorage(globalData)); + exec, i, value, attributes, mode, convertInt32ToArrayStorage(vm)); } if (!value.isInt32()) { - convertInt32ForValue(globalData, value); + convertInt32ForValue(vm, value); return putDirectIndexBeyondVectorLength(exec, i, value, attributes, mode); } putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, i, value); @@ -2194,15 +2180,15 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV case ALL_DOUBLE_INDEXING_TYPES: { if (attributes & (ReadOnly | Accessor)) { return putDirectIndexBeyondVectorLengthWithArrayStorage( - exec, i, value, attributes, mode, convertDoubleToArrayStorage(globalData)); + exec, i, value, attributes, mode, convertDoubleToArrayStorage(vm)); } if (!value.isNumber()) { - convertDoubleToContiguous(globalData); + convertDoubleToContiguous(vm); return putDirectIndexBeyondVectorLength(exec, i, value, attributes, mode); } double valueAsDouble = value.asNumber(); if (valueAsDouble != valueAsDouble) { - convertDoubleToContiguous(globalData); + convertDoubleToContiguous(vm); return putDirectIndexBeyondVectorLength(exec, i, value, attributes, mode); } putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, i, value); @@ -2212,7 +2198,7 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV case ALL_CONTIGUOUS_INDEXING_TYPES: { if (attributes & (ReadOnly | Accessor)) { return putDirectIndexBeyondVectorLengthWithArrayStorage( - exec, i, value, attributes, mode, convertContiguousToArrayStorage(globalData)); + exec, i, value, attributes, mode, convertContiguousToArrayStorage(vm)); } putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, i, value); return true; @@ -2222,11 +2208,21 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, arrayStorage()); default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return false; } } +void JSObject::putDirectNativeFunction(ExecState* exec, JSGlobalObject* globalObject, const PropertyName& propertyName, unsigned functionLength, NativeFunction nativeFunction, Intrinsic intrinsic, unsigned attributes) +{ + StringImpl* name = propertyName.publicName(); + ASSERT(name); + + JSFunction* function = + JSFunction::create(exec, globalObject, functionLength, name, nativeFunction, intrinsic); + putDirect(exec->vm(), propertyName, function, attributes); +} + ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned currentVectorLength, unsigned currentLength, unsigned desiredLength) { ASSERT(desiredLength <= MAX_STORAGE_VECTOR_LENGTH); @@ -2313,7 +2309,7 @@ unsigned JSObject::countElements() } } -bool JSObject::increaseVectorLength(JSGlobalData& globalData, unsigned newLength) +bool JSObject::increaseVectorLength(VM& vm, unsigned newLength) { // This function leaves the array in an internally inconsistent state, because it does not move any values from sparse value map // to the vector. Callers have to account for that, because they can do it more efficiently. @@ -2333,7 +2329,7 @@ bool JSObject::increaseVectorLength(JSGlobalData& globalData, unsigned newLength // Fast case - there is no precapacity. In these cases a realloc makes sense. if (LIKELY(!indexBias)) { - Butterfly* newButterfly = storage->butterfly()->growArrayRight(globalData, structure(), structure()->outOfLineCapacity(), true, ArrayStorage::sizeFor(vectorLength), ArrayStorage::sizeFor(newVectorLength)); + Butterfly* newButterfly = storage->butterfly()->growArrayRight(vm, structure(), structure()->outOfLineCapacity(), true, ArrayStorage::sizeFor(vectorLength), ArrayStorage::sizeFor(newVectorLength)); if (!newButterfly) return false; m_butterfly = newButterfly; @@ -2344,7 +2340,7 @@ bool JSObject::increaseVectorLength(JSGlobalData& globalData, unsigned newLength // Remove some, but not all of the precapacity. Atomic decay, & capped to not overflow array length. unsigned newIndexBias = std::min(indexBias >> 1, MAX_STORAGE_VECTOR_LENGTH - newVectorLength); Butterfly* newButterfly = storage->butterfly()->resizeArray( - globalData, + vm, structure()->outOfLineCapacity(), true, ArrayStorage::sizeFor(vectorLength), newIndexBias, true, ArrayStorage::sizeFor(newVectorLength)); if (!newButterfly) @@ -2356,7 +2352,7 @@ bool JSObject::increaseVectorLength(JSGlobalData& globalData, unsigned newLength return true; } -void JSObject::ensureLengthSlow(JSGlobalData& globalData, unsigned length) +void JSObject::ensureLengthSlow(VM& vm, unsigned length) { ASSERT(length < MAX_ARRAY_INDEX); ASSERT(hasContiguous(structure()->indexingType()) || hasInt32(structure()->indexingType()) || hasDouble(structure()->indexingType()) || hasUndecided(structure()->indexingType())); @@ -2367,33 +2363,33 @@ void JSObject::ensureLengthSlow(JSGlobalData& globalData, unsigned length) MAX_STORAGE_VECTOR_LENGTH); unsigned oldVectorLength = m_butterfly->vectorLength(); m_butterfly = m_butterfly->growArrayRight( - globalData, structure(), structure()->outOfLineCapacity(), true, + vm, structure(), structure()->outOfLineCapacity(), true, oldVectorLength * sizeof(EncodedJSValue), newVectorLength * sizeof(EncodedJSValue)); if (hasDouble(structure()->indexingType())) { for (unsigned i = oldVectorLength; i < newVectorLength; ++i) - m_butterfly->contiguousDouble()[i] = QNaN; + m_butterfly->contiguousDouble().data()[i] = QNaN; } m_butterfly->setVectorLength(newVectorLength); } -Butterfly* JSObject::growOutOfLineStorage(JSGlobalData& globalData, size_t oldSize, size_t newSize) +Butterfly* JSObject::growOutOfLineStorage(VM& vm, size_t oldSize, size_t newSize) { ASSERT(newSize > oldSize); // It's important that this function not rely on structure(), for the property // capacity, since we might have already mutated the structure in-place. - return m_butterfly->growPropertyStorage(globalData, structure(), oldSize, newSize); + return m_butterfly->growPropertyStorage(vm, structure(), oldSize, newSize); } bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor) { unsigned attributes = 0; JSCell* cell = 0; - PropertyOffset offset = object->structure()->get(exec->globalData(), propertyName, attributes, cell); + PropertyOffset offset = object->structure()->get(exec->vm(), propertyName, attributes, cell); if (isValidOffset(offset)) { - descriptor.setDescriptor(object->getDirectOffset(offset), attributes); + descriptor.setDescriptor(object->getDirect(offset), attributes); return true; } @@ -2451,7 +2447,7 @@ bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Prope } default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return false; } } @@ -2475,9 +2471,9 @@ static bool putDescriptor(ExecState* exec, JSObject* target, PropertyName proper if (descriptor.isGenericDescriptor() && oldDescriptor.isAccessorDescriptor()) { GetterSetter* accessor = GetterSetter::create(exec); if (oldDescriptor.getterPresent()) - accessor->setGetter(exec->globalData(), oldDescriptor.getterObject()); + accessor->setGetter(exec->vm(), oldDescriptor.getterObject()); if (oldDescriptor.setterPresent()) - accessor->setSetter(exec->globalData(), oldDescriptor.setterObject()); + accessor->setSetter(exec->vm(), oldDescriptor.setterObject()); target->putDirectAccessor(exec, propertyName, accessor, attributes | Accessor); return true; } @@ -2486,7 +2482,7 @@ static bool putDescriptor(ExecState* exec, JSObject* target, PropertyName proper newValue = descriptor.value(); else if (oldDescriptor.value()) newValue = oldDescriptor.value(); - target->putDirect(exec->globalData(), propertyName, newValue, attributes & ~Accessor); + target->putDirect(exec->vm(), propertyName, newValue, attributes & ~Accessor); if (attributes & ReadOnly) target->structure()->setContainsReadOnlyProperties(); return true; @@ -2495,13 +2491,13 @@ static bool putDescriptor(ExecState* exec, JSObject* target, PropertyName proper GetterSetter* accessor = GetterSetter::create(exec); if (descriptor.getterPresent()) - accessor->setGetter(exec->globalData(), descriptor.getterObject()); + accessor->setGetter(exec->vm(), descriptor.getterObject()); else if (oldDescriptor.getterPresent()) - accessor->setGetter(exec->globalData(), oldDescriptor.getterObject()); + accessor->setGetter(exec->vm(), oldDescriptor.getterObject()); if (descriptor.setterPresent()) - accessor->setSetter(exec->globalData(), descriptor.setterObject()); + accessor->setSetter(exec->vm(), descriptor.setterObject()); else if (oldDescriptor.setterPresent()) - accessor->setSetter(exec->globalData(), oldDescriptor.setterObject()); + accessor->setSetter(exec->vm(), oldDescriptor.setterObject()); target->putDirectAccessor(exec, propertyName, accessor, attributes | Accessor); return true; @@ -2511,7 +2507,7 @@ void JSObject::putDirectMayBeIndex(ExecState* exec, PropertyName propertyName, J { unsigned asIndex = propertyName.asIndex(); if (asIndex == PropertyName::NotAnIndex) - putDirect(exec->globalData(), propertyName, value); + putDirect(exec->vm(), propertyName, value); else putDirectIndex(exec, asIndex, value); } @@ -2519,18 +2515,18 @@ void JSObject::putDirectMayBeIndex(ExecState* exec, PropertyName propertyName, J class DefineOwnPropertyScope { public: DefineOwnPropertyScope(ExecState* exec) - : m_globalData(exec->globalData()) + : m_vm(exec->vm()) { - m_globalData.setInDefineOwnProperty(true); + m_vm.setInDefineOwnProperty(true); } ~DefineOwnPropertyScope() { - m_globalData.setInDefineOwnProperty(false); + m_vm.setInDefineOwnProperty(false); } private: - JSGlobalData& m_globalData; + VM& m_vm; }; bool JSObject::defineOwnNonIndexProperty(ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor, bool throwException) @@ -2631,14 +2627,14 @@ bool JSObject::defineOwnNonIndexProperty(ExecState* exec, PropertyName propertyN return false; } } - JSValue accessor = getDirect(exec->globalData(), propertyName); + JSValue accessor = getDirect(exec->vm(), propertyName); if (!accessor) return false; GetterSetter* getterSetter = asGetterSetter(accessor); if (descriptor.setterPresent()) - getterSetter->setSetter(exec->globalData(), descriptor.setterObject()); + getterSetter->setSetter(exec->vm(), descriptor.setterObject()); if (descriptor.getterPresent()) - getterSetter->setGetter(exec->globalData(), descriptor.getterObject()); + getterSetter->setGetter(exec->vm(), descriptor.getterObject()); if (current.attributesEqual(descriptor)) return true; methodTable()->deleteProperty(this, exec, propertyName); diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h index 428e51f3c..c62dc2aec 100644 --- a/Source/JavaScriptCore/runtime/JSObject.h +++ b/Source/JavaScriptCore/runtime/JSObject.h @@ -37,7 +37,7 @@ #include "PutPropertySlot.h" #include "Structure.h" -#include "JSGlobalData.h" +#include "VM.h" #include "JSString.h" #include "SlotVisitorInlines.h" #include "SparseArrayValueMap.h" @@ -121,16 +121,8 @@ public: JS_EXPORT_PRIVATE static String className(const JSObject*); JSValue prototype() const; - void setPrototype(JSGlobalData&, JSValue prototype); - bool setPrototypeWithCycleCheck(JSGlobalData&, JSValue prototype); - - Structure* inheritorID(JSGlobalData&); - void notifyUsedAsPrototype(JSGlobalData&); - - bool mayBeUsedAsPrototype(JSGlobalData& globalData) - { - return isValidOffset(structure()->get(globalData, globalData.m_inheritorIDKey)); - } + void setPrototype(VM&, JSValue prototype); + bool setPrototypeWithCycleCheck(VM&, JSValue prototype); bool mayInterceptIndexedAccesses() { @@ -170,7 +162,7 @@ public: void putByIndexInline(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow) { if (canSetIndexQuickly(propertyName)) { - setIndexQuickly(exec->globalData(), propertyName, value); + setIndexQuickly(exec->vm(), propertyName, value); return; } methodTable()->putByIndex(this, exec, propertyName, value, shouldThrow); @@ -184,7 +176,7 @@ public: bool putDirectIndex(ExecState* exec, unsigned propertyName, JSValue value, unsigned attributes, PutDirectIndexMode mode) { if (!attributes && canSetIndexQuicklyForPutDirect(propertyName)) { - setIndexQuickly(exec->globalData(), propertyName, value); + setIndexQuickly(exec->vm(), propertyName, value); return true; } return putDirectIndexBeyondVectorLength(exec, propertyName, value, attributes, mode); @@ -217,7 +209,7 @@ public: case ALL_ARRAY_STORAGE_INDEXING_TYPES: return i < m_butterfly->arrayStorage()->vectorLength() && m_butterfly->arrayStorage()->m_vector[i]; default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return false; } } @@ -233,7 +225,7 @@ public: case ALL_ARRAY_STORAGE_INDEXING_TYPES: return m_butterfly->arrayStorage()->m_vector[i].get(); default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return JSValue(); } } @@ -262,7 +254,7 @@ public: return m_butterfly->arrayStorage()->m_vector[i].get(); break; default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); break; } return JSValue(); @@ -302,7 +294,7 @@ public: return i < m_butterfly->arrayStorage()->vectorLength() && !!m_butterfly->arrayStorage()->m_vector[i]; default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return false; } } @@ -319,25 +311,25 @@ public: case ALL_ARRAY_STORAGE_INDEXING_TYPES: return i < m_butterfly->vectorLength(); default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return false; } } - void setIndexQuickly(JSGlobalData& globalData, unsigned i, JSValue v) + void setIndexQuickly(VM& vm, unsigned i, JSValue v) { switch (structure()->indexingType()) { case ALL_INT32_INDEXING_TYPES: { ASSERT(i < m_butterfly->vectorLength()); if (!v.isInt32()) { - convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(globalData, i, v); + convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(vm, i, v); return; } // Fall through to contiguous case. } case ALL_CONTIGUOUS_INDEXING_TYPES: { ASSERT(i < m_butterfly->vectorLength()); - m_butterfly->contiguous()[i].set(globalData, this, v); + m_butterfly->contiguous()[i].set(vm, this, v); if (i >= m_butterfly->publicLength()) m_butterfly->setPublicLength(i + 1); break; @@ -345,12 +337,12 @@ public: case ALL_DOUBLE_INDEXING_TYPES: { ASSERT(i < m_butterfly->vectorLength()); if (!v.isNumber()) { - convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v); + convertDoubleToContiguousWhilePerformingSetIndex(vm, i, v); return; } double value = v.asNumber(); if (value != value) { - convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v); + convertDoubleToContiguousWhilePerformingSetIndex(vm, i, v); return; } m_butterfly->contiguousDouble()[i] = value; @@ -362,7 +354,7 @@ public: ArrayStorage* storage = m_butterfly->arrayStorage(); WriteBarrier<Unknown>& x = storage->m_vector[i]; JSValue old = x.get(); - x.set(globalData, this, v); + x.set(vm, this, v); if (!old) { ++storage->m_numValuesInVector; if (i >= storage->length()) @@ -371,22 +363,22 @@ public: break; } default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } } - void initializeIndex(JSGlobalData& globalData, unsigned i, JSValue v) + void initializeIndex(VM& vm, unsigned i, JSValue v) { switch (structure()->indexingType()) { case ALL_UNDECIDED_INDEXING_TYPES: { - setIndexQuicklyToUndecided(globalData, i, v); + setIndexQuicklyToUndecided(vm, i, v); break; } case ALL_INT32_INDEXING_TYPES: { ASSERT(i < m_butterfly->publicLength()); ASSERT(i < m_butterfly->vectorLength()); if (!v.isInt32()) { - convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(globalData, i, v); + convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(vm, i, v); break; } // Fall through. @@ -394,19 +386,19 @@ public: case ALL_CONTIGUOUS_INDEXING_TYPES: { ASSERT(i < m_butterfly->publicLength()); ASSERT(i < m_butterfly->vectorLength()); - m_butterfly->contiguous()[i].set(globalData, this, v); + m_butterfly->contiguous()[i].set(vm, this, v); break; } case ALL_DOUBLE_INDEXING_TYPES: { ASSERT(i < m_butterfly->publicLength()); ASSERT(i < m_butterfly->vectorLength()); if (!v.isNumber()) { - convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v); + convertDoubleToContiguousWhilePerformingSetIndex(vm, i, v); return; } double value = v.asNumber(); if (value != value) { - convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v); + convertDoubleToContiguousWhilePerformingSetIndex(vm, i, v); return; } m_butterfly->contiguousDouble()[i] = value; @@ -416,11 +408,11 @@ public: ArrayStorage* storage = m_butterfly->arrayStorage(); ASSERT(i < storage->length()); ASSERT(i < storage->m_numValuesInVector); - storage->m_vector[i].set(globalData, this, v); + storage->m_vector[i].set(vm, this, v); break; } default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } } @@ -436,7 +428,7 @@ public: case ALL_ARRAY_STORAGE_INDEXING_TYPES: return m_butterfly->arrayStorage()->m_sparseMap; default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return false; } } @@ -453,12 +445,12 @@ public: case ALL_ARRAY_STORAGE_INDEXING_TYPES: return m_butterfly->arrayStorage()->inSparseMode(); default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return false; } } - void enterDictionaryIndexingMode(JSGlobalData&); + void enterDictionaryIndexingMode(VM&); // putDirect is effectively an unchecked vesion of 'defineOwnProperty': // - the prototype chain is not consulted @@ -466,9 +458,9 @@ public: // - attributes will be respected (after the call the property will exist with the given attributes) // - the property name is assumed to not be an index. JS_EXPORT_PRIVATE static void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes); - void putDirect(JSGlobalData&, PropertyName, JSValue, unsigned attributes = 0); - void putDirect(JSGlobalData&, PropertyName, JSValue, PutPropertySlot&); - void putDirectWithoutTransition(JSGlobalData&, PropertyName, JSValue, unsigned attributes = 0); + void putDirect(VM&, PropertyName, JSValue, unsigned attributes = 0); + void putDirect(VM&, PropertyName, JSValue, PutPropertySlot&); + void putDirectWithoutTransition(VM&, PropertyName, JSValue, unsigned attributes = 0); void putDirectAccessor(ExecState*, PropertyName, JSValue, unsigned attributes); bool propertyIsEnumerable(ExecState*, const Identifier& propertyName) const; @@ -501,25 +493,18 @@ public: bool getPropertySpecificValue(ExecState*, PropertyName, JSCell*& specificFunction) const; // This get function only looks at the property map. - JSValue getDirect(JSGlobalData& globalData, PropertyName propertyName) const + JSValue getDirect(VM& vm, PropertyName propertyName) const { - PropertyOffset offset = structure()->get(globalData, propertyName); - checkOffset(offset, structure()->typeInfo().type()); - return offset != invalidOffset ? getDirectOffset(offset) : JSValue(); + PropertyOffset offset = structure()->get(vm, propertyName); + checkOffset(offset, structure()->inlineCapacity()); + return offset != invalidOffset ? getDirect(offset) : JSValue(); } - WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, PropertyName propertyName) + PropertyOffset getDirectOffset(VM& vm, PropertyName propertyName) { - PropertyOffset offset = structure()->get(globalData, propertyName); - checkOffset(offset, structure()->typeInfo().type()); - return isValidOffset(offset) ? locationForOffset(offset) : 0; - } - - WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, PropertyName propertyName, unsigned& attributes) - { - JSCell* specificFunction; - PropertyOffset offset = structure()->get(globalData, propertyName, attributes, specificFunction); - return isValidOffset(offset) ? locationForOffset(offset) : 0; + PropertyOffset offset = structure()->get(vm, propertyName); + checkOffset(offset, structure()->inlineCapacity()); + return offset; } bool hasInlineStorage() const { return structure()->hasInlineStorage(); } @@ -562,21 +547,9 @@ public: return &outOfLineStorage()[offsetInOutOfLineStorage(offset)]; } - PropertyOffset offsetForLocation(WriteBarrierBase<Unknown>* location) const - { - PropertyOffset result; - size_t offsetInInlineStorage = location - inlineStorageUnsafe(); - if (offsetInInlineStorage < static_cast<size_t>(firstOutOfLineOffset)) - result = offsetInInlineStorage; - else - result = outOfLineStorage() - location + (firstOutOfLineOffset - 1); - validateOffset(result, structure()->typeInfo().type()); - return result; - } + void transitionTo(VM&, Structure*); - void transitionTo(JSGlobalData&, Structure*); - - bool removeDirect(JSGlobalData&, PropertyName); // Return true if anything is removed. + bool removeDirect(VM&, PropertyName); // Return true if anything is removed. bool hasCustomProperties() { return structure()->didTransition(); } bool hasGetterSetterProperties() { return structure()->hasGetterSetterProperties(); } @@ -585,26 +558,29 @@ public: // - provides no special handling for __proto__ // - does not walk the prototype chain (to check for accessors or non-writable properties). // This is used by JSActivation. - bool putOwnDataProperty(JSGlobalData&, PropertyName, JSValue, PutPropertySlot&); + bool putOwnDataProperty(VM&, PropertyName, JSValue, PutPropertySlot&); // Fast access to known property offsets. - JSValue getDirectOffset(PropertyOffset offset) const { return locationForOffset(offset)->get(); } - void putDirectOffset(JSGlobalData& globalData, PropertyOffset offset, JSValue value) { locationForOffset(offset)->set(globalData, this, value); } - void putUndefinedAtDirectOffset(PropertyOffset offset) { locationForOffset(offset)->setUndefined(); } + JSValue getDirect(PropertyOffset offset) const { return locationForOffset(offset)->get(); } + void putDirect(VM& vm, PropertyOffset offset, JSValue value) { locationForOffset(offset)->set(vm, this, value); } + void putDirectUndefined(PropertyOffset offset) { locationForOffset(offset)->setUndefined(); } + + void putDirectNativeFunction(ExecState*, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, unsigned attributes); JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow); bool isGlobalObject() const; bool isVariableObject() const; + bool isStaticScopeObject() const; bool isNameScopeObject() const; bool isActivationObject() const; bool isErrorInstance() const; - void seal(JSGlobalData&); - void freeze(JSGlobalData&); - JS_EXPORT_PRIVATE void preventExtensions(JSGlobalData&); - bool isSealed(JSGlobalData& globalData) { return structure()->isSealed(globalData); } - bool isFrozen(JSGlobalData& globalData) { return structure()->isFrozen(globalData); } + void seal(VM&); + void freeze(VM&); + JS_EXPORT_PRIVATE void preventExtensions(VM&); + bool isSealed(VM& vm) { return structure()->isSealed(vm); } + bool isFrozen(VM& vm) { return structure()->isFrozen(vm); } bool isExtensible() { return structure()->isExtensible(); } bool indexingShouldBeSparse() { @@ -615,16 +591,16 @@ public: bool staticFunctionsReified() { return structure()->staticFunctionsReified(); } void reifyStaticFunctionsForDelete(ExecState* exec); - JS_EXPORT_PRIVATE Butterfly* growOutOfLineStorage(JSGlobalData&, size_t oldSize, size_t newSize); - void setButterfly(JSGlobalData&, Butterfly*, Structure*); + JS_EXPORT_PRIVATE Butterfly* growOutOfLineStorage(VM&, size_t oldSize, size_t newSize); + void setButterfly(VM&, Butterfly*, Structure*); void setButterflyWithoutChangingStructure(Butterfly*); // You probably don't want to call this. - void setStructureAndReallocateStorageIfNecessary(JSGlobalData&, unsigned oldCapacity, Structure*); - void setStructureAndReallocateStorageIfNecessary(JSGlobalData&, Structure*); + void setStructureAndReallocateStorageIfNecessary(VM&, unsigned oldCapacity, Structure*); + void setStructureAndReallocateStorageIfNecessary(VM&, Structure*); - void flattenDictionaryObject(JSGlobalData& globalData) + void flattenDictionaryObject(VM& vm) { - structure()->flattenDictionaryStructure(globalData, this); + structure()->flattenDictionaryStructure(vm, this); } JSGlobalObject* globalObject() const @@ -634,7 +610,7 @@ public: return structure()->globalObject(); } - void switchToSlowPutArrayStorage(JSGlobalData&); + void switchToSlowPutArrayStorage(VM&); // The receiver is the prototype in this case. The following: // @@ -649,46 +625,57 @@ public: // indexing should be sparse, we're having a bad time, or because // we already have a more general form of storage (double, // contiguous, array storage). - WriteBarrier<Unknown>* ensureInt32(JSGlobalData& globalData) + ContiguousJSValues ensureInt32(VM& vm) { if (LIKELY(hasInt32(structure()->indexingType()))) return m_butterfly->contiguousInt32(); - return ensureInt32Slow(globalData); + return ensureInt32Slow(vm); } // Returns 0 if double storage cannot be created - either because // indexing should be sparse, we're having a bad time, or because // we already have a more general form of storage (contiguous, // or array storage). - double* ensureDouble(JSGlobalData& globalData) + ContiguousDoubles ensureDouble(VM& vm) { if (LIKELY(hasDouble(structure()->indexingType()))) return m_butterfly->contiguousDouble(); - return ensureDoubleSlow(globalData); + return ensureDoubleSlow(vm); } // Returns 0 if contiguous storage cannot be created - either because // indexing should be sparse or because we're having a bad time. - WriteBarrier<Unknown>* ensureContiguous(JSGlobalData& globalData) + ContiguousJSValues ensureContiguous(VM& vm) { if (LIKELY(hasContiguous(structure()->indexingType()))) return m_butterfly->contiguous(); - return ensureContiguousSlow(globalData); + return ensureContiguousSlow(vm); + } + + // Same as ensureContiguous(), except that if the indexed storage is in + // double mode, then it does a rage conversion to contiguous: it + // attempts to convert each double to an int32. + ContiguousJSValues rageEnsureContiguous(VM& vm) + { + if (LIKELY(hasContiguous(structure()->indexingType()))) + return m_butterfly->contiguous(); + + return rageEnsureContiguousSlow(vm); } // Ensure that the object is in a mode where it has array storage. Use // this if you're about to perform actions that would have required the // object to be converted to have array storage, if it didn't have it // already. - ArrayStorage* ensureArrayStorage(JSGlobalData& globalData) + ArrayStorage* ensureArrayStorage(VM& vm) { if (LIKELY(hasArrayStorage(structure()->indexingType()))) return m_butterfly->arrayStorage(); - return ensureArrayStorageSlow(globalData); + return ensureArrayStorageSlow(vm); } static size_t offsetOfInlineStorage(); @@ -706,9 +693,9 @@ public: static JS_EXPORTDATA const ClassInfo s_info; protected: - void finishCreation(JSGlobalData& globalData) + void finishCreation(VM& vm) { - Base::finishCreation(globalData); + Base::finishCreation(vm); ASSERT(inherits(&s_info)); ASSERT(!structure()->outOfLineCapacity()); ASSERT(structure()->isEmpty()); @@ -717,16 +704,14 @@ protected: ASSERT(classInfo()); } - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } // To instantiate objects you likely want JSFinalObject, below. // To create derived types you likely want JSNonFinalObject, below. - JSObject(JSGlobalData&, Structure*, Butterfly* = 0); - - void resetInheritorID(JSGlobalData&); + JSObject(VM&, Structure*, Butterfly* = 0); void visitButterfly(SlotVisitor&, Butterfly*, size_t storageSize); void copyButterfly(CopyVisitor&, Butterfly*, size_t storageSize); @@ -752,41 +737,42 @@ protected: } } - Butterfly* createInitialUndecided(JSGlobalData&, unsigned length); - WriteBarrier<Unknown>* createInitialInt32(JSGlobalData&, unsigned length); - double* createInitialDouble(JSGlobalData&, unsigned length); - WriteBarrier<Unknown>* createInitialContiguous(JSGlobalData&, unsigned length); + Butterfly* createInitialUndecided(VM&, unsigned length); + ContiguousJSValues createInitialInt32(VM&, unsigned length); + ContiguousDoubles createInitialDouble(VM&, unsigned length); + ContiguousJSValues createInitialContiguous(VM&, unsigned length); - void convertUndecidedForValue(JSGlobalData&, JSValue); - void convertInt32ForValue(JSGlobalData&, JSValue); + void convertUndecidedForValue(VM&, JSValue); + void convertInt32ForValue(VM&, JSValue); - ArrayStorage* createArrayStorage(JSGlobalData&, unsigned length, unsigned vectorLength); - ArrayStorage* createInitialArrayStorage(JSGlobalData&); + ArrayStorage* createArrayStorage(VM&, unsigned length, unsigned vectorLength); + ArrayStorage* createInitialArrayStorage(VM&); - WriteBarrier<Unknown>* convertUndecidedToInt32(JSGlobalData&); - double* convertUndecidedToDouble(JSGlobalData&); - WriteBarrier<Unknown>* convertUndecidedToContiguous(JSGlobalData&); - ArrayStorage* convertUndecidedToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength); - ArrayStorage* convertUndecidedToArrayStorage(JSGlobalData&, NonPropertyTransition); - ArrayStorage* convertUndecidedToArrayStorage(JSGlobalData&); + ContiguousJSValues convertUndecidedToInt32(VM&); + ContiguousDoubles convertUndecidedToDouble(VM&); + ContiguousJSValues convertUndecidedToContiguous(VM&); + ArrayStorage* convertUndecidedToArrayStorage(VM&, NonPropertyTransition, unsigned neededLength); + ArrayStorage* convertUndecidedToArrayStorage(VM&, NonPropertyTransition); + ArrayStorage* convertUndecidedToArrayStorage(VM&); - double* convertInt32ToDouble(JSGlobalData&); - WriteBarrier<Unknown>* convertInt32ToContiguous(JSGlobalData&); - ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength); - ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&, NonPropertyTransition); - ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&); - - WriteBarrier<Unknown>* convertDoubleToContiguous(JSGlobalData&); - ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength); - ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&, NonPropertyTransition); - ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&); + ContiguousDoubles convertInt32ToDouble(VM&); + ContiguousJSValues convertInt32ToContiguous(VM&); + ArrayStorage* convertInt32ToArrayStorage(VM&, NonPropertyTransition, unsigned neededLength); + ArrayStorage* convertInt32ToArrayStorage(VM&, NonPropertyTransition); + ArrayStorage* convertInt32ToArrayStorage(VM&); + + ContiguousJSValues convertDoubleToContiguous(VM&); + ContiguousJSValues rageConvertDoubleToContiguous(VM&); + ArrayStorage* convertDoubleToArrayStorage(VM&, NonPropertyTransition, unsigned neededLength); + ArrayStorage* convertDoubleToArrayStorage(VM&, NonPropertyTransition); + ArrayStorage* convertDoubleToArrayStorage(VM&); - ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength); - ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&, NonPropertyTransition); - ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&); + ArrayStorage* convertContiguousToArrayStorage(VM&, NonPropertyTransition, unsigned neededLength); + ArrayStorage* convertContiguousToArrayStorage(VM&, NonPropertyTransition); + ArrayStorage* convertContiguousToArrayStorage(VM&); - ArrayStorage* ensureArrayStorageExistsAndEnterDictionaryIndexingMode(JSGlobalData&); + ArrayStorage* ensureArrayStorageExistsAndEnterDictionaryIndexingMode(VM&); bool defineOwnNonIndexProperty(ExecState*, PropertyName, PropertyDescriptor&, bool throwException); @@ -794,24 +780,24 @@ protected: void putByIndexBeyondVectorLengthWithoutAttributes(ExecState*, unsigned propertyName, JSValue); void putByIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, bool shouldThrow, ArrayStorage*); - bool increaseVectorLength(JSGlobalData&, unsigned newLength); + bool increaseVectorLength(VM&, unsigned newLength); void deallocateSparseIndexMap(); bool defineOwnIndexedProperty(ExecState*, unsigned, PropertyDescriptor&, bool throwException); - SparseArrayValueMap* allocateSparseIndexMap(JSGlobalData&); + SparseArrayValueMap* allocateSparseIndexMap(VM&); - void notifyPresenceOfIndexedAccessors(JSGlobalData&); + void notifyPresenceOfIndexedAccessors(VM&); bool attemptToInterceptPutByIndexOnHole(ExecState*, unsigned index, JSValue, bool shouldThrow); // Call this if you want setIndexQuickly to succeed and you're sure that // the array is contiguous. - void ensureLength(JSGlobalData& globalData, unsigned length) + void ensureLength(VM& vm, unsigned length) { ASSERT(length < MAX_ARRAY_INDEX); ASSERT(hasContiguous(structure()->indexingType()) || hasInt32(structure()->indexingType()) || hasDouble(structure()->indexingType()) || hasUndecided(structure()->indexingType())); if (m_butterfly->vectorLength() < length) - ensureLengthSlow(globalData, length); + ensureLengthSlow(vm, length); if (m_butterfly->publicLength() < length) m_butterfly->setPublicLength(length); @@ -827,7 +813,7 @@ protected: // as if it contained JSValues. But it won't always contain JSValues. // Make sure you cast this to the appropriate type before using. template<IndexingType indexingType> - WriteBarrier<Unknown>* indexingData() + ContiguousJSValues indexingData() { switch (indexingType) { case ALL_INT32_INDEXING_TYPES: @@ -836,15 +822,15 @@ protected: return m_butterfly->contiguous(); case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return m_butterfly->arrayStorage()->m_vector; - + return m_butterfly->arrayStorage()->vector(); + default: CRASH(); - return 0; + return ContiguousJSValues(); } } - WriteBarrier<Unknown>* currentIndexingData() + ContiguousJSValues currentIndexingData() { switch (structure()->indexingType()) { case ALL_INT32_INDEXING_TYPES: @@ -852,11 +838,11 @@ protected: return m_butterfly->contiguous(); case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return m_butterfly->arrayStorage()->m_vector; + return m_butterfly->arrayStorage()->vector(); default: CRASH(); - return 0; + return ContiguousJSValues(); } } @@ -931,18 +917,17 @@ private: void isObject(); void isString(); - Butterfly* createInitialIndexedStorage(JSGlobalData&, unsigned length, size_t elementSize); + Butterfly* createInitialIndexedStorage(VM&, unsigned length, size_t elementSize); - ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(JSGlobalData&, ArrayStorage*); + ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(VM&, ArrayStorage*); template<PutMode> - bool putDirectInternal(JSGlobalData&, PropertyName, JSValue, unsigned attr, PutPropertySlot&, JSCell*); + bool putDirectInternal(VM&, PropertyName, JSValue, unsigned attr, PutPropertySlot&, JSCell*); bool inlineGetOwnPropertySlot(ExecState*, PropertyName, PropertySlot&); JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&, PropertyOffset); const HashEntry* findPropertyHashEntry(ExecState*, PropertyName) const; - Structure* createInheritorID(JSGlobalData&); void putIndexedDescriptor(ExecState*, SparseArrayEntry*, PropertyDescriptor&, PropertyDescriptor& old); @@ -955,24 +940,29 @@ private: JS_EXPORT_PRIVATE bool getOwnPropertySlotSlow(ExecState*, PropertyName, PropertySlot&); - ArrayStorage* constructConvertedArrayStorageWithoutCopyingElements(JSGlobalData&, unsigned neededLength); - - JS_EXPORT_PRIVATE void setIndexQuicklyToUndecided(JSGlobalData&, unsigned index, JSValue); - JS_EXPORT_PRIVATE void convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(JSGlobalData&, unsigned index, JSValue); - JS_EXPORT_PRIVATE void convertDoubleToContiguousWhilePerformingSetIndex(JSGlobalData&, unsigned index, JSValue); + ArrayStorage* constructConvertedArrayStorageWithoutCopyingElements(VM&, unsigned neededLength); - void ensureLengthSlow(JSGlobalData&, unsigned length); + JS_EXPORT_PRIVATE void setIndexQuicklyToUndecided(VM&, unsigned index, JSValue); + JS_EXPORT_PRIVATE void convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(VM&, unsigned index, JSValue); + JS_EXPORT_PRIVATE void convertDoubleToContiguousWhilePerformingSetIndex(VM&, unsigned index, JSValue); - WriteBarrier<Unknown>* ensureInt32Slow(JSGlobalData&); - double* ensureDoubleSlow(JSGlobalData&); - WriteBarrier<Unknown>* ensureContiguousSlow(JSGlobalData&); - ArrayStorage* ensureArrayStorageSlow(JSGlobalData&); + void ensureLengthSlow(VM&, unsigned length); + ContiguousJSValues ensureInt32Slow(VM&); + ContiguousDoubles ensureDoubleSlow(VM&); + ContiguousJSValues ensureContiguousSlow(VM&); + ContiguousJSValues rageEnsureContiguousSlow(VM&); + ArrayStorage* ensureArrayStorageSlow(VM&); + + enum DoubleToContiguousMode { EncodeValueAsDouble, RageConvertDoubleToValue }; + template<DoubleToContiguousMode mode> + ContiguousJSValues genericConvertDoubleToContiguous(VM&); + ContiguousJSValues ensureContiguousSlow(VM&, DoubleToContiguousMode); + protected: Butterfly* m_butterfly; }; - // 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. @@ -982,20 +972,20 @@ class JSNonFinalObject : public JSObject { public: typedef JSObject Base; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } protected: - explicit JSNonFinalObject(JSGlobalData& globalData, Structure* structure, Butterfly* butterfly = 0) - : JSObject(globalData, structure, butterfly) + explicit JSNonFinalObject(VM& vm, Structure* structure, Butterfly* butterfly = 0) + : JSObject(vm, structure, butterfly) { } - void finishCreation(JSGlobalData& globalData) + void finishCreation(VM& vm) { - Base::finishCreation(globalData); + Base::finishCreation(vm); ASSERT(!this->structure()->totalStorageCapacity()); ASSERT(classInfo()); } @@ -1011,10 +1001,22 @@ class JSFinalObject : public JSObject { public: typedef JSObject Base; + static const unsigned defaultSize = 64; + static inline unsigned defaultInlineCapacity() + { + return (defaultSize - allocationSize(0)) / sizeof(WriteBarrier<Unknown>); + } + + static const unsigned maxSize = 512; + static inline unsigned maxInlineCapacity() + { + return (maxSize - allocationSize(0)) / sizeof(WriteBarrier<Unknown>); + } + static JSFinalObject* create(ExecState*, Structure*); - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, unsigned inlineCapacity) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(FinalObjectType, StructureFlags), &s_info, NonArray, INLINE_STORAGE_CAPACITY); + return Structure::create(vm, globalObject, prototype, TypeInfo(FinalObjectType, StructureFlags), &s_info, NonArray, inlineCapacity); } JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); @@ -1024,9 +1026,9 @@ public: protected: void visitChildrenCommon(SlotVisitor&); - void finishCreation(JSGlobalData& globalData) + void finishCreation(VM& vm) { - Base::finishCreation(globalData); + Base::finishCreation(vm); ASSERT(structure()->totalStorageCapacity() == structure()->inlineCapacity()); ASSERT(classInfo()); } @@ -1034,8 +1036,8 @@ protected: private: friend class LLIntOffsetsExtractor; - explicit JSFinalObject(JSGlobalData& globalData, Structure* structure) - : JSObject(globalData, structure) + explicit JSFinalObject(VM& vm, Structure* structure) + : JSObject(vm, structure) { } @@ -1050,8 +1052,8 @@ inline JSFinalObject* JSFinalObject::create(ExecState* exec, Structure* structur *exec->heap(), allocationSize(structure->inlineCapacity()) ) - ) JSFinalObject(exec->globalData(), structure); - finalObject->finishCreation(exec->globalData()); + ) JSFinalObject(exec->vm(), structure); + finalObject->finishCreation(exec->vm()); return finalObject; } @@ -1080,6 +1082,14 @@ inline bool JSObject::isVariableObject() const return structure()->typeInfo().type() >= VariableObjectType; } + +inline bool JSObject::isStaticScopeObject() const +{ + JSType type = structure()->typeInfo().type(); + return type == NameScopeObjectType || type == ActivationObjectType; +} + + inline bool JSObject::isNameScopeObject() const { return structure()->typeInfo().type() == NameScopeObjectType; @@ -1095,11 +1105,11 @@ inline bool JSObject::isErrorInstance() const return structure()->typeInfo().type() == ErrorInstanceType; } -inline void JSObject::setButterfly(JSGlobalData& globalData, Butterfly* butterfly, Structure* structure) +inline void JSObject::setButterfly(VM& vm, Butterfly* butterfly, Structure* structure) { ASSERT(structure); ASSERT(!butterfly == (!structure->outOfLineCapacity() && !hasIndexingHeader(structure->indexingType()))); - setStructure(globalData, structure); + setStructure(vm, structure); m_butterfly = butterfly; } @@ -1108,11 +1118,6 @@ inline void JSObject::setButterflyWithoutChangingStructure(Butterfly* butterfly) m_butterfly = butterfly; } -inline JSObject* constructEmptyObject(ExecState* exec, Structure* structure) -{ - return JSFinalObject::create(exec, structure); -} - inline CallType getCallData(JSValue value, CallData& callData) { CallType result = value.isCell() ? value.asCell()->methodTable()->getCallData(value.asCell(), callData) : CallTypeNone; @@ -1127,11 +1132,6 @@ inline ConstructType getConstructData(JSValue value, ConstructData& constructDat return result; } -inline Structure* createEmptyObjectStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) -{ - return JSFinalObject::createStructure(globalData, globalObject, prototype); -} - inline JSObject* asObject(JSCell* cell) { ASSERT(cell->isObject()); @@ -1143,8 +1143,8 @@ inline JSObject* asObject(JSValue value) return asObject(value.asCell()); } -inline JSObject::JSObject(JSGlobalData& globalData, Structure* structure, Butterfly* butterfly) - : JSCell(globalData, structure) +inline JSObject::JSObject(VM& vm, Structure* structure, Butterfly* butterfly) + : JSCell(vm, structure) , m_butterfly(butterfly) { } @@ -1154,32 +1154,11 @@ inline JSValue JSObject::prototype() const return structure()->storedPrototype(); } -inline const MethodTable* JSCell::methodTable() const -{ - return &classInfo()->methodTable; -} - -inline bool JSCell::inherits(const ClassInfo* info) const -{ - return classInfo()->isSubClassOf(info); -} - -// this method is here to be after the inline declaration of JSCell::inherits -inline bool JSValue::inherits(const ClassInfo* classInfo) const -{ - return isCell() && asCell()->inherits(classInfo); -} - -inline JSObject* JSValue::toThisObject(ExecState* exec) const -{ - return isCell() ? asCell()->methodTable()->toThisObject(asCell(), exec) : toThisObjectSlowCase(exec); -} - ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot) { - PropertyOffset offset = structure()->get(exec->globalData(), propertyName); + PropertyOffset offset = structure()->get(exec->vm(), propertyName); if (LIKELY(isValidOffset(offset))) { - JSValue value = getDirectOffset(offset); + JSValue value = getDirect(offset); if (structure()->hasGetterSetterProperties() && value.isGetterSetter()) fillGetterPropertySlot(slot, offset); else @@ -1198,29 +1177,6 @@ ALWAYS_INLINE bool JSObject::getOwnPropertySlot(JSCell* cell, ExecState* exec, P return jsCast<JSObject*>(cell)->inlineGetOwnPropertySlot(exec, propertyName, slot); } -ALWAYS_INLINE bool JSCell::fastGetOwnPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot) -{ - if (!structure()->typeInfo().overridesGetOwnPropertySlot()) - return asObject(this)->inlineGetOwnPropertySlot(exec, propertyName, slot); - return methodTable()->getOwnPropertySlot(this, exec, propertyName, slot); -} - -// Fast call to get a property where we may not yet have converted the string to an -// identifier. The first time we perform a property access with a given string, try -// performing the property map lookup without forming an identifier. We detect this -// case by checking whether the hash has yet been set for this string. -ALWAYS_INLINE JSValue JSCell::fastGetOwnProperty(ExecState* exec, const String& name) -{ - if (!structure()->typeInfo().overridesGetOwnPropertySlot() && !structure()->hasGetterSetterProperties()) { - PropertyOffset offset = name.impl()->hasHash() - ? structure()->get(exec->globalData(), Identifier(exec, name)) - : structure()->get(exec->globalData(), name); - if (offset != invalidOffset) - return asObject(this)->locationForOffset(offset)->get(); - } - return JSValue(); -} - // It may seem crazy to inline a function this large but it makes a big difference // since this is function very hot in variable lookup ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot) @@ -1268,7 +1224,7 @@ inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const } template<JSObject::PutMode mode> -inline bool JSObject::putDirectInternal(JSGlobalData& globalData, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot, JSCell* specificFunction) +inline bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot, JSCell* specificFunction) { ASSERT(value); ASSERT(value.isGetterSetter() == !!(attributes & Accessor)); @@ -1278,16 +1234,16 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, PropertyName p if (structure()->isDictionary()) { unsigned currentAttributes; JSCell* currentSpecificFunction; - PropertyOffset offset = structure()->get(globalData, propertyName, currentAttributes, currentSpecificFunction); + PropertyOffset offset = structure()->get(vm, propertyName, currentAttributes, currentSpecificFunction); if (offset != invalidOffset) { // 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)) - structure()->despecifyDictionaryFunction(globalData, propertyName); + structure()->despecifyDictionaryFunction(vm, propertyName); if ((mode == PutModePut) && currentAttributes & ReadOnly) return false; - putDirectOffset(globalData, offset, value); + putDirect(vm, offset, value); // At this point, the objects structure only has a specific value set if previously there // had been one set, and if the new value being specified is the same (otherwise we would // have despecified, above). So, if currentSpecificFunction is not set, or if the new @@ -1304,13 +1260,13 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, PropertyName p Butterfly* newButterfly = m_butterfly; if (structure()->putWillGrowOutOfLineStorage()) - newButterfly = growOutOfLineStorage(globalData, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity()); - offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, specificFunction); - setButterfly(globalData, newButterfly, structure()); + newButterfly = growOutOfLineStorage(vm, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity()); + offset = structure()->addPropertyWithoutTransition(vm, propertyName, attributes, specificFunction); + setButterfly(vm, newButterfly, structure()); validateOffset(offset); ASSERT(structure()->isValidOffset(offset)); - putDirectOffset(globalData, offset, value); + putDirect(vm, offset, value); // See comment on setNewProperty call below. if (!specificFunction) slot.setNewProperty(this, offset); @@ -1324,12 +1280,12 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, PropertyName p if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, specificFunction, offset)) { Butterfly* newButterfly = m_butterfly; if (currentCapacity != structure->outOfLineCapacity()) - newButterfly = growOutOfLineStorage(globalData, currentCapacity, structure->outOfLineCapacity()); + newButterfly = growOutOfLineStorage(vm, currentCapacity, structure->outOfLineCapacity()); validateOffset(offset); ASSERT(structure->isValidOffset(offset)); - setButterfly(globalData, newButterfly, structure); - putDirectOffset(globalData, offset, value); + setButterfly(vm, newButterfly, structure); + putDirect(vm, offset, value); // This is a new property; transitions with specific values are not currently cachable, // so leave the slot in an uncachable state. if (!specificFunction) @@ -1339,7 +1295,7 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, PropertyName p unsigned currentAttributes; JSCell* currentSpecificFunction; - offset = structure()->get(globalData, propertyName, currentAttributes, currentSpecificFunction); + offset = structure()->get(vm, propertyName, currentAttributes, currentSpecificFunction); if (offset != invalidOffset) { if ((mode == PutModePut) && currentAttributes & ReadOnly) return false; @@ -1356,29 +1312,29 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, PropertyName p if (currentSpecificFunction) { // case (1) Do the put, then return leaving the slot uncachable. if (specificFunction == currentSpecificFunction) { - putDirectOffset(globalData, offset, value); + putDirect(vm, offset, value); return true; } // case (2) Despecify, fall through to (3). - setStructure(globalData, Structure::despecifyFunctionTransition(globalData, structure(), propertyName)); + setStructure(vm, Structure::despecifyFunctionTransition(vm, structure(), propertyName)); } // case (3) set the slot, do the put, return. slot.setExistingProperty(this, offset); - putDirectOffset(globalData, offset, value); + putDirect(vm, offset, value); return true; } if ((mode == PutModePut) && !isExtensible()) return false; - Structure* structure = Structure::addPropertyTransition(globalData, this->structure(), propertyName, attributes, specificFunction, offset); + Structure* structure = Structure::addPropertyTransition(vm, this->structure(), propertyName, attributes, specificFunction, offset); validateOffset(offset); ASSERT(structure->isValidOffset(offset)); - setStructureAndReallocateStorageIfNecessary(globalData, structure); + setStructureAndReallocateStorageIfNecessary(vm, structure); - putDirectOffset(globalData, offset, value); + putDirect(vm, offset, value); // This is a new property; transitions with specific values are not currently cachable, // so leave the slot in an uncachable state. if (!specificFunction) @@ -1388,57 +1344,57 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, PropertyName p return true; } -inline void JSObject::setStructureAndReallocateStorageIfNecessary(JSGlobalData& globalData, unsigned oldCapacity, Structure* newStructure) +inline void JSObject::setStructureAndReallocateStorageIfNecessary(VM& vm, unsigned oldCapacity, Structure* newStructure) { ASSERT(oldCapacity <= newStructure->outOfLineCapacity()); if (oldCapacity == newStructure->outOfLineCapacity()) { - setStructure(globalData, newStructure); + setStructure(vm, newStructure); return; } Butterfly* newButterfly = growOutOfLineStorage( - globalData, oldCapacity, newStructure->outOfLineCapacity()); - setButterfly(globalData, newButterfly, newStructure); + vm, oldCapacity, newStructure->outOfLineCapacity()); + setButterfly(vm, newButterfly, newStructure); } -inline void JSObject::setStructureAndReallocateStorageIfNecessary(JSGlobalData& globalData, Structure* newStructure) +inline void JSObject::setStructureAndReallocateStorageIfNecessary(VM& vm, Structure* newStructure) { setStructureAndReallocateStorageIfNecessary( - globalData, structure()->outOfLineCapacity(), newStructure); + vm, structure()->outOfLineCapacity(), newStructure); } -inline bool JSObject::putOwnDataProperty(JSGlobalData& globalData, PropertyName propertyName, JSValue value, PutPropertySlot& slot) +inline bool JSObject::putOwnDataProperty(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { ASSERT(value); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); ASSERT(!structure()->hasGetterSetterProperties()); - return putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getCallableObject(value)); + return putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot, getCallableObject(value)); } -inline void JSObject::putDirect(JSGlobalData& globalData, PropertyName propertyName, JSValue value, unsigned attributes) +inline void JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes) { ASSERT(!value.isGetterSetter() && !(attributes & Accessor)); PutPropertySlot slot; - putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, attributes, slot, getCallableObject(value)); + putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot, getCallableObject(value)); } -inline void JSObject::putDirect(JSGlobalData& globalData, PropertyName propertyName, JSValue value, PutPropertySlot& slot) +inline void JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { ASSERT(!value.isGetterSetter()); - putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, 0, slot, getCallableObject(value)); + putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, 0, slot, getCallableObject(value)); } -inline void JSObject::putDirectWithoutTransition(JSGlobalData& globalData, PropertyName propertyName, JSValue value, unsigned attributes) +inline void JSObject::putDirectWithoutTransition(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes) { ASSERT(!value.isGetterSetter() && !(attributes & Accessor)); Butterfly* newButterfly = m_butterfly; if (structure()->putWillGrowOutOfLineStorage()) - newButterfly = growOutOfLineStorage(globalData, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity()); - PropertyOffset offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, getCallableObject(value)); - setButterfly(globalData, newButterfly, structure()); - putDirectOffset(globalData, offset, value); + newButterfly = growOutOfLineStorage(vm, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity()); + PropertyOffset offset = structure()->addPropertyWithoutTransition(vm, propertyName, attributes, getCallableObject(value)); + setButterfly(vm, newButterfly, structure()); + putDirect(vm, offset, value); } inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const @@ -1446,74 +1402,6 @@ inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType pre return methodTable()->defaultValue(this, exec, preferredType); } -inline JSValue JSValue::get(ExecState* exec, PropertyName propertyName) const -{ - PropertySlot slot(asValue()); - return get(exec, propertyName, slot); -} - -inline JSValue JSValue::get(ExecState* exec, PropertyName propertyName, PropertySlot& slot) const -{ - if (UNLIKELY(!isCell())) { - JSObject* prototype = synthesizePrototype(exec); - if (!prototype->getPropertySlot(exec, propertyName, slot)) - return jsUndefined(); - return slot.getValue(exec, propertyName); - } - JSCell* cell = asCell(); - while (true) { - if (cell->fastGetOwnPropertySlot(exec, propertyName, slot)) - return slot.getValue(exec, propertyName); - JSValue prototype = asObject(cell)->prototype(); - if (!prototype.isObject()) - return jsUndefined(); - cell = asObject(prototype); - } -} - -inline JSValue JSValue::get(ExecState* exec, unsigned propertyName) const -{ - PropertySlot slot(asValue()); - return get(exec, propertyName, slot); -} - -inline JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const -{ - if (UNLIKELY(!isCell())) { - JSObject* prototype = synthesizePrototype(exec); - if (!prototype->getPropertySlot(exec, propertyName, slot)) - return jsUndefined(); - return slot.getValue(exec, propertyName); - } - JSCell* cell = const_cast<JSCell*>(asCell()); - while (true) { - if (cell->methodTable()->getOwnPropertySlotByIndex(cell, exec, propertyName, slot)) - return slot.getValue(exec, propertyName); - JSValue prototype = asObject(cell)->prototype(); - if (!prototype.isObject()) - return jsUndefined(); - cell = prototype.asCell(); - } -} - -inline void JSValue::put(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) -{ - if (UNLIKELY(!isCell())) { - putToPrimitive(exec, propertyName, value, slot); - return; - } - asCell()->methodTable()->put(asCell(), exec, propertyName, value, slot); -} - -inline void JSValue::putByIndex(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow) -{ - if (UNLIKELY(!isCell())) { - putToPrimitiveByIndex(exec, propertyName, value, shouldThrow); - return; - } - asCell()->methodTable()->putByIndex(asCell(), exec, propertyName, value, shouldThrow); -} - ALWAYS_INLINE JSObject* Register::function() const { if (!jsValue()) @@ -1533,7 +1421,7 @@ inline size_t offsetInButterfly(PropertyOffset offset) return offsetInOutOfLineStorage(offset) + Butterfly::indexOfPropertyStorage(); } -// This is a helper for patching code where you want to emit a load or store and +// Helpers for patching code where you want to emit a load or store and // the base is: // For inline offsets: a pointer to the out-of-line storage pointer. // For out-of-line offsets: the base of the out-of-line storage. @@ -1544,6 +1432,17 @@ inline size_t offsetRelativeToPatchedStorage(PropertyOffset offset) return JSObject::offsetOfInlineStorage() - JSObject::butterflyOffset() + sizeof(EncodedJSValue) * offsetInInlineStorage(offset); } +// Returns the maximum offset (away from zero) a load instruction will encode. +inline size_t maxOffsetRelativeToPatchedStorage(PropertyOffset offset) +{ + ptrdiff_t addressOffset = static_cast<ptrdiff_t>(offsetRelativeToPatchedStorage(offset)); +#if USE(JSVALUE32_64) + if (addressOffset >= 0) + return static_cast<size_t>(addressOffset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag); +#endif + return static_cast<size_t>(addressOffset); +} + inline int indexRelativeToBase(PropertyOffset offset) { if (isOutOfLineOffset(offset)) @@ -1561,37 +1460,30 @@ inline int offsetRelativeToBase(PropertyOffset offset) COMPILE_ASSERT(!(sizeof(JSObject) % sizeof(WriteBarrierBase<Unknown>)), JSObject_inline_storage_has_correct_alignment); -class JSDestructibleObject : public JSNonFinalObject { -public: - typedef JSNonFinalObject Base; - - static const bool needsDestruction = true; - - const ClassInfo* classInfo() const { return m_classInfo; } - -protected: - JSDestructibleObject(JSGlobalData& globalData, Structure* structure, Butterfly* butterfly = 0) - : JSNonFinalObject(globalData, structure, butterfly) - , m_classInfo(structure->classInfo()) - { - ASSERT(m_classInfo); - } - -private: - const ClassInfo* m_classInfo; -}; +ALWAYS_INLINE Identifier makeIdentifier(ExecState* exec, const char* name) +{ + return Identifier(exec, name); +} -inline const ClassInfo* JSCell::classInfo() const +ALWAYS_INLINE Identifier makeIdentifier(ExecState*, const Identifier& name) { - if (MarkedBlock::blockFor(this)->destructorType() == MarkedBlock::Normal) - return static_cast<const JSDestructibleObject*>(this)->classInfo(); -#if ENABLE(GC_VALIDATION) - return m_structure.unvalidatedGet()->classInfo(); -#else - return m_structure->classInfo(); -#endif + return name; } +// Helper for defining native functions, if you're not using a static hash table. +// Use this macro from within finishCreation() methods in prototypes. This assumes +// you've defined variables called exec, globalObject, and vm, and they +// have the expected meanings. +#define JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, attributes, length, intrinsic) \ + putDirectNativeFunction(\ + exec, globalObject, makeIdentifier(exec, (jsName)), (length), cppName, \ + (intrinsic), (attributes)) + +// As above, but this assumes that the function you're defining doesn't have an +// intrinsic. +#define JSC_NATIVE_FUNCTION(jsName, cppName, attributes, length) \ + JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, (attributes), (length), NoIntrinsic) + } // namespace JSC #endif // JSObject_h diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp index 496799501..78b8aaee9 100644 --- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp +++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp @@ -36,7 +36,7 @@ namespace JSC { const ClassInfo JSPropertyNameIterator::s_info = { "JSPropertyNameIterator", 0, 0, 0, CREATE_METHOD_TABLE(JSPropertyNameIterator) }; inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlots) - : JSCell(exec->globalData(), exec->globalData().propertyNameIteratorStructure.get()) + : JSCell(exec->vm(), exec->vm().propertyNameIteratorStructure.get()) , m_numCacheableSlots(numCacheableSlots) , m_jsStringsSize(propertyNameArrayData->propertyNameVector().size()) , m_jsStrings(adoptArrayPtr(new WriteBarrier<Unknown>[m_jsStringsSize])) @@ -76,9 +76,9 @@ JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSObject return jsPropertyNameIterator; } - jsPropertyNameIterator->setCachedPrototypeChain(exec->globalData(), structureChain); - jsPropertyNameIterator->setCachedStructure(exec->globalData(), o->structure()); - o->structure()->setEnumerationCache(exec->globalData(), jsPropertyNameIterator); + jsPropertyNameIterator->setCachedPrototypeChain(exec->vm(), structureChain); + jsPropertyNameIterator->setCachedStructure(exec->vm(), o->structure()); + o->structure()->setEnumerationCache(exec->vm(), jsPropertyNameIterator); return jsPropertyNameIterator; } diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h index e59a5c6a4..ba931b131 100644 --- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h +++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h @@ -52,9 +52,9 @@ namespace JSC { static const bool hasImmortalStructure = true; static void destroy(JSCell*); - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(CompoundType, OverridesVisitChildren), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, OverridesVisitChildren), &s_info); } static void visitChildren(JSCell*, SlotVisitor&); @@ -62,26 +62,26 @@ namespace JSC { JSValue get(ExecState*, JSObject*, size_t i); size_t size() { return m_jsStringsSize; } - void setCachedStructure(JSGlobalData& globalData, Structure* structure) + void setCachedStructure(VM& vm, Structure* structure) { ASSERT(!m_cachedStructure); ASSERT(structure); - m_cachedStructure.set(globalData, this, structure); + m_cachedStructure.set(vm, this, structure); } Structure* cachedStructure() { return m_cachedStructure.get(); } - void setCachedPrototypeChain(JSGlobalData& globalData, StructureChain* cachedPrototypeChain) { m_cachedPrototypeChain.set(globalData, this, cachedPrototypeChain); } + void setCachedPrototypeChain(VM& vm, StructureChain* cachedPrototypeChain) { m_cachedPrototypeChain.set(vm, this, cachedPrototypeChain); } StructureChain* cachedPrototypeChain() { return m_cachedPrototypeChain.get(); } - static const ClassInfo s_info; + static JS_EXPORTDATA const ClassInfo s_info; protected: void finishCreation(ExecState* exec, PropertyNameArrayData* propertyNameArrayData, JSObject* object) { - Base::finishCreation(exec->globalData()); + Base::finishCreation(exec->vm()); PropertyNameArrayData::PropertyNameVector& propertyNameVector = propertyNameArrayData->propertyNameVector(); for (size_t i = 0; i < m_jsStringsSize; ++i) - m_jsStrings[i].set(exec->globalData(), this, jsOwnedString(exec, propertyNameVector[i].string())); + m_jsStrings[i].set(exec->vm(), this, jsOwnedString(exec, propertyNameVector[i].string())); m_cachedStructureInlineCapacity = object->structure()->inlineCapacity(); } @@ -98,20 +98,19 @@ namespace JSC { OwnArrayPtr<WriteBarrier<Unknown> > m_jsStrings; }; - inline void Structure::setEnumerationCache(JSGlobalData& globalData, JSPropertyNameIterator* enumerationCache) + ALWAYS_INLINE JSPropertyNameIterator* Register::propertyNameIterator() const { - ASSERT(!isDictionary()); - m_enumerationCache.set(globalData, this, enumerationCache); + return jsCast<JSPropertyNameIterator*>(jsValue().asCell()); } - inline JSPropertyNameIterator* Structure::enumerationCache() + inline JSPropertyNameIterator* StructureRareData::enumerationCache() { return m_enumerationCache.get(); } - - ALWAYS_INLINE JSPropertyNameIterator* Register::propertyNameIterator() const + + inline void StructureRareData::setEnumerationCache(VM& vm, const Structure* owner, JSPropertyNameIterator* value) { - return jsCast<JSPropertyNameIterator*>(jsValue().asCell()); + m_enumerationCache.set(vm, owner, value); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSProxy.cpp b/Source/JavaScriptCore/runtime/JSProxy.cpp index 7108dcfa0..e0f9d69e6 100644 --- a/Source/JavaScriptCore/runtime/JSProxy.cpp +++ b/Source/JavaScriptCore/runtime/JSProxy.cpp @@ -27,6 +27,7 @@ #include "JSProxy.h" #include "JSGlobalObject.h" +#include "Operations.h" namespace JSC { @@ -46,12 +47,21 @@ void JSProxy::visitChildren(JSCell* cell, SlotVisitor& visitor) visitor.append(&thisObject->m_target); } -void JSProxy::setTarget(JSGlobalData& globalData, JSGlobalObject* globalObject) +void JSProxy::setTarget(VM& vm, JSGlobalObject* globalObject) { ASSERT_ARG(globalObject, globalObject); - m_target.set(globalData, this, globalObject); - setPrototype(globalData, globalObject->prototype()); - resetInheritorID(globalData); + m_target.set(vm, this, globalObject); + setPrototype(vm, globalObject->prototype()); + + PrototypeMap& prototypeMap = vm.prototypeMap; + if (!prototypeMap.isPrototype(this)) + return; + + // This is slow but constant time. We think it's very rare for a proxy + // to be a prototype, and reasonably rare to retarget a proxy, + // so slow constant time is OK. + for (size_t i = 0; i <= JSFinalObject::maxInlineCapacity(); ++i) + prototypeMap.clearEmptyObjectStructureForPrototype(this, i); } String JSProxy::className(const JSObject* object) diff --git a/Source/JavaScriptCore/runtime/JSProxy.h b/Source/JavaScriptCore/runtime/JSProxy.h index 144085a79..9b6bed52e 100644 --- a/Source/JavaScriptCore/runtime/JSProxy.h +++ b/Source/JavaScriptCore/runtime/JSProxy.h @@ -34,16 +34,16 @@ class JSProxy : public JSDestructibleObject { public: typedef JSDestructibleObject Base; - static JSProxy* create(JSGlobalData& globalData, Structure* structure, JSObject* target) + static JSProxy* create(VM& vm, Structure* structure, JSObject* target) { - JSProxy* proxy = new (NotNull, allocateCell<JSProxy>(globalData.heap)) JSProxy(globalData, structure); - proxy->finishCreation(globalData, target); + JSProxy* proxy = new (NotNull, allocateCell<JSProxy>(vm.heap)) JSProxy(vm, structure); + proxy->finishCreation(vm, target); return proxy; } - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ProxyType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ProxyType, StructureFlags), &s_info); } static JS_EXPORTDATA const ClassInfo s_info; @@ -51,27 +51,27 @@ public: JSObject* target() const { return m_target.get(); } protected: - JSProxy(JSGlobalData& globalData, Structure* structure) - : JSDestructibleObject(globalData, structure) + JSProxy(VM& vm, Structure* structure) + : JSDestructibleObject(vm, structure) { } - void finishCreation(JSGlobalData& globalData) + void finishCreation(VM& vm) { - Base::finishCreation(globalData); + Base::finishCreation(vm); } - void finishCreation(JSGlobalData& globalData, JSObject* target) + void finishCreation(VM& vm, JSObject* target) { - Base::finishCreation(globalData); - m_target.set(globalData, this, target); + Base::finishCreation(vm); + m_target.set(vm, this, target); } - static const unsigned StructureFlags = OverridesVisitChildren | OverridesGetOwnPropertySlot | OverridesGetPropertyNames | Base::StructureFlags; + static const unsigned StructureFlags = OverridesVisitChildren | OverridesGetOwnPropertySlot | OverridesGetPropertyNames | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | Base::StructureFlags; JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); - JS_EXPORT_PRIVATE void setTarget(JSGlobalData&, JSGlobalObject*); + JS_EXPORT_PRIVATE void setTarget(VM&, JSGlobalObject*); JS_EXPORT_PRIVATE static String className(const JSObject*); JS_EXPORT_PRIVATE static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); diff --git a/Source/JavaScriptCore/runtime/JSScope.cpp b/Source/JavaScriptCore/runtime/JSScope.cpp index 8651a76ba..69ff1e478 100644 --- a/Source/JavaScriptCore/runtime/JSScope.cpp +++ b/Source/JavaScriptCore/runtime/JSScope.cpp @@ -30,6 +30,7 @@ #include "JSGlobalObject.h" #include "JSNameScope.h" #include "JSWithScope.h" +#include "Operations.h" namespace JSC { @@ -56,7 +57,7 @@ bool JSScope::isDynamicScope(bool& requiresDynamicChecks) const case NameScopeObjectType: return static_cast<const JSNameScope*>(this)->isDynamicScope(requiresDynamicChecks); default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); break; } @@ -166,7 +167,7 @@ static bool executeResolveOperations(CallFrame* callFrame, JSScope* scope, const case ResolveOperation::GetAndReturnGlobalProperty: { JSGlobalObject* globalObject = scope->globalObject(); if (globalObject->structure() == pc->m_structure.get()) { - result.setValue(globalObject->getDirectOffset(pc->m_offset)); + result.setValue(globalObject->getDirect(pc->m_offset)); return true; } @@ -186,7 +187,7 @@ static bool executeResolveOperations(CallFrame* callFrame, JSScope* scope, const return true; } - pc->m_structure.set(callFrame->globalData(), callFrame->codeBlock()->ownerExecutable(), structure); + pc->m_structure.set(callFrame->vm(), callFrame->codeBlock()->ownerExecutable(), structure); pc->m_offset = slot.cachedOffset(); result.setValue(value); return true; @@ -302,7 +303,7 @@ template <JSScope::LookupMode mode, JSScope::ReturnValues returnValues> JSObject if (putToBaseOperation) { putToBaseOperation->m_isDynamic = requiresDynamicChecks; putToBaseOperation->m_kind = PutToBaseOperation::GlobalPropertyPut; - putToBaseOperation->m_structure.set(callFrame->globalData(), callFrame->codeBlock()->ownerExecutable(), globalObject->structure()); + putToBaseOperation->m_structure.set(callFrame->vm(), callFrame->codeBlock()->ownerExecutable(), globalObject->structure()); setPutPropertyAccessOffset(putToBaseOperation, slot.cachedOffset()); } switch (returnValues) { @@ -345,7 +346,7 @@ template <JSScope::LookupMode mode, JSScope::ReturnValues returnValues> JSObject if (putToBaseOperation) { putToBaseOperation->m_kind = entry.isReadOnly() ? PutToBaseOperation::Readonly : PutToBaseOperation::VariablePut; - putToBaseOperation->m_structure.set(callFrame->globalData(), callFrame->codeBlock()->ownerExecutable(), callFrame->lexicalGlobalObject()->activationStructure()); + putToBaseOperation->m_structure.set(callFrame->vm(), callFrame->codeBlock()->ownerExecutable(), callFrame->lexicalGlobalObject()->activationStructure()); putToBaseOperation->m_offset = entry.getIndex(); putToBaseOperation->m_scopeDepth = (skipTopScopeNode ? 1 : 0) + scopeCount; } @@ -498,7 +499,7 @@ JSValue JSScope::resolveWithBase(CallFrame* callFrame, const Identifier& identif if (JSObject* propertyBase = JSScope::resolveContainingScope<ReturnBaseAndValue>(callFrame, identifier, slot, operations, putToBaseOperations, false)) { ASSERT(operations->size()); JSValue value = slot.getValue(callFrame, identifier); - if (callFrame->globalData().exception) + if (callFrame->vm().exception) return JSValue(); *base = propertyBase; @@ -528,7 +529,7 @@ JSValue JSScope::resolveWithThis(CallFrame* callFrame, const Identifier& identif if (JSObject* propertyBase = JSScope::resolveContainingScope<ReturnThisAndValue>(callFrame, identifier, slot, operations, 0, false)) { ASSERT(operations->size()); JSValue value = slot.getValue(callFrame, identifier); - if (callFrame->globalData().exception) + if (callFrame->vm().exception) return JSValue(); ASSERT(value); *base = propertyBase->structure()->typeInfo().isEnvironmentRecord() ? jsUndefined() : JSValue(propertyBase); @@ -563,7 +564,7 @@ void JSScope::resolvePut(CallFrame* callFrame, JSValue base, const Identifier& p goto genericHandler; } } - operation->m_registerAddress->set(callFrame->globalData(), base.asCell(), value); + operation->m_registerAddress->set(callFrame->vm(), base.asCell(), value); return; case PutToBaseOperation::VariablePut: { @@ -573,7 +574,7 @@ void JSScope::resolvePut(CallFrame* callFrame, JSValue base, const Identifier& p goto genericHandler; } JSVariableObject* variableObject = jsCast<JSVariableObject*>(base); - variableObject->registerAt(operation->m_offset).set(callFrame->globalData(), variableObject, value); + variableObject->registerAt(operation->m_offset).set(callFrame->vm(), variableObject, value); return; } @@ -581,7 +582,7 @@ void JSScope::resolvePut(CallFrame* callFrame, JSValue base, const Identifier& p JSObject* object = jsCast<JSObject*>(base); if (operation->m_structure.get() != object->structure()) break; - object->putDirectOffset(callFrame->globalData(), operation->m_offset, value); + object->putDirect(callFrame->vm(), operation->m_offset, value); return; } @@ -606,7 +607,7 @@ void JSScope::resolvePut(CallFrame* callFrame, JSValue base, const Identifier& p if (slot.base() != baseObject) return; ASSERT(!baseObject->hasInlineStorage()); - operation->m_structure.set(callFrame->globalData(), callFrame->codeBlock()->ownerExecutable(), baseObject->structure()); + operation->m_structure.set(callFrame->vm(), callFrame->codeBlock()->ownerExecutable(), baseObject->structure()); setPutPropertyAccessOffset(operation, slot.cachedOffset()); return; } diff --git a/Source/JavaScriptCore/runtime/JSScope.h b/Source/JavaScriptCore/runtime/JSScope.h index a9a9dd8d8..95db8ad56 100644 --- a/Source/JavaScriptCore/runtime/JSScope.h +++ b/Source/JavaScriptCore/runtime/JSScope.h @@ -59,11 +59,11 @@ public: int localDepth(); JSGlobalObject* globalObject(); - JSGlobalData* globalData(); + VM* vm(); JSObject* globalThis(); protected: - JSScope(JSGlobalData&, Structure*, JSScope* next); + JSScope(VM&, Structure*, JSScope* next); static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; private: @@ -80,9 +80,9 @@ private: template <ReturnValues> static JSObject* resolveContainingScope(CallFrame*, const Identifier&, PropertySlot&, ResolveOperations*, PutToBaseOperation*, bool isStrict); }; -inline JSScope::JSScope(JSGlobalData& globalData, Structure* structure, JSScope* next) - : Base(globalData, structure) - , m_next(globalData, this, next, WriteBarrier<JSScope>::MayBeNull) +inline JSScope::JSScope(VM& vm, Structure* structure, JSScope* next) + : Base(vm, structure) + , m_next(vm, this, next, WriteBarrier<JSScope>::MayBeNull) { } @@ -127,9 +127,9 @@ inline JSGlobalObject* JSScope::globalObject() return structure()->globalObject(); } -inline JSGlobalData* JSScope::globalData() +inline VM* JSScope::vm() { - return Heap::heap(this)->globalData(); + return Heap::heap(this)->vm(); } inline Register& Register::operator=(JSScope* scope) @@ -143,10 +143,10 @@ inline JSScope* Register::scope() const return jsCast<JSScope*>(jsValue()); } -inline JSGlobalData& ExecState::globalData() const +inline VM& ExecState::vm() const { - ASSERT(scope()->globalData()); - return *scope()->globalData(); + ASSERT(scope()->vm()); + return *scope()->vm(); } inline JSGlobalObject* ExecState::lexicalGlobalObject() const diff --git a/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp b/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp index c65d2b1b9..01c070451 100644 --- a/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp +++ b/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp @@ -29,6 +29,8 @@ #include "config.h" #include "JSSegmentedVariableObject.h" +#include "Operations.h" + namespace JSC { int JSSegmentedVariableObject::findRegisterIndex(void* registerAddress) diff --git a/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h b/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h index 1fd96c17a..3a6f625ce 100644 --- a/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h +++ b/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h @@ -35,7 +35,6 @@ #include "SymbolTable.h" #include <wtf/OwnArrayPtr.h> #include <wtf/SegmentedVector.h> -#include <wtf/UnusedParam.h> namespace JSC { @@ -82,14 +81,14 @@ public: protected: static const unsigned StructureFlags = OverridesVisitChildren | JSSymbolTableObject::StructureFlags; - JSSegmentedVariableObject(JSGlobalData& globalData, Structure* structure, JSScope* scope) - : JSSymbolTableObject(globalData, structure, scope) + JSSegmentedVariableObject(VM& vm, Structure* structure, JSScope* scope) + : JSSymbolTableObject(vm, structure, scope) { } - void finishCreation(JSGlobalData& globalData) + void finishCreation(VM& vm) { - Base::finishCreation(globalData); + Base::finishCreation(vm); } SegmentedVector<WriteBarrier<Unknown>, 16> m_registers; diff --git a/Source/JavaScriptCore/runtime/JSString.cpp b/Source/JavaScriptCore/runtime/JSString.cpp index f0e796d89..86704d715 100644 --- a/Source/JavaScriptCore/runtime/JSString.cpp +++ b/Source/JavaScriptCore/runtime/JSString.cpp @@ -40,7 +40,7 @@ void JSRopeString::RopeBuilder::expand() { ASSERT(m_index == JSRopeString::s_maxInternalRopeLength); JSString* jsString = m_jsString; - m_jsString = jsStringBuilder(&m_globalData); + m_jsString = jsStringBuilder(&m_vm); m_index = 0; append(jsString); } @@ -154,7 +154,7 @@ void JSRopeString::resolveRope(ExecState* exec) const void JSRopeString::resolveRopeSlowCase8(LChar* buffer) const { LChar* position = buffer + m_length; // We will be working backwards over the rope. - Vector<JSString*, 32> workQueue; // Putting strings into a Vector is only OK because there are no GC points in this method. + Vector<JSString*, 32, UnsafeVectorOverflow> workQueue; // Putting strings into a Vector is only OK because there are no GC points in this method. for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) { workQueue.append(m_fibers[i].get()); @@ -186,7 +186,7 @@ void JSRopeString::resolveRopeSlowCase8(LChar* buffer) const void JSRopeString::resolveRopeSlowCase(UChar* buffer) const { UChar* position = buffer + m_length; // We will be working backwards over the rope. - Vector<JSString*, 32> workQueue; // These strings are kept alive by the parent rope, so using a Vector is OK. + Vector<JSString*, 32, UnsafeVectorOverflow> workQueue; // These strings are kept alive by the parent rope, so using a Vector is OK. for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) workQueue.append(m_fibers[i].get()); @@ -233,7 +233,7 @@ JSString* JSRopeString::getIndexSlowCase(ExecState* exec, unsigned i) if (exec->exception()) return jsEmptyString(exec); ASSERT(!isRope()); - ASSERT(i < m_value.length()); + RELEASE_ASSERT(i < m_value.length()); return jsSingleCharacterSubstring(exec, m_value, i); } @@ -261,8 +261,8 @@ double JSString::toNumber(ExecState* exec) const inline StringObject* StringObject::create(ExecState* exec, JSGlobalObject* globalObject, JSString* string) { - StringObject* object = new (NotNull, allocateCell<StringObject>(*exec->heap())) StringObject(exec->globalData(), globalObject->stringObjectStructure()); - object->finishCreation(exec->globalData(), string); + StringObject* object = new (NotNull, allocateCell<StringObject>(*exec->heap())) StringObject(exec->vm(), globalObject->stringObjectStructure()); + object->finishCreation(exec->vm(), string); return object; } diff --git a/Source/JavaScriptCore/runtime/JSString.h b/Source/JavaScriptCore/runtime/JSString.h index 245c48a51..855de974d 100644 --- a/Source/JavaScriptCore/runtime/JSString.h +++ b/Source/JavaScriptCore/runtime/JSString.h @@ -31,525 +31,523 @@ namespace JSC { - class JSString; - class JSRopeString; - class LLIntOffsetsExtractor; - - JSString* jsEmptyString(JSGlobalData*); - JSString* jsEmptyString(ExecState*); - JSString* jsString(JSGlobalData*, const String&); // returns empty string if passed null string - JSString* jsString(ExecState*, const String&); // returns empty string if passed null string - - JSString* jsSingleCharacterString(JSGlobalData*, UChar); - JSString* jsSingleCharacterString(ExecState*, UChar); - JSString* jsSingleCharacterSubstring(ExecState*, const String&, unsigned offset); - JSString* jsSubstring(JSGlobalData*, const String&, unsigned offset, unsigned length); - JSString* jsSubstring(ExecState*, const String&, unsigned offset, unsigned length); - - // Non-trivial strings are two or more characters long. - // These functions are faster than just calling jsString. - JSString* jsNontrivialString(JSGlobalData*, const String&); - JSString* jsNontrivialString(ExecState*, const String&); - - // Should be used for strings that are owned by an object that will - // likely outlive the JSValue this makes, such as the parse tree or a - // DOM object that contains a String - JSString* jsOwnedString(JSGlobalData*, const String&); - JSString* jsOwnedString(ExecState*, const String&); - - JSRopeString* jsStringBuilder(JSGlobalData*); - - class JSString : public JSCell { - public: - friend class JIT; - friend class JSGlobalData; - friend class SpecializedThunkJIT; - friend class JSRopeString; - friend class MarkStack; - friend class SlotVisitor; - friend struct ThunkHelpers; - - typedef JSCell Base; - - static const bool needsDestruction = true; - static const bool hasImmortalStructure = true; - static void destroy(JSCell*); - - private: - JSString(JSGlobalData& globalData, PassRefPtr<StringImpl> value) - : JSCell(globalData, globalData.stringStructure.get()) - , m_flags(0) - , m_value(value) - { - } +class JSString; +class JSRopeString; +class LLIntOffsetsExtractor; + +JSString* jsEmptyString(VM*); +JSString* jsEmptyString(ExecState*); +JSString* jsString(VM*, const String&); // returns empty string if passed null string +JSString* jsString(ExecState*, const String&); // returns empty string if passed null string + +JSString* jsSingleCharacterString(VM*, UChar); +JSString* jsSingleCharacterString(ExecState*, UChar); +JSString* jsSingleCharacterSubstring(ExecState*, const String&, unsigned offset); +JSString* jsSubstring(VM*, const String&, unsigned offset, unsigned length); +JSString* jsSubstring(ExecState*, const String&, unsigned offset, unsigned length); + +// Non-trivial strings are two or more characters long. +// These functions are faster than just calling jsString. +JSString* jsNontrivialString(VM*, const String&); +JSString* jsNontrivialString(ExecState*, const String&); + +// Should be used for strings that are owned by an object that will +// likely outlive the JSValue this makes, such as the parse tree or a +// DOM object that contains a String +JSString* jsOwnedString(VM*, const String&); +JSString* jsOwnedString(ExecState*, const String&); + +JSRopeString* jsStringBuilder(VM*); + +class JSString : public JSCell { +public: + friend class JIT; + friend class VM; + friend class SpecializedThunkJIT; + friend class JSRopeString; + friend class MarkStack; + friend class SlotVisitor; + friend struct ThunkHelpers; + + typedef JSCell Base; + + static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; + static void destroy(JSCell*); + +private: + JSString(VM& vm, PassRefPtr<StringImpl> value) + : JSCell(vm, vm.stringStructure.get()) + , m_flags(0) + , m_value(value) + { + } - JSString(JSGlobalData& globalData) - : JSCell(globalData, globalData.stringStructure.get()) - , m_flags(0) - { - } + JSString(VM& vm) + : JSCell(vm, vm.stringStructure.get()) + , m_flags(0) + { + } - void finishCreation(JSGlobalData& globalData, size_t length) - { - ASSERT(!m_value.isNull()); - Base::finishCreation(globalData); - m_length = length; - setIs8Bit(m_value.impl()->is8Bit()); - globalData.m_newStringsSinceLastHashConst++; - } + void finishCreation(VM& vm, size_t length) + { + ASSERT(!m_value.isNull()); + Base::finishCreation(vm); + m_length = length; + setIs8Bit(m_value.impl()->is8Bit()); + vm.m_newStringsSinceLastHashCons++; + } - void finishCreation(JSGlobalData& globalData, size_t length, size_t cost) - { - ASSERT(!m_value.isNull()); - Base::finishCreation(globalData); - m_length = length; - setIs8Bit(m_value.impl()->is8Bit()); - Heap::heap(this)->reportExtraMemoryCost(cost); - globalData.m_newStringsSinceLastHashConst++; - } + void finishCreation(VM& vm, size_t length, size_t cost) + { + ASSERT(!m_value.isNull()); + Base::finishCreation(vm); + m_length = length; + setIs8Bit(m_value.impl()->is8Bit()); + Heap::heap(this)->reportExtraMemoryCost(cost); + vm.m_newStringsSinceLastHashCons++; + } - protected: - void finishCreation(JSGlobalData& globalData) - { - Base::finishCreation(globalData); - m_length = 0; - setIs8Bit(true); - globalData.m_newStringsSinceLastHashConst++; - } +protected: + void finishCreation(VM& vm) + { + Base::finishCreation(vm); + m_length = 0; + setIs8Bit(true); + vm.m_newStringsSinceLastHashCons++; + } - public: - static JSString* create(JSGlobalData& globalData, PassRefPtr<StringImpl> value) - { - ASSERT(value); - size_t length = value->length(); - size_t cost = value->cost(); - JSString* newString = new (NotNull, allocateCell<JSString>(globalData.heap)) JSString(globalData, value); - newString->finishCreation(globalData, length, cost); - return newString; - } - static JSString* createHasOtherOwner(JSGlobalData& globalData, PassRefPtr<StringImpl> value) - { - ASSERT(value); - size_t length = value->length(); - JSString* newString = new (NotNull, allocateCell<JSString>(globalData.heap)) JSString(globalData, value); - newString->finishCreation(globalData, length); - return newString; - } +public: + static JSString* create(VM& vm, PassRefPtr<StringImpl> value) + { + ASSERT(value); + size_t length = value->length(); + size_t cost = value->cost(); + JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, value); + newString->finishCreation(vm, length, cost); + return newString; + } + static JSString* createHasOtherOwner(VM& vm, PassRefPtr<StringImpl> value) + { + ASSERT(value); + size_t length = value->length(); + JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, value); + newString->finishCreation(vm, length); + return newString; + } - const String& value(ExecState*) const; - const String& tryGetValue() const; - unsigned length() { return m_length; } + const String& value(ExecState*) const; + const String& tryGetValue() const; + unsigned length() { return m_length; } - JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; - JS_EXPORT_PRIVATE bool toBoolean() const; - bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const; - JSObject* toObject(ExecState*, JSGlobalObject*) const; - double toNumber(ExecState*) const; + JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; + JS_EXPORT_PRIVATE bool toBoolean() const; + bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const; + JSObject* toObject(ExecState*, JSGlobalObject*) const; + double toNumber(ExecState*) const; - bool getStringPropertySlot(ExecState*, PropertyName, PropertySlot&); - bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); - bool getStringPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&); + bool getStringPropertySlot(ExecState*, PropertyName, PropertySlot&); + bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); + bool getStringPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&); - bool canGetIndex(unsigned i) { return i < m_length; } - JSString* getIndex(ExecState*, unsigned); + bool canGetIndex(unsigned i) { return i < m_length; } + JSString* getIndex(ExecState*, unsigned); - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) - { - return Structure::create(globalData, globalObject, proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero), &s_info); - } + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) + { + return Structure::create(vm, globalObject, proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero), &s_info); + } - static size_t offsetOfLength() { return OBJECT_OFFSETOF(JSString, m_length); } - static size_t offsetOfValue() { return OBJECT_OFFSETOF(JSString, m_value); } + static size_t offsetOfLength() { return OBJECT_OFFSETOF(JSString, m_length); } + static size_t offsetOfFlags() { return OBJECT_OFFSETOF(JSString, m_flags); } + static size_t offsetOfValue() { return OBJECT_OFFSETOF(JSString, m_value); } - static JS_EXPORTDATA const ClassInfo s_info; + static JS_EXPORTDATA const ClassInfo s_info; - static void visitChildren(JSCell*, SlotVisitor&); + static void visitChildren(JSCell*, SlotVisitor&); - protected: - bool isRope() const { return m_value.isNull(); } - bool is8Bit() const { return m_flags & Is8Bit; } - void setIs8Bit(bool flag) - { - if (flag) - m_flags |= Is8Bit; - else - m_flags &= ~Is8Bit; - } - bool shouldTryHashConst(); - bool isHashConstSingleton() const { return m_flags & IsHashConstSingleton; } - void clearHashConstSingleton() { m_flags &= ~IsHashConstSingleton; } - void setHashConstSingleton() { m_flags |= IsHashConstSingleton; } - bool tryHashConstLock(); - void releaseHashConstLock(); - - unsigned m_flags; - - enum { - HashConstLock = 1u << 2, - IsHashConstSingleton = 1u << 1, - Is8Bit = 1u - }; + enum { + HashConsLock = 1u << 2, + IsHashConsSingleton = 1u << 1, + Is8Bit = 1u + }; - // A string is represented either by a String or a rope of fibers. - unsigned m_length; - mutable String m_value; +protected: + friend class JSValue; + + bool isRope() const { return m_value.isNull(); } + bool is8Bit() const { return m_flags & Is8Bit; } + void setIs8Bit(bool flag) + { + if (flag) + m_flags |= Is8Bit; + else + m_flags &= ~Is8Bit; + } + bool shouldTryHashCons(); + bool isHashConsSingleton() const { return m_flags & IsHashConsSingleton; } + void clearHashConsSingleton() { m_flags &= ~IsHashConsSingleton; } + void setHashConsSingleton() { m_flags |= IsHashConsSingleton; } + bool tryHashConsLock(); + void releaseHashConsLock(); + + unsigned m_flags; + + // A string is represented either by a String or a rope of fibers. + unsigned m_length; + mutable String m_value; - private: - friend class LLIntOffsetsExtractor; +private: + friend class LLIntOffsetsExtractor; - static JSObject* toThisObject(JSCell*, ExecState*); + static JSObject* toThisObject(JSCell*, ExecState*); - // Actually getPropertySlot, not getOwnPropertySlot (see JSCell). - static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); - static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&); + // Actually getPropertySlot, not getOwnPropertySlot (see JSCell). + static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); + static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&); - String& string() { ASSERT(!isRope()); return m_value; } + String& string() { ASSERT(!isRope()); return m_value; } - friend JSValue jsString(ExecState*, JSString*, JSString*); - friend JSString* jsSubstring(ExecState*, JSString*, unsigned offset, unsigned length); - }; + friend JSValue jsString(ExecState*, JSString*, JSString*); + friend JSString* jsSubstring(ExecState*, JSString*, unsigned offset, unsigned length); +}; - class JSRopeString : public JSString { - friend class JSString; +class JSRopeString : public JSString { + friend class JSString; - friend JSRopeString* jsStringBuilder(JSGlobalData*); + friend JSRopeString* jsStringBuilder(VM*); - class RopeBuilder { - public: - RopeBuilder(JSGlobalData& globalData) - : m_globalData(globalData) - , m_jsString(jsStringBuilder(&globalData)) + class RopeBuilder { + public: + RopeBuilder(VM& vm) + : m_vm(vm) + , m_jsString(jsStringBuilder(&vm)) , m_index(0) - { - } - - void append(JSString* jsString) - { - if (m_index == JSRopeString::s_maxInternalRopeLength) - expand(); - m_jsString->append(m_globalData, m_index++, jsString); - } - - JSRopeString* release() - { - JSRopeString* tmp = m_jsString; - m_jsString = 0; - return tmp; - } - - unsigned length() { return m_jsString->m_length; } - - private: - void expand(); - - JSGlobalData& m_globalData; - JSRopeString* m_jsString; - size_t m_index; - }; - - private: - JSRopeString(JSGlobalData& globalData) - : JSString(globalData) - { - } - - void finishCreation(JSGlobalData& globalData, JSString* s1, JSString* s2) - { - Base::finishCreation(globalData); - m_length = s1->length() + s2->length(); - setIs8Bit(s1->is8Bit() && s2->is8Bit()); - m_fibers[0].set(globalData, this, s1); - m_fibers[1].set(globalData, this, s2); - } - - void finishCreation(JSGlobalData& globalData, JSString* s1, JSString* s2, JSString* s3) { - Base::finishCreation(globalData); - m_length = s1->length() + s2->length() + s3->length(); - setIs8Bit(s1->is8Bit() && s2->is8Bit() && s3->is8Bit()); - m_fibers[0].set(globalData, this, s1); - m_fibers[1].set(globalData, this, s2); - m_fibers[2].set(globalData, this, s3); } - void finishCreation(JSGlobalData& globalData) + void append(JSString* jsString) { - JSString::finishCreation(globalData); + if (m_index == JSRopeString::s_maxInternalRopeLength) + expand(); + m_jsString->append(m_vm, m_index++, jsString); } - void append(JSGlobalData& globalData, size_t index, JSString* jsString) - { - m_fibers[index].set(globalData, this, jsString); - m_length += jsString->m_length; - setIs8Bit(is8Bit() && jsString->is8Bit()); - } - - static JSRopeString* createNull(JSGlobalData& globalData) - { - JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(globalData.heap)) JSRopeString(globalData); - newString->finishCreation(globalData); - return newString; - } - - public: - static JSString* create(JSGlobalData& globalData, JSString* s1, JSString* s2) - { - JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(globalData.heap)) JSRopeString(globalData); - newString->finishCreation(globalData, s1, s2); - return newString; - } - static JSString* create(JSGlobalData& globalData, JSString* s1, JSString* s2, JSString* s3) + JSRopeString* release() { - JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(globalData.heap)) JSRopeString(globalData); - newString->finishCreation(globalData, s1, s2, s3); - return newString; + JSRopeString* tmp = m_jsString; + m_jsString = 0; + return tmp; } - void visitFibers(SlotVisitor&); + unsigned length() { return m_jsString->m_length; } private: - friend JSValue jsString(ExecState*, Register*, unsigned); - friend JSValue jsStringFromArguments(ExecState*, JSValue); - - JS_EXPORT_PRIVATE void resolveRope(ExecState*) const; - void resolveRopeSlowCase8(LChar*) const; - void resolveRopeSlowCase(UChar*) const; - void outOfMemory(ExecState*) const; - - JSString* getIndexSlowCase(ExecState*, unsigned); - - static const unsigned s_maxInternalRopeLength = 3; - - mutable FixedArray<WriteBarrier<JSString>, s_maxInternalRopeLength> m_fibers; + void expand(); + + VM& m_vm; + JSRopeString* m_jsString; + size_t m_index; }; - - JSString* asString(JSValue); - - inline JSString* asString(JSValue value) + +private: + JSRopeString(VM& vm) + : JSString(vm) { - ASSERT(value.asCell()->isString()); - return jsCast<JSString*>(value.asCell()); } - inline JSString* jsEmptyString(JSGlobalData* globalData) + void finishCreation(VM& vm, JSString* s1, JSString* s2) { - return globalData->smallStrings.emptyString(globalData); + Base::finishCreation(vm); + m_length = s1->length() + s2->length(); + setIs8Bit(s1->is8Bit() && s2->is8Bit()); + m_fibers[0].set(vm, this, s1); + m_fibers[1].set(vm, this, s2); } - - ALWAYS_INLINE JSString* jsSingleCharacterString(JSGlobalData* globalData, UChar c) + + void finishCreation(VM& vm, JSString* s1, JSString* s2, JSString* s3) { - if (c <= maxSingleCharacterString) - return globalData->smallStrings.singleCharacterString(globalData, c); - return JSString::create(*globalData, String(&c, 1).impl()); + Base::finishCreation(vm); + m_length = s1->length() + s2->length() + s3->length(); + setIs8Bit(s1->is8Bit() && s2->is8Bit() && s3->is8Bit()); + m_fibers[0].set(vm, this, s1); + m_fibers[1].set(vm, this, s2); + m_fibers[2].set(vm, this, s3); } - ALWAYS_INLINE JSString* jsSingleCharacterSubstring(ExecState* exec, const String& s, unsigned offset) + void finishCreation(VM& vm) { - JSGlobalData* globalData = &exec->globalData(); - ASSERT(offset < static_cast<unsigned>(s.length())); - UChar c = s.characterAt(offset); - if (c <= maxSingleCharacterString) - return globalData->smallStrings.singleCharacterString(globalData, c); - return JSString::create(*globalData, StringImpl::create(s.impl(), offset, 1)); + JSString::finishCreation(vm); } - inline JSString* jsNontrivialString(JSGlobalData* globalData, const String& s) + void append(VM& vm, size_t index, JSString* jsString) { - ASSERT(s.length() > 1); - return JSString::create(*globalData, s.impl()); + m_fibers[index].set(vm, this, jsString); + m_length += jsString->m_length; + setIs8Bit(is8Bit() && jsString->is8Bit()); } - inline const String& JSString::value(ExecState* exec) const + static JSRopeString* createNull(VM& vm) { - if (isRope()) - static_cast<const JSRopeString*>(this)->resolveRope(exec); - return m_value; + JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); + newString->finishCreation(vm); + return newString; } - inline const String& JSString::tryGetValue() const +public: + static JSString* create(VM& vm, JSString* s1, JSString* s2) { - if (isRope()) - static_cast<const JSRopeString*>(this)->resolveRope(0); - return m_value; + JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); + newString->finishCreation(vm, s1, s2); + return newString; } - - inline JSString* JSString::getIndex(ExecState* exec, unsigned i) + static JSString* create(VM& vm, JSString* s1, JSString* s2, JSString* s3) { - ASSERT(canGetIndex(i)); - if (isRope()) - return static_cast<JSRopeString*>(this)->getIndexSlowCase(exec, i); - ASSERT(i < m_value.length()); - return jsSingleCharacterSubstring(exec, m_value, i); + JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); + newString->finishCreation(vm, s1, s2, s3); + return newString; } - inline JSString* jsString(JSGlobalData* globalData, const String& s) - { - int size = s.length(); - if (!size) - return globalData->smallStrings.emptyString(globalData); - if (size == 1) { - UChar c = s.characterAt(0); - if (c <= maxSingleCharacterString) - return globalData->smallStrings.singleCharacterString(globalData, c); - } - return JSString::create(*globalData, s.impl()); - } + void visitFibers(SlotVisitor&); + + static ptrdiff_t offsetOfFibers() { return OBJECT_OFFSETOF(JSRopeString, m_fibers); } - inline JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length) - { - ASSERT(offset <= static_cast<unsigned>(s->length())); - ASSERT(length <= static_cast<unsigned>(s->length())); - ASSERT(offset + length <= static_cast<unsigned>(s->length())); - JSGlobalData* globalData = &exec->globalData(); - if (!length) - return globalData->smallStrings.emptyString(globalData); - return jsSubstring(globalData, s->value(exec), offset, length); + static const unsigned s_maxInternalRopeLength = 3; + +private: + friend JSValue jsString(ExecState*, Register*, unsigned); + friend JSValue jsStringFromArguments(ExecState*, JSValue); + + JS_EXPORT_PRIVATE void resolveRope(ExecState*) const; + void resolveRopeSlowCase8(LChar*) const; + void resolveRopeSlowCase(UChar*) const; + void outOfMemory(ExecState*) const; + + JSString* getIndexSlowCase(ExecState*, unsigned); + + mutable FixedArray<WriteBarrier<JSString>, s_maxInternalRopeLength> m_fibers; +}; + +JSString* asString(JSValue); + +inline JSString* asString(JSValue value) +{ + ASSERT(value.asCell()->isString()); + return jsCast<JSString*>(value.asCell()); +} + +inline JSString* jsEmptyString(VM* vm) +{ + return vm->smallStrings.emptyString(); +} + +ALWAYS_INLINE JSString* jsSingleCharacterString(VM* vm, UChar c) +{ + if (c <= maxSingleCharacterString) + return vm->smallStrings.singleCharacterString(vm, c); + return JSString::create(*vm, String(&c, 1).impl()); +} + +ALWAYS_INLINE JSString* jsSingleCharacterSubstring(ExecState* exec, const String& s, unsigned offset) +{ + VM* vm = &exec->vm(); + ASSERT(offset < static_cast<unsigned>(s.length())); + UChar c = s.characterAt(offset); + if (c <= maxSingleCharacterString) + return vm->smallStrings.singleCharacterString(vm, c); + return JSString::create(*vm, StringImpl::create(s.impl(), offset, 1)); +} + +inline JSString* jsNontrivialString(VM* vm, const String& s) +{ + ASSERT(s.length() > 1); + return JSString::create(*vm, s.impl()); +} + +inline const String& JSString::value(ExecState* exec) const +{ + if (isRope()) + static_cast<const JSRopeString*>(this)->resolveRope(exec); + return m_value; +} + +inline const String& JSString::tryGetValue() const +{ + if (isRope()) + static_cast<const JSRopeString*>(this)->resolveRope(0); + return m_value; +} + +inline JSString* JSString::getIndex(ExecState* exec, unsigned i) +{ + ASSERT(canGetIndex(i)); + if (isRope()) + return static_cast<JSRopeString*>(this)->getIndexSlowCase(exec, i); + ASSERT(i < m_value.length()); + return jsSingleCharacterSubstring(exec, m_value, i); +} + +inline JSString* jsString(VM* vm, const String& s) +{ + int size = s.length(); + if (!size) + return vm->smallStrings.emptyString(); + if (size == 1) { + UChar c = s.characterAt(0); + if (c <= maxSingleCharacterString) + return vm->smallStrings.singleCharacterString(vm, c); } - - inline JSString* jsSubstring8(JSGlobalData* globalData, const String& s, unsigned offset, unsigned length) - { - ASSERT(offset <= static_cast<unsigned>(s.length())); - ASSERT(length <= static_cast<unsigned>(s.length())); - ASSERT(offset + length <= static_cast<unsigned>(s.length())); - if (!length) - return globalData->smallStrings.emptyString(globalData); - if (length == 1) { - UChar c = s.characterAt(offset); - if (c <= maxSingleCharacterString) - return globalData->smallStrings.singleCharacterString(globalData, c); - } - return JSString::createHasOtherOwner(*globalData, StringImpl::create8(s.impl(), offset, length)); + return JSString::create(*vm, s.impl()); +} + +inline JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length) +{ + ASSERT(offset <= static_cast<unsigned>(s->length())); + ASSERT(length <= static_cast<unsigned>(s->length())); + ASSERT(offset + length <= static_cast<unsigned>(s->length())); + VM* vm = &exec->vm(); + if (!length) + return vm->smallStrings.emptyString(); + return jsSubstring(vm, s->value(exec), offset, length); +} + +inline JSString* jsSubstring8(VM* vm, const String& s, unsigned offset, unsigned length) +{ + ASSERT(offset <= static_cast<unsigned>(s.length())); + ASSERT(length <= static_cast<unsigned>(s.length())); + ASSERT(offset + length <= static_cast<unsigned>(s.length())); + if (!length) + return vm->smallStrings.emptyString(); + if (length == 1) { + UChar c = s.characterAt(offset); + if (c <= maxSingleCharacterString) + return vm->smallStrings.singleCharacterString(vm, c); } - - inline JSString* jsSubstring(JSGlobalData* globalData, const String& s, unsigned offset, unsigned length) - { - ASSERT(offset <= static_cast<unsigned>(s.length())); - ASSERT(length <= static_cast<unsigned>(s.length())); - ASSERT(offset + length <= static_cast<unsigned>(s.length())); - if (!length) - return globalData->smallStrings.emptyString(globalData); - if (length == 1) { - UChar c = s.characterAt(offset); - if (c <= maxSingleCharacterString) - return globalData->smallStrings.singleCharacterString(globalData, c); - } - return JSString::createHasOtherOwner(*globalData, StringImpl::create(s.impl(), offset, length)); + return JSString::createHasOtherOwner(*vm, StringImpl::create8(s.impl(), offset, length)); +} + +inline JSString* jsSubstring(VM* vm, const String& s, unsigned offset, unsigned length) +{ + ASSERT(offset <= static_cast<unsigned>(s.length())); + ASSERT(length <= static_cast<unsigned>(s.length())); + ASSERT(offset + length <= static_cast<unsigned>(s.length())); + if (!length) + return vm->smallStrings.emptyString(); + if (length == 1) { + UChar c = s.characterAt(offset); + if (c <= maxSingleCharacterString) + return vm->smallStrings.singleCharacterString(vm, c); } - - inline JSString* jsOwnedString(JSGlobalData* globalData, const String& s) - { - int size = s.length(); - if (!size) - return globalData->smallStrings.emptyString(globalData); - if (size == 1) { - UChar c = s.characterAt(0); - if (c <= maxSingleCharacterString) - return globalData->smallStrings.singleCharacterString(globalData, c); - } - return JSString::createHasOtherOwner(*globalData, s.impl()); + return JSString::createHasOtherOwner(*vm, StringImpl::create(s.impl(), offset, length)); +} + +inline JSString* jsOwnedString(VM* vm, const String& s) +{ + int size = s.length(); + if (!size) + return vm->smallStrings.emptyString(); + if (size == 1) { + UChar c = s.characterAt(0); + if (c <= maxSingleCharacterString) + return vm->smallStrings.singleCharacterString(vm, c); } - - inline JSRopeString* jsStringBuilder(JSGlobalData* globalData) - { - return JSRopeString::createNull(*globalData); + return JSString::createHasOtherOwner(*vm, s.impl()); +} + +inline JSRopeString* jsStringBuilder(VM* vm) +{ + return JSRopeString::createNull(*vm); +} + +inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->vm()); } +inline JSString* jsString(ExecState* exec, const String& s) { return jsString(&exec->vm(), s); } +inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->vm(), c); } +inline JSString* jsSubstring8(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring8(&exec->vm(), s, offset, length); } +inline JSString* jsSubstring(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring(&exec->vm(), s, offset, length); } +inline JSString* jsNontrivialString(ExecState* exec, const String& s) { return jsNontrivialString(&exec->vm(), s); } +inline JSString* jsOwnedString(ExecState* exec, const String& s) { return jsOwnedString(&exec->vm(), s); } + +ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot) +{ + if (propertyName == exec->propertyNames().length) { + slot.setValue(jsNumber(m_length)); + return true; } - inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->globalData()); } - inline JSString* jsString(ExecState* exec, const String& s) { return jsString(&exec->globalData(), s); } - inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->globalData(), c); } - inline JSString* jsSubstring8(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring8(&exec->globalData(), s, offset, length); } - inline JSString* jsSubstring(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring(&exec->globalData(), s, offset, length); } - inline JSString* jsNontrivialString(ExecState* exec, const String& s) { return jsNontrivialString(&exec->globalData(), s); } - inline JSString* jsOwnedString(ExecState* exec, const String& s) { return jsOwnedString(&exec->globalData(), s); } - - ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot) - { - if (propertyName == exec->propertyNames().length) { - slot.setValue(jsNumber(m_length)); - return true; - } - - unsigned i = propertyName.asIndex(); - if (i < m_length) { - ASSERT(i != PropertyName::NotAnIndex); // No need for an explicit check, the above test would always fail! - slot.setValue(getIndex(exec, i)); - return true; - } - - return false; + unsigned i = propertyName.asIndex(); + if (i < m_length) { + ASSERT(i != PropertyName::NotAnIndex); // No need for an explicit check, the above test would always fail! + slot.setValue(getIndex(exec, i)); + return true; } - - ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) - { - if (propertyName < m_length) { - slot.setValue(getIndex(exec, propertyName)); - return true; - } - return false; + return false; +} + +ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) +{ + if (propertyName < m_length) { + slot.setValue(getIndex(exec, propertyName)); + return true; } - inline bool isJSString(JSValue v) { return v.isCell() && v.asCell()->classInfo() == &JSString::s_info; } + return false; +} - inline bool JSCell::toBoolean(ExecState* exec) const - { - if (isString()) - return static_cast<const JSString*>(this)->toBoolean(); - return !structure()->masqueradesAsUndefined(exec->lexicalGlobalObject()); - } +inline bool isJSString(JSValue v) { return v.isCell() && v.asCell()->classInfo() == &JSString::s_info; } - // --- JSValue inlines ---------------------------- +// --- JSValue inlines ---------------------------- - inline bool JSValue::toBoolean(ExecState* exec) const - { - if (isInt32()) - return asInt32(); - if (isDouble()) - return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN - if (isCell()) - return asCell()->toBoolean(exec); - return isTrue(); // false, null, and undefined all convert to false. - } - - inline JSString* JSValue::toString(ExecState* exec) const - { - if (isString()) - return jsCast<JSString*>(asCell()); - return toStringSlowCase(exec); - } - - inline String JSValue::toWTFString(ExecState* exec) const - { - if (isString()) - return static_cast<JSString*>(asCell())->value(exec); - return toWTFStringSlowCase(exec); - } - - ALWAYS_INLINE String inlineJSValueNotStringtoString(const JSValue& value, ExecState* exec) - { - JSGlobalData& globalData = exec->globalData(); - if (value.isInt32()) - return globalData.numericStrings.add(value.asInt32()); - if (value.isDouble()) - return globalData.numericStrings.add(value.asDouble()); - if (value.isTrue()) - return globalData.propertyNames->trueKeyword.string(); - if (value.isFalse()) - return globalData.propertyNames->falseKeyword.string(); - if (value.isNull()) - return globalData.propertyNames->nullKeyword.string(); - if (value.isUndefined()) - return globalData.propertyNames->undefinedKeyword.string(); - return value.toString(exec)->value(exec); - } - - ALWAYS_INLINE String JSValue::toWTFStringInline(ExecState* exec) const - { - if (isString()) - return static_cast<JSString*>(asCell())->value(exec); - - return inlineJSValueNotStringtoString(*this, exec); - } +inline bool JSValue::toBoolean(ExecState* exec) const +{ + if (isInt32()) + return asInt32(); + if (isDouble()) + return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN + if (isCell()) + return asCell()->toBoolean(exec); + return isTrue(); // false, null, and undefined all convert to false. +} + +inline JSString* JSValue::toString(ExecState* exec) const +{ + if (isString()) + return jsCast<JSString*>(asCell()); + return toStringSlowCase(exec); +} + +inline String JSValue::toWTFString(ExecState* exec) const +{ + if (isString()) + return static_cast<JSString*>(asCell())->value(exec); + return toWTFStringSlowCase(exec); +} + +ALWAYS_INLINE String inlineJSValueNotStringtoString(const JSValue& value, ExecState* exec) +{ + VM& vm = exec->vm(); + if (value.isInt32()) + return vm.numericStrings.add(value.asInt32()); + if (value.isDouble()) + return vm.numericStrings.add(value.asDouble()); + if (value.isTrue()) + return vm.propertyNames->trueKeyword.string(); + if (value.isFalse()) + return vm.propertyNames->falseKeyword.string(); + if (value.isNull()) + return vm.propertyNames->nullKeyword.string(); + if (value.isUndefined()) + return vm.propertyNames->undefinedKeyword.string(); + return value.toString(exec)->value(exec); +} + +ALWAYS_INLINE String JSValue::toWTFStringInline(ExecState* exec) const +{ + if (isString()) + return static_cast<JSString*>(asCell())->value(exec); + + return inlineJSValueNotStringtoString(*this, exec); +} } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSStringBuilder.h b/Source/JavaScriptCore/runtime/JSStringBuilder.h index e7778e4fb..5d4960e89 100644 --- a/Source/JavaScriptCore/runtime/JSStringBuilder.h +++ b/Source/JavaScriptCore/runtime/JSStringBuilder.h @@ -137,8 +137,8 @@ public: } protected: - Vector<LChar, 64> buffer8; - Vector<UChar, 64> buffer16; + Vector<LChar, 64, UnsafeVectorOverflow> buffer8; + Vector<UChar, 64, UnsafeVectorOverflow> buffer16; bool m_okay; bool m_is8Bit; }; diff --git a/Source/JavaScriptCore/runtime/JSStringJoiner.cpp b/Source/JavaScriptCore/runtime/JSStringJoiner.cpp index cbf9ba48b..7e20d2195 100644 --- a/Source/JavaScriptCore/runtime/JSStringJoiner.cpp +++ b/Source/JavaScriptCore/runtime/JSStringJoiner.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,9 +29,9 @@ #include "ExceptionHelpers.h" #include "JSScope.h" #include "JSString.h" +#include "Operations.h" #include <wtf/text/StringImpl.h> - namespace JSC { // The destination is 16bits, at least one string is 16 bits. @@ -94,7 +94,7 @@ static inline PassRefPtr<StringImpl> joinStrings(const Vector<String>& strings, return outputStringImpl.release(); } -JSValue JSStringJoiner::build(ExecState* exec) +JSValue JSStringJoiner::join(ExecState* exec) { if (!m_isValid) return throwOutOfMemoryError(exec); @@ -102,25 +102,29 @@ JSValue JSStringJoiner::build(ExecState* exec) if (!m_strings.size()) return jsEmptyString(exec); - size_t separatorLength = m_separator.length(); + Checked<size_t, RecordOverflow> separatorLength = m_separator.length(); // FIXME: add special cases of joinStrings() for (separatorLength == 0) and (separatorLength == 1). ASSERT(m_strings.size() > 0); - size_t totalSeparactorsLength = separatorLength * (m_strings.size() - 1); - size_t outputStringSize = totalSeparactorsLength + m_cumulatedStringsLength; + Checked<size_t, RecordOverflow> totalSeparactorsLength = separatorLength * (m_strings.size() - 1); + Checked<size_t, RecordOverflow> outputStringSize = totalSeparactorsLength + m_accumulatedStringsLength; + size_t finalSize; + if (outputStringSize.safeGet(finalSize) == CheckedState::DidOverflow) + return throwOutOfMemoryError(exec); + if (!outputStringSize) return jsEmptyString(exec); RefPtr<StringImpl> outputStringImpl; if (m_is8Bits) - outputStringImpl = joinStrings<LChar>(m_strings, m_separator, outputStringSize); + outputStringImpl = joinStrings<LChar>(m_strings, m_separator, finalSize); else - outputStringImpl = joinStrings<UChar>(m_strings, m_separator, outputStringSize); + outputStringImpl = joinStrings<UChar>(m_strings, m_separator, finalSize); if (!outputStringImpl) return throwOutOfMemoryError(exec); - return JSString::create(exec->globalData(), outputStringImpl.release()); + return JSString::create(exec->vm(), outputStringImpl.release()); } } diff --git a/Source/JavaScriptCore/runtime/JSStringJoiner.h b/Source/JavaScriptCore/runtime/JSStringJoiner.h index 5cb841a80..73950c6d7 100644 --- a/Source/JavaScriptCore/runtime/JSStringJoiner.h +++ b/Source/JavaScriptCore/runtime/JSStringJoiner.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,7 +26,7 @@ #ifndef JSStringJoiner_h #define JSStringJoiner_h -#include "JSValue.h" +#include "JSCJSValue.h" #include <wtf/Vector.h> #include <wtf/text/WTFString.h> @@ -40,20 +40,19 @@ public: JSStringJoiner(const String& separator, size_t stringCount); void append(const String&); - JSValue build(ExecState*); + JSValue join(ExecState*); private: String m_separator; Vector<String> m_strings; - unsigned m_cumulatedStringsLength; + Checked<unsigned, RecordOverflow> m_accumulatedStringsLength; bool m_isValid; bool m_is8Bits; }; inline JSStringJoiner::JSStringJoiner(const String& separator, size_t stringCount) : m_separator(separator) - , m_cumulatedStringsLength(0) , m_isValid(true) , m_is8Bits(m_separator.is8Bit()) { @@ -66,9 +65,9 @@ inline void JSStringJoiner::append(const String& str) if (!m_isValid) return; - m_strings.uncheckedAppend(str); + m_strings.append(str); if (!str.isNull()) { - m_cumulatedStringsLength += str.length(); + m_accumulatedStringsLength += str.length(); m_is8Bits = m_is8Bits && str.is8Bit(); } } diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp b/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp index 7dcde4700..16b20d9db 100644 --- a/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp +++ b/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp @@ -32,6 +32,7 @@ #include "JSActivation.h" #include "JSGlobalObject.h" #include "JSNameScope.h" +#include "Operations.h" #include "PropertyNameArray.h" namespace JSC { @@ -70,7 +71,7 @@ void JSSymbolTableObject::getOwnNonIndexPropertyNames(JSObject* object, ExecStat void JSSymbolTableObject::putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned) { - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.h b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h index 913679f80..6db2b88ab 100644 --- a/Source/JavaScriptCore/runtime/JSSymbolTableObject.h +++ b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h @@ -41,7 +41,7 @@ public: SharedSymbolTable* symbolTable() const { return m_symbolTable.get(); } - static NO_RETURN_DUE_TO_ASSERT void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes); + static NO_RETURN_DUE_TO_CRASH void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes); JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName); JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); @@ -49,18 +49,18 @@ public: protected: static const unsigned StructureFlags = IsEnvironmentRecord | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags; - JSSymbolTableObject(JSGlobalData& globalData, Structure* structure, JSScope* scope, SharedSymbolTable* symbolTable = 0) - : Base(globalData, structure, scope) + JSSymbolTableObject(VM& vm, Structure* structure, JSScope* scope, SharedSymbolTable* symbolTable = 0) + : Base(vm, structure, scope) { if (symbolTable) - m_symbolTable.set(globalData, this, symbolTable); + m_symbolTable.set(vm, this, symbolTable); } - void finishCreation(JSGlobalData& globalData) + void finishCreation(VM& vm) { - Base::finishCreation(globalData); + Base::finishCreation(vm); if (!m_symbolTable) - m_symbolTable.set(globalData, this, SharedSymbolTable::create(globalData)); + m_symbolTable.set(vm, this, SharedSymbolTable::create(vm)); } static void visitChildren(JSCell*, SlotVisitor&); @@ -118,7 +118,7 @@ inline bool symbolTablePut( SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName, JSValue value, bool shouldThrow) { - JSGlobalData& globalData = exec->globalData(); + VM& vm = exec->vm(); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object)); SymbolTable& symbolTable = *object->symbolTable(); @@ -135,13 +135,13 @@ inline bool symbolTablePut( } if (UNLIKELY(wasFat)) iter->value.notifyWrite(); - object->registerAt(fastEntry.getIndex()).set(globalData, object, value); + object->registerAt(fastEntry.getIndex()).set(vm, object, value); return true; } template<typename SymbolTableObjectType> inline bool symbolTablePutWithAttributes( - SymbolTableObjectType* object, JSGlobalData& globalData, PropertyName propertyName, + SymbolTableObjectType* object, VM& vm, PropertyName propertyName, JSValue value, unsigned attributes) { ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object)); @@ -153,7 +153,7 @@ inline bool symbolTablePutWithAttributes( ASSERT(!entry.isNull()); entry.notifyWrite(); entry.setAttributes(attributes); - object->registerAt(entry.getIndex()).set(globalData, object, value); + object->registerAt(entry.getIndex()).set(vm, object, value); return true; } diff --git a/Source/JavaScriptCore/runtime/JSTypeInfo.h b/Source/JavaScriptCore/runtime/JSTypeInfo.h index 97fc64c1c..109a032bd 100644 --- a/Source/JavaScriptCore/runtime/JSTypeInfo.h +++ b/Source/JavaScriptCore/runtime/JSTypeInfo.h @@ -47,6 +47,7 @@ namespace JSC { static const unsigned OverridesGetPropertyNames = 1 << 8; static const unsigned ProhibitsPropertyCaching = 1 << 9; static const unsigned HasImpureGetOwnPropertySlot = 1 << 10; + static const unsigned StructureHasRareData = 1 << 11; class TypeInfo { public: @@ -70,6 +71,7 @@ namespace JSC { bool isNumberObject() const { return type() == NumberObjectType; } bool isName() const { return type() == NameInstanceType; } + unsigned flags() const { return (static_cast<unsigned>(m_flags2) << 8) | static_cast<unsigned>(m_flags); } bool masqueradesAsUndefined() const { return isSetOnFlags1(MasqueradesAsUndefined); } bool implementsHasInstance() const { return isSetOnFlags1(ImplementsHasInstance); } bool isEnvironmentRecord() const { return isSetOnFlags1(IsEnvironmentRecord); } @@ -81,6 +83,7 @@ namespace JSC { bool overridesGetPropertyNames() const { return isSetOnFlags2(OverridesGetPropertyNames); } bool prohibitsPropertyCaching() const { return isSetOnFlags2(ProhibitsPropertyCaching); } bool hasImpureGetOwnPropertySlot() const { return isSetOnFlags2(HasImpureGetOwnPropertySlot); } + bool structureHasRareData() const { return isSetOnFlags2(StructureHasRareData); } static ptrdiff_t flagsOffset() { diff --git a/Source/JavaScriptCore/runtime/JSValueInlines.h b/Source/JavaScriptCore/runtime/JSValueInlines.h deleted file mode 100644 index c5a42f67f..000000000 --- a/Source/JavaScriptCore/runtime/JSValueInlines.h +++ /dev/null @@ -1,497 +0,0 @@ -/* - * Copyright (C) 2011 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef JSValueInlines_h -#define JSValueInlines_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::asNumber() const - { - ASSERT(isNumber()); - return isInt32() ? asInt32() : asDouble(); - } - - inline JSValue jsNaN() - { - return JSValue(QNaN); - } - - 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)); - } - - inline EncodedJSValue JSValue::encode(JSValue value) - { - return value.u.asInt64; - } - - inline JSValue JSValue::decode(EncodedJSValue encodedJSValue) - { - JSValue v; - v.u.asInt64 = encodedJSValue; - return v; - } - -#if USE(JSVALUE32_64) - 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); - } - - 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)); - } - - 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::isEmpty() const - { - return tag() == EmptyValueTag; - } - - 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; - } - -#if ENABLE(LLINT_C_LOOP) - inline JSValue::JSValue(int32_t tag, int32_t payload) - { - u.asBits.tag = tag; - u.asBits.payload = payload; - } -#endif - - inline bool JSValue::isNumber() const - { - return isInt32() || isDouble(); - } - - inline bool JSValue::isBoolean() const - { - return isTrue() || isFalse(); - } - - inline bool JSValue::asBoolean() const - { - ASSERT(isBoolean()); - return payload(); - } - -#else // !USE(JSVALUE32_64) i.e. USE(JSVALUE64) - - // 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.asInt64 = reinterpret_cast<uintptr_t>(ptr); - } - - inline JSValue::JSValue(const JSCell* ptr) - { - u.asInt64 = reinterpret_cast<uintptr_t>(const_cast<JSCell*>(ptr)); - } - - inline JSValue::operator bool() const - { - return u.asInt64; - } - - 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::isEmpty() const - { - return u.asInt64 == ValueEmpty; - } - - inline bool JSValue::isUndefined() const - { - return asValue() == JSValue(JSUndefined); - } - - inline bool JSValue::isNull() const - { - return asValue() == JSValue(JSNull); - } - - inline bool JSValue::isTrue() const - { - return asValue() == JSValue(JSTrue); - } - - inline bool JSValue::isFalse() const - { - return asValue() == JSValue(JSFalse); - } - - inline bool JSValue::asBoolean() const - { - ASSERT(isBoolean()); - return asValue() == JSValue(JSTrue); - } - - 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 int64_t reinterpretDoubleToInt64(double value) - { - return bitwise_cast<int64_t>(value); - } - inline double reinterpretInt64ToDouble(int64_t value) - { - return bitwise_cast<double>(value); - } - - ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d) - { - u.asInt64 = reinterpretDoubleToInt64(d) + DoubleEncodeOffset; - } - - inline JSValue::JSValue(int i) - { - u.asInt64 = TagTypeNumber | static_cast<uint32_t>(i); - } - - inline double JSValue::asDouble() const - { - ASSERT(isDouble()); - return reinterpretInt64ToDouble(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 // JSValueInlines_h - diff --git a/Source/JavaScriptCore/runtime/JSVariableObject.cpp b/Source/JavaScriptCore/runtime/JSVariableObject.cpp index 9b03a2c64..fc262f5d8 100644 --- a/Source/JavaScriptCore/runtime/JSVariableObject.cpp +++ b/Source/JavaScriptCore/runtime/JSVariableObject.cpp @@ -29,6 +29,8 @@ #include "config.h" #include "JSVariableObject.h" +#include "Operations.h" + namespace JSC { const ClassInfo JSVariableObject::s_info = { "VariableObject", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSVariableObject) }; diff --git a/Source/JavaScriptCore/runtime/JSVariableObject.h b/Source/JavaScriptCore/runtime/JSVariableObject.h index 3ff7aa841..615aa331f 100644 --- a/Source/JavaScriptCore/runtime/JSVariableObject.h +++ b/Source/JavaScriptCore/runtime/JSVariableObject.h @@ -33,7 +33,6 @@ #include "JSSymbolTableObject.h" #include "Register.h" #include "SymbolTable.h" -#include <wtf/UnusedParam.h> #include <wtf/OwnArrayPtr.h> namespace JSC { @@ -59,13 +58,13 @@ namespace JSC { static const unsigned StructureFlags = Base::StructureFlags; JSVariableObject( - JSGlobalData& globalData, + VM& vm, Structure* structure, Register* registers, JSScope* scope, SharedSymbolTable* symbolTable = 0 ) - : Base(globalData, structure, scope, symbolTable) + : Base(vm, structure, scope, symbolTable) , m_registers(reinterpret_cast<WriteBarrierBase<Unknown>*>(registers)) { } diff --git a/Source/JavaScriptCore/runtime/JSWithScope.cpp b/Source/JavaScriptCore/runtime/JSWithScope.cpp index 7d74e63c3..c0c6c1f7b 100644 --- a/Source/JavaScriptCore/runtime/JSWithScope.cpp +++ b/Source/JavaScriptCore/runtime/JSWithScope.cpp @@ -26,6 +26,8 @@ #include "config.h" #include "JSWithScope.h" +#include "Operations.h" + namespace JSC { const ClassInfo JSWithScope::s_info = { "WithScope", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSWithScope) }; diff --git a/Source/JavaScriptCore/runtime/JSWithScope.h b/Source/JavaScriptCore/runtime/JSWithScope.h index ba2b793a9..ea879cb54 100644 --- a/Source/JavaScriptCore/runtime/JSWithScope.h +++ b/Source/JavaScriptCore/runtime/JSWithScope.h @@ -37,14 +37,14 @@ public: static JSWithScope* create(ExecState* exec, JSObject* object) { JSWithScope* withScope = new (NotNull, allocateCell<JSWithScope>(*exec->heap())) JSWithScope(exec, object); - withScope->finishCreation(exec->globalData()); + withScope->finishCreation(exec->vm()); return withScope; } static JSWithScope* create(ExecState* exec, JSObject* object, JSScope* next) { JSWithScope* withScope = new (NotNull, allocateCell<JSWithScope>(*exec->heap())) JSWithScope(exec, object, next); - withScope->finishCreation(exec->globalData()); + withScope->finishCreation(exec->vm()); return withScope; } @@ -52,9 +52,9 @@ public: static void visitChildren(JSCell*, SlotVisitor&); - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { - return Structure::create(globalData, globalObject, proto, TypeInfo(WithScopeType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, proto, TypeInfo(WithScopeType, StructureFlags), &s_info); } static JS_EXPORTDATA const ClassInfo s_info; @@ -65,21 +65,21 @@ protected: private: JSWithScope(ExecState* exec, JSObject* object) : Base( - exec->globalData(), + exec->vm(), exec->lexicalGlobalObject()->withScopeStructure(), exec->scope() ) - , m_object(exec->globalData(), this, object) + , m_object(exec->vm(), this, object) { } JSWithScope(ExecState* exec, JSObject* object, JSScope* next) : Base( - exec->globalData(), + exec->vm(), exec->lexicalGlobalObject()->withScopeStructure(), next ) - , m_object(exec->globalData(), this, object) + , m_object(exec->vm(), this, object) { } diff --git a/Source/JavaScriptCore/runtime/JSWrapperObject.cpp b/Source/JavaScriptCore/runtime/JSWrapperObject.cpp index ff80c1e20..01961a984 100644 --- a/Source/JavaScriptCore/runtime/JSWrapperObject.cpp +++ b/Source/JavaScriptCore/runtime/JSWrapperObject.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Maks Orlovich - * Copyright (C) 2006, 2009 Apple, Inc. + * Copyright (C) 2006, 2009, 2012 Apple, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -22,6 +22,8 @@ #include "config.h" #include "JSWrapperObject.h" +#include "Operations.h" + namespace JSC { ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSWrapperObject); diff --git a/Source/JavaScriptCore/runtime/JSWrapperObject.h b/Source/JavaScriptCore/runtime/JSWrapperObject.h index 72bc1874c..f1b6d3286 100644 --- a/Source/JavaScriptCore/runtime/JSWrapperObject.h +++ b/Source/JavaScriptCore/runtime/JSWrapperObject.h @@ -32,16 +32,32 @@ namespace JSC { public: typedef JSDestructibleObject Base; + static size_t allocationSize(size_t inlineCapacity) + { + ASSERT_UNUSED(inlineCapacity, !inlineCapacity); + return sizeof(JSWrapperObject); + } + JSValue internalValue() const; - void setInternalValue(JSGlobalData&, JSValue); + void setInternalValue(VM&, JSValue); - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + } + + static ptrdiff_t internalValueOffset() { return OBJECT_OFFSETOF(JSWrapperObject, m_internalValue); } + static ptrdiff_t internalValueCellOffset() + { +#if USE(JSVALUE64) + return internalValueOffset(); +#else + return internalValueOffset() + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload); +#endif } protected: - explicit JSWrapperObject(JSGlobalData&, Structure*); + explicit JSWrapperObject(VM&, Structure*); static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; static void visitChildren(JSCell*, SlotVisitor&); @@ -50,8 +66,8 @@ namespace JSC { WriteBarrier<Unknown> m_internalValue; }; - inline JSWrapperObject::JSWrapperObject(JSGlobalData& globalData, Structure* structure) - : JSDestructibleObject(globalData, structure) + inline JSWrapperObject::JSWrapperObject(VM& vm, Structure* structure) + : JSDestructibleObject(vm, structure) { } @@ -60,11 +76,11 @@ namespace JSC { return m_internalValue.get(); } - inline void JSWrapperObject::setInternalValue(JSGlobalData& globalData, JSValue value) + inline void JSWrapperObject::setInternalValue(VM& vm, JSValue value) { ASSERT(value); ASSERT(!value.isObject()); - m_internalValue.set(globalData, this, value); + m_internalValue.set(vm, this, value); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/LiteralParser.cpp b/Source/JavaScriptCore/runtime/LiteralParser.cpp index bf27327bf..f594518b6 100644 --- a/Source/JavaScriptCore/runtime/LiteralParser.cpp +++ b/Source/JavaScriptCore/runtime/LiteralParser.cpp @@ -32,6 +32,8 @@ #include "JSArray.h" #include "JSString.h" #include "Lexer.h" +#include "ObjectConstructor.h" +#include "Operations.h" #include "StrongInlines.h" #include <wtf/ASCIICType.h> #include <wtf/dtoa.h> @@ -55,22 +57,24 @@ bool LiteralParser<CharType>::tryJSONPParse(Vector<JSONPData>& results, bool nee do { Vector<JSONPPathEntry> path; // Unguarded next to start off the lexer - Identifier name = Identifier(&m_exec->globalData(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start); + Identifier name = Identifier(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start); JSONPPathEntry entry; - if (name == m_exec->globalData().propertyNames->varKeyword) { + if (name == m_exec->vm().propertyNames->varKeyword) { if (m_lexer.next() != TokIdentifier) return false; entry.m_type = JSONPPathEntryTypeDeclare; - entry.m_pathEntryName = Identifier(&m_exec->globalData(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start); + entry.m_pathEntryName = Identifier(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start); path.append(entry); } else { entry.m_type = JSONPPathEntryTypeDot; - entry.m_pathEntryName = Identifier(&m_exec->globalData(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start); + entry.m_pathEntryName = Identifier(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start); path.append(entry); } - if (m_exec->globalData().keywords->isKeyword(entry.m_pathEntryName)) + if (m_exec->vm().keywords->isKeyword(entry.m_pathEntryName)) return false; TokenType tokenType = m_lexer.next(); + if (entry.m_type == JSONPPathEntryTypeDeclare && tokenType != TokAssign) + return false; while (tokenType != TokAssign) { switch (tokenType) { case TokLBracket: { @@ -90,7 +94,7 @@ bool LiteralParser<CharType>::tryJSONPParse(Vector<JSONPData>& results, bool nee entry.m_type = JSONPPathEntryTypeDot; if (m_lexer.next() != TokIdentifier) return false; - entry.m_pathEntryName = Identifier(&m_exec->globalData(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start); + entry.m_pathEntryName = Identifier(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start); break; } case TokLParen: { @@ -109,7 +113,7 @@ bool LiteralParser<CharType>::tryJSONPParse(Vector<JSONPData>& results, bool nee startJSON: m_lexer.next(); results.append(JSONPData()); - results.last().m_value.set(m_exec->globalData(), parse(StartParseExpression)); + results.last().m_value.set(m_exec->vm(), parse(StartParseExpression)); if (!results.last().m_value) return false; results.last().m_path.swap(path); @@ -129,19 +133,19 @@ template <typename CharType> ALWAYS_INLINE const Identifier LiteralParser<CharType>::makeIdentifier(const LChar* characters, size_t length) { if (!length) - return m_exec->globalData().propertyNames->emptyIdentifier; + return m_exec->vm().propertyNames->emptyIdentifier; if (characters[0] >= MaximumCachableCharacter) - return Identifier(&m_exec->globalData(), characters, length); + return Identifier(&m_exec->vm(), characters, length); if (length == 1) { if (!m_shortIdentifiers[characters[0]].isNull()) return m_shortIdentifiers[characters[0]]; - m_shortIdentifiers[characters[0]] = Identifier(&m_exec->globalData(), characters, length); + m_shortIdentifiers[characters[0]] = Identifier(&m_exec->vm(), characters, length); return m_shortIdentifiers[characters[0]]; } if (!m_recentIdentifiers[characters[0]].isNull() && Identifier::equal(m_recentIdentifiers[characters[0]].impl(), characters, length)) return m_recentIdentifiers[characters[0]]; - m_recentIdentifiers[characters[0]] = Identifier(&m_exec->globalData(), characters, length); + m_recentIdentifiers[characters[0]] = Identifier(&m_exec->vm(), characters, length); return m_recentIdentifiers[characters[0]]; } @@ -149,19 +153,19 @@ template <typename CharType> ALWAYS_INLINE const Identifier LiteralParser<CharType>::makeIdentifier(const UChar* characters, size_t length) { if (!length) - return m_exec->globalData().propertyNames->emptyIdentifier; + return m_exec->vm().propertyNames->emptyIdentifier; if (characters[0] >= MaximumCachableCharacter) - return Identifier(&m_exec->globalData(), characters, length); + return Identifier(&m_exec->vm(), characters, length); if (length == 1) { if (!m_shortIdentifiers[characters[0]].isNull()) return m_shortIdentifiers[characters[0]]; - m_shortIdentifiers[characters[0]] = Identifier(&m_exec->globalData(), characters, length); + m_shortIdentifiers[characters[0]] = Identifier(&m_exec->vm(), characters, length); return m_shortIdentifiers[characters[0]]; } if (!m_recentIdentifiers[characters[0]].isNull() && Identifier::equal(m_recentIdentifiers[characters[0]].impl(), characters, length)) return m_recentIdentifiers[characters[0]]; - m_recentIdentifiers[characters[0]] = Identifier(&m_exec->globalData(), characters, length); + m_recentIdentifiers[characters[0]] = Identifier(&m_exec->vm(), characters, length); return m_recentIdentifiers[characters[0]]; } @@ -542,8 +546,8 @@ JSValue LiteralParser<CharType>::parse(ParserState initialState) ParserState state = initialState; MarkedArgumentBuffer objectStack; JSValue lastValue; - Vector<ParserState, 16> stateStack; - Vector<Identifier, 16> identifierStack; + Vector<ParserState, 16, UnsafeVectorOverflow> stateStack; + Vector<Identifier, 16, UnsafeVectorOverflow> identifierStack; while (1) { switch(state) { startParseArray: @@ -649,7 +653,7 @@ JSValue LiteralParser<CharType>::parse(ParserState initialState) if (i != PropertyName::NotAnIndex) object->putDirectIndex(m_exec, i, lastValue); else - object->putDirect(m_exec->globalData(), ident, lastValue); + object->putDirect(m_exec->vm(), ident, lastValue); identifierStack.removeLast(); if (m_lexer.currentToken().type == TokComma) goto doParseObjectStartExpression; @@ -814,7 +818,7 @@ JSValue LiteralParser<CharType>::parse(ParserState initialState) return JSValue(); } default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } if (stateStack.isEmpty()) return lastValue; diff --git a/Source/JavaScriptCore/runtime/LiteralParser.h b/Source/JavaScriptCore/runtime/LiteralParser.h index c0f308ee5..fac97571c 100644 --- a/Source/JavaScriptCore/runtime/LiteralParser.h +++ b/Source/JavaScriptCore/runtime/LiteralParser.h @@ -27,8 +27,8 @@ #define LiteralParser_h #include "Identifier.h" +#include "JSCJSValue.h" #include "JSGlobalObjectFunctions.h" -#include "JSValue.h" #include <wtf/text/WTFString.h> namespace JSC { diff --git a/Source/JavaScriptCore/runtime/Lookup.cpp b/Source/JavaScriptCore/runtime/Lookup.cpp index a6a349974..030aef5a5 100644 --- a/Source/JavaScriptCore/runtime/Lookup.cpp +++ b/Source/JavaScriptCore/runtime/Lookup.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2012 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,10 +22,11 @@ #include "Executable.h" #include "JSFunction.h" +#include "Operations.h" namespace JSC { -void HashTable::createTable(JSGlobalData* globalData) const +void HashTable::createTable(VM* vm) const { ASSERT(!table); int linkIndex = compactHashSizeMask + 1; @@ -33,7 +34,7 @@ void HashTable::createTable(JSGlobalData* globalData) const for (int i = 0; i < compactSize; ++i) entries[i].setKey(0); for (int i = 0; values[i].key; ++i) { - StringImpl* identifier = Identifier::add(globalData, values[i].key).leakRef(); + StringImpl* identifier = Identifier::add(vm, values[i].key).leakRef(); int hashIndex = identifier->existingHash() & compactHashSizeMask; HashEntry* entry = &entries[hashIndex]; @@ -68,23 +69,22 @@ bool setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* { ASSERT(thisObj->globalObject()); ASSERT(entry->attributes() & Function); - WriteBarrierBase<Unknown>* location = thisObj->getDirectLocation(exec->globalData(), propertyName); + PropertyOffset offset = thisObj->getDirectOffset(exec->vm(), propertyName); - if (!location) { + if (!isValidOffset(offset)) { // If a property is ever deleted from an object with a static table, then we reify // all static functions at that time - after this we shouldn't be re-adding anything. if (thisObj->staticFunctionsReified()) return false; - StringImpl* name = propertyName.publicName(); - ASSERT(name); - - JSFunction* function = JSFunction::create(exec, thisObj->globalObject(), entry->functionLength(), name, entry->function(), entry->intrinsic()); - thisObj->putDirect(exec->globalData(), propertyName, function, entry->attributes()); - location = thisObj->getDirectLocation(exec->globalData(), propertyName); + thisObj->putDirectNativeFunction( + exec, thisObj->globalObject(), propertyName, entry->functionLength(), + entry->function(), entry->intrinsic(), entry->attributes()); + offset = thisObj->getDirectOffset(exec->vm(), propertyName); + ASSERT(isValidOffset(offset)); } - slot.setValue(thisObj, location->get(), thisObj->offsetForLocation(location)); + slot.setValue(thisObj, thisObj->getDirect(offset), offset); return true; } diff --git a/Source/JavaScriptCore/runtime/Lookup.h b/Source/JavaScriptCore/runtime/Lookup.h index ccb08128d..c90ceae7c 100644 --- a/Source/JavaScriptCore/runtime/Lookup.h +++ b/Source/JavaScriptCore/runtime/Lookup.h @@ -53,7 +53,7 @@ namespace JSC { m_attributes = attributes; m_u.store.value1 = v1; m_u.store.value2 = v2; - m_u.function.intrinsic = intrinsic; + m_intrinsic = intrinsic; m_next = 0; } @@ -65,7 +65,7 @@ namespace JSC { Intrinsic intrinsic() const { ASSERT(m_attributes & Function); - return m_u.function.intrinsic; + return m_intrinsic; } NativeFunction function() const { ASSERT(m_attributes & Function); return m_u.function.functionValue; } @@ -82,6 +82,7 @@ namespace JSC { private: StringImpl* m_key; unsigned char m_attributes; // JSObject attributes + Intrinsic m_intrinsic; union { struct { @@ -91,7 +92,6 @@ namespace JSC { struct { NativeFunction functionValue; intptr_t length; // number of arguments for function - Intrinsic intrinsic; } function; struct { GetFunction get; @@ -121,24 +121,24 @@ namespace JSC { return result; } - ALWAYS_INLINE void initializeIfNeeded(JSGlobalData* globalData) const + ALWAYS_INLINE void initializeIfNeeded(VM* vm) const { if (!table) - createTable(globalData); + createTable(vm); } ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const { if (!table) - createTable(&exec->globalData()); + createTable(&exec->vm()); } JS_EXPORT_PRIVATE void deleteTable() const; // Find an entry in the table, and return the entry. - ALWAYS_INLINE const HashEntry* entry(JSGlobalData* globalData, PropertyName identifier) const + ALWAYS_INLINE const HashEntry* entry(VM* vm, PropertyName identifier) const { - initializeIfNeeded(globalData); + initializeIfNeeded(vm); return entry(identifier); } @@ -194,14 +194,14 @@ namespace JSC { int m_position; }; - ConstIterator begin(JSGlobalData& globalData) const + ConstIterator begin(VM& vm) const { - initializeIfNeeded(&globalData); + initializeIfNeeded(&vm); return ConstIterator(this, 0); } - ConstIterator end(JSGlobalData& globalData) const + ConstIterator end(VM& vm) const { - initializeIfNeeded(&globalData); + initializeIfNeeded(&vm); return ConstIterator(this, compactSize); } @@ -229,7 +229,7 @@ namespace JSC { } // Convert the hash table keys to identifiers. - JS_EXPORT_PRIVATE void createTable(JSGlobalData*) const; + JS_EXPORT_PRIVATE void createTable(VM*) const; }; JS_EXPORT_PRIVATE bool setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, PropertyName, PropertySlot&); @@ -353,6 +353,18 @@ namespace JSC { return true; } + template <class ThisImp> + inline void putEntry(ExecState* exec, const HashEntry* entry, PropertyName propertyName, JSValue value, ThisImp* thisObj, bool shouldThrow = false) + { + // If this is a function put it as an override property. + if (entry->attributes() & Function) + thisObj->putDirect(exec->vm(), propertyName, value); + else if (!(entry->attributes() & ReadOnly)) + entry->propertyPutter()(exec, thisObj, value); + else if (shouldThrow) + throwTypeError(exec, StrictModeReadonlyPropertyWriteError); + } + /** * This one is for "put". * It looks up a hash entry for the property to be set. If an entry @@ -366,14 +378,7 @@ namespace JSC { if (!entry) return false; - // If this is a function put it as an override property. - if (entry->attributes() & Function) - thisObj->putDirect(exec->globalData(), propertyName, value); - else if (!(entry->attributes() & ReadOnly)) - entry->propertyPutter()(exec, thisObj, value); - else if (shouldThrow) - throwTypeError(exec, StrictModeReadonlyPropertyWriteError); - + putEntry<ThisImp>(exec, entry, propertyName, value, thisObj, shouldThrow); return true; } diff --git a/Source/JavaScriptCore/runtime/MathObject.cpp b/Source/JavaScriptCore/runtime/MathObject.cpp index 7634487ad..71c53a3e4 100644 --- a/Source/JavaScriptCore/runtime/MathObject.cpp +++ b/Source/JavaScriptCore/runtime/MathObject.cpp @@ -52,6 +52,7 @@ static EncodedJSValue JSC_HOST_CALL mathProtoFuncRound(ExecState*); static EncodedJSValue JSC_HOST_CALL mathProtoFuncSin(ExecState*); static EncodedJSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState*); static EncodedJSValue JSC_HOST_CALL mathProtoFuncTan(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncIMul(ExecState*); } @@ -81,27 +82,28 @@ const ClassInfo MathObject::s_info = { "Math", &Base::s_info, 0, ExecState::math sin mathProtoFuncSin DontEnum|Function 1 sqrt mathProtoFuncSqrt DontEnum|Function 1 tan mathProtoFuncTan DontEnum|Function 1 + imul mathProtoFuncIMul DontEnum|Function 2 @end */ MathObject::MathObject(JSGlobalObject* globalObject, Structure* structure) - : JSNonFinalObject(globalObject->globalData(), structure) + : JSNonFinalObject(globalObject->vm(), structure) { } void MathObject::finishCreation(ExecState* exec, JSGlobalObject* globalObject) { - Base::finishCreation(globalObject->globalData()); + Base::finishCreation(globalObject->vm()); 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(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); + putDirectWithoutTransition(exec->vm(), Identifier(exec, "E"), jsNumber(exp(1.0)), DontDelete | DontEnum | ReadOnly); + putDirectWithoutTransition(exec->vm(), Identifier(exec, "LN2"), jsNumber(log(2.0)), DontDelete | DontEnum | ReadOnly); + putDirectWithoutTransition(exec->vm(), Identifier(exec, "LN10"), jsNumber(log(10.0)), DontDelete | DontEnum | ReadOnly); + putDirectWithoutTransition(exec->vm(), Identifier(exec, "LOG2E"), jsNumber(1.0 / log(2.0)), DontDelete | DontEnum | ReadOnly); + putDirectWithoutTransition(exec->vm(), Identifier(exec, "LOG10E"), jsNumber(0.4342944819032518), DontDelete | DontEnum | ReadOnly); // See ECMA-262 15.8.1.5 + putDirectWithoutTransition(exec->vm(), Identifier(exec, "PI"), jsNumber(piDouble), DontDelete | DontEnum | ReadOnly); + putDirectWithoutTransition(exec->vm(), Identifier(exec, "SQRT1_2"), jsNumber(sqrt(0.5)), DontDelete | DontEnum | ReadOnly); + putDirectWithoutTransition(exec->vm(), Identifier(exec, "SQRT2"), jsNumber(sqrt(2.0)), DontDelete | DontEnum | ReadOnly); } bool MathObject::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot &slot) @@ -174,11 +176,11 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncMax(ExecState* exec) double result = -std::numeric_limits<double>::infinity(); for (unsigned k = 0; k < argsCount; ++k) { double val = exec->argument(k).toNumber(exec); - if (isnan(val)) { + if (std::isnan(val)) { result = QNaN; break; } - if (val > result || (val == 0 && result == 0 && !signbit(val))) + if (val > result || (!val && !result && !std::signbit(val))) result = val; } return JSValue::encode(jsNumber(result)); @@ -190,11 +192,11 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncMin(ExecState* exec) double result = +std::numeric_limits<double>::infinity(); for (unsigned k = 0; k < argsCount; ++k) { double val = exec->argument(k).toNumber(exec); - if (isnan(val)) { + if (std::isnan(val)) { result = QNaN; break; } - if (val < result || (val == 0 && result == 0 && signbit(val))) + if (val < result || (!val && !result && std::signbit(val))) result = val; } return JSValue::encode(jsNumber(result)); @@ -244,9 +246,9 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState* exec) double arg = exec->argument(0).toNumber(exec); double arg2 = exec->argument(1).toNumber(exec); - if (isnan(arg2)) + if (std::isnan(arg2)) return JSValue::encode(jsNaN()); - if (isinf(arg2) && fabs(arg) == 1) + if (std::isinf(arg2) && fabs(arg) == 1) return JSValue::encode(jsNaN()); return JSValue::encode(jsNumber(mathPow(arg, arg2))); } @@ -265,7 +267,7 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncRound(ExecState* exec) EncodedJSValue JSC_HOST_CALL mathProtoFuncSin(ExecState* exec) { - return JSValue::encode(exec->globalData().cachedSin(exec->argument(0).toNumber(exec))); + return JSValue::encode(exec->vm().cachedSin(exec->argument(0).toNumber(exec))); } EncodedJSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState* exec) @@ -278,6 +280,15 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncTan(ExecState* exec) return JSValue::encode(jsDoubleNumber(tan(exec->argument(0).toNumber(exec)))); } +EncodedJSValue JSC_HOST_CALL mathProtoFuncIMul(ExecState* exec) +{ + int32_t left = exec->argument(0).toInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsNull()); + int32_t right = exec->argument(1).toInt32(exec); + return JSValue::encode(jsNumber(left * right)); +} + #if PLATFORM(IOS) && CPU(ARM_THUMB2) // The following code is taken from netlib.org: diff --git a/Source/JavaScriptCore/runtime/MathObject.h b/Source/JavaScriptCore/runtime/MathObject.h index f4082f087..190614b84 100644 --- a/Source/JavaScriptCore/runtime/MathObject.h +++ b/Source/JavaScriptCore/runtime/MathObject.h @@ -43,9 +43,9 @@ namespace JSC { static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } protected: diff --git a/Source/JavaScriptCore/runtime/MemoryStatistics.cpp b/Source/JavaScriptCore/runtime/MemoryStatistics.cpp index 0f8efc604..5459ff3db 100644 --- a/Source/JavaScriptCore/runtime/MemoryStatistics.cpp +++ b/Source/JavaScriptCore/runtime/MemoryStatistics.cpp @@ -27,7 +27,7 @@ #include "MemoryStatistics.h" #include "ExecutableAllocator.h" -#include "JSGlobalData.h" +#include "VM.h" #include "JSStack.h" namespace JSC { diff --git a/Source/JavaScriptCore/runtime/MemoryStatistics.h b/Source/JavaScriptCore/runtime/MemoryStatistics.h index 9a86df296..79cec9c21 100644 --- a/Source/JavaScriptCore/runtime/MemoryStatistics.h +++ b/Source/JavaScriptCore/runtime/MemoryStatistics.h @@ -28,7 +28,7 @@ #include "Heap.h" -class JSGlobalData; +class VM; namespace JSC { diff --git a/Source/JavaScriptCore/runtime/NameConstructor.cpp b/Source/JavaScriptCore/runtime/NameConstructor.cpp index b5facc7cf..e6f85693a 100644 --- a/Source/JavaScriptCore/runtime/NameConstructor.cpp +++ b/Source/JavaScriptCore/runtime/NameConstructor.cpp @@ -28,6 +28,7 @@ #include "JSGlobalObject.h" #include "NamePrototype.h" +#include "Operations.h" namespace JSC { @@ -42,15 +43,15 @@ NameConstructor::NameConstructor(JSGlobalObject* globalObject, Structure* struct void NameConstructor::finishCreation(ExecState* exec, NamePrototype* prototype) { - Base::finishCreation(exec->globalData(), prototype->classInfo()->className); - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, prototype, DontEnum | DontDelete | ReadOnly); - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), DontDelete | ReadOnly | DontEnum); + Base::finishCreation(exec->vm(), prototype->classInfo()->className); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().prototype, prototype, DontEnum | DontDelete | ReadOnly); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().length, jsNumber(1), DontDelete | ReadOnly | DontEnum); } static EncodedJSValue JSC_HOST_CALL constructPrivateName(ExecState* exec) { JSValue publicName = exec->argumentCount() ? exec->argument(0) : jsUndefined(); - return JSValue::encode(NameInstance::create(exec->globalData(), exec->lexicalGlobalObject()->privateNameStructure(), publicName.toString(exec))); + return JSValue::encode(NameInstance::create(exec->vm(), exec->lexicalGlobalObject()->privateNameStructure(), publicName.toString(exec))); } ConstructType NameConstructor::getConstructData(JSCell*, ConstructData& constructData) diff --git a/Source/JavaScriptCore/runtime/NameConstructor.h b/Source/JavaScriptCore/runtime/NameConstructor.h index 16c5eef68..b7a52e402 100644 --- a/Source/JavaScriptCore/runtime/NameConstructor.h +++ b/Source/JavaScriptCore/runtime/NameConstructor.h @@ -46,9 +46,9 @@ public: static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } protected: diff --git a/Source/JavaScriptCore/runtime/NameInstance.cpp b/Source/JavaScriptCore/runtime/NameInstance.cpp index f257243e8..dbbf0e2f6 100644 --- a/Source/JavaScriptCore/runtime/NameInstance.cpp +++ b/Source/JavaScriptCore/runtime/NameInstance.cpp @@ -27,15 +27,16 @@ #include "NameInstance.h" #include "JSScope.h" +#include "Operations.h" namespace JSC { const ClassInfo NameInstance::s_info = { "Name", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(NameInstance) }; -NameInstance::NameInstance(JSGlobalData& globalData, Structure* structure, JSString* nameString) - : Base(globalData, structure) +NameInstance::NameInstance(VM& vm, Structure* structure, JSString* nameString) + : Base(vm, structure) { - m_nameString.set(globalData, this, nameString); + m_nameString.set(vm, this, nameString); } void NameInstance::destroy(JSCell* cell) diff --git a/Source/JavaScriptCore/runtime/NameInstance.h b/Source/JavaScriptCore/runtime/NameInstance.h index 129e7c407..e5aa79d97 100644 --- a/Source/JavaScriptCore/runtime/NameInstance.h +++ b/Source/JavaScriptCore/runtime/NameInstance.h @@ -37,15 +37,15 @@ public: static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(NameInstanceType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(NameInstanceType, StructureFlags), &s_info); } - static NameInstance* create(JSGlobalData& globalData, Structure* structure, JSString* nameString) + static NameInstance* create(VM& vm, Structure* structure, JSString* nameString) { - NameInstance* name = new (NotNull, allocateCell<NameInstance>(globalData.heap)) NameInstance(globalData, structure, nameString); - name->finishCreation(globalData); + NameInstance* name = new (NotNull, allocateCell<NameInstance>(vm.heap)) NameInstance(vm, structure, nameString); + name->finishCreation(vm); return name; } @@ -55,11 +55,11 @@ public: protected: static void destroy(JSCell*); - NameInstance(JSGlobalData&, Structure*, JSString*); + NameInstance(VM&, Structure*, JSString*); - void finishCreation(JSGlobalData& globalData) + void finishCreation(VM& vm) { - Base::finishCreation(globalData); + Base::finishCreation(vm); ASSERT(inherits(&s_info)); } diff --git a/Source/JavaScriptCore/runtime/NamePrototype.cpp b/Source/JavaScriptCore/runtime/NamePrototype.cpp index f14e58522..a3b55fe74 100644 --- a/Source/JavaScriptCore/runtime/NamePrototype.cpp +++ b/Source/JavaScriptCore/runtime/NamePrototype.cpp @@ -27,6 +27,7 @@ #include "NamePrototype.h" #include "Error.h" +#include "Operations.h" namespace JSC { @@ -47,13 +48,13 @@ const ClassInfo NamePrototype::s_info = { "Name", &Base::s_info, 0, ExecState::p */ NamePrototype::NamePrototype(ExecState* exec, Structure* structure) - : Base(exec->globalData(), structure, jsEmptyString(exec)) + : Base(exec->vm(), structure, jsEmptyString(exec)) { } void NamePrototype::finishCreation(ExecState* exec) { - Base::finishCreation(exec->globalData()); + Base::finishCreation(exec->vm()); ASSERT(inherits(&s_info)); } diff --git a/Source/JavaScriptCore/runtime/NamePrototype.h b/Source/JavaScriptCore/runtime/NamePrototype.h index 5d86decfd..a3abf330b 100644 --- a/Source/JavaScriptCore/runtime/NamePrototype.h +++ b/Source/JavaScriptCore/runtime/NamePrototype.h @@ -43,9 +43,9 @@ public: static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(NameInstanceType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(NameInstanceType, StructureFlags), &s_info); } protected: diff --git a/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp b/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp index 1f1730805..929cc8cb2 100644 --- a/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp +++ b/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp @@ -25,6 +25,7 @@ #include "JSFunction.h" #include "JSString.h" #include "NativeErrorPrototype.h" +#include "Operations.h" namespace JSC { diff --git a/Source/JavaScriptCore/runtime/NativeErrorConstructor.h b/Source/JavaScriptCore/runtime/NativeErrorConstructor.h index 8db237028..0a6ef6ec1 100644 --- a/Source/JavaScriptCore/runtime/NativeErrorConstructor.h +++ b/Source/JavaScriptCore/runtime/NativeErrorConstructor.h @@ -43,9 +43,9 @@ namespace JSC { static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } Structure* errorStructure() { return m_errorStructure.get(); } @@ -53,14 +53,14 @@ namespace JSC { protected: void finishCreation(ExecState* exec, JSGlobalObject* globalObject, Structure* prototypeStructure, const String& name) { - Base::finishCreation(exec->globalData(), name); + Base::finishCreation(exec->vm(), name); ASSERT(inherits(&s_info)); NativeErrorPrototype* prototype = NativeErrorPrototype::create(exec, globalObject, prototypeStructure, name, 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.set(exec->globalData(), this, ErrorInstance::createStructure(exec->globalData(), globalObject, prototype)); + putDirect(exec->vm(), exec->propertyNames().length, jsNumber(1), DontDelete | ReadOnly | DontEnum); // ECMA 15.11.7.5 + putDirect(exec->vm(), exec->propertyNames().prototype, prototype, DontDelete | ReadOnly | DontEnum); + m_errorStructure.set(exec->vm(), this, ErrorInstance::createStructure(exec->vm(), globalObject, prototype)); ASSERT(m_errorStructure); ASSERT(m_errorStructure->isObject()); } diff --git a/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp b/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp index 296a86a22..c33ac3d92 100644 --- a/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp +++ b/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp @@ -24,6 +24,7 @@ #include "JSGlobalObject.h" #include "JSString.h" #include "NativeErrorConstructor.h" +#include "Operations.h" namespace JSC { @@ -35,9 +36,9 @@ NativeErrorPrototype::NativeErrorPrototype(ExecState* exec, Structure* structure void NativeErrorPrototype::finishCreation(ExecState* exec, JSGlobalObject* globalObject, const WTF::String& nameAndMessage, NativeErrorConstructor* constructor) { Base::finishCreation(exec, globalObject); - putDirect(exec->globalData(), exec->propertyNames().name, jsString(exec, nameAndMessage), DontEnum); - putDirect(exec->globalData(), exec->propertyNames().message, jsEmptyString(exec), DontEnum); - putDirect(exec->globalData(), exec->propertyNames().constructor, constructor, DontEnum); + putDirect(exec->vm(), exec->propertyNames().name, jsString(exec, nameAndMessage), DontEnum); + putDirect(exec->vm(), exec->propertyNames().message, jsEmptyString(exec), DontEnum); + putDirect(exec->vm(), exec->propertyNames().constructor, constructor, DontEnum); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/NumberConstructor.cpp b/Source/JavaScriptCore/runtime/NumberConstructor.cpp index daa643da7..14e149dcf 100644 --- a/Source/JavaScriptCore/runtime/NumberConstructor.cpp +++ b/Source/JavaScriptCore/runtime/NumberConstructor.cpp @@ -25,6 +25,7 @@ #include "Lookup.h" #include "NumberObject.h" #include "NumberPrototype.h" +#include "Operations.h" namespace JSC { @@ -61,14 +62,14 @@ NumberConstructor::NumberConstructor(JSGlobalObject* globalObject, Structure* st void NumberConstructor::finishCreation(ExecState* exec, NumberPrototype* numberPrototype) { - Base::finishCreation(exec->globalData(), numberPrototype->s_info.className); + Base::finishCreation(exec->vm(), numberPrototype->s_info.className); ASSERT(inherits(&s_info)); // Number.Prototype - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, numberPrototype, DontEnum | DontDelete | ReadOnly); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().prototype, numberPrototype, DontEnum | DontDelete | ReadOnly); // no. of arguments for constructor - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontEnum | DontDelete); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontEnum | DontDelete); } bool NumberConstructor::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot) @@ -114,9 +115,9 @@ static JSValue numberConstructorMinValue(ExecState*, JSValue, PropertyName) // ECMA 15.7.1 static EncodedJSValue JSC_HOST_CALL constructWithNumberConstructor(ExecState* exec) { - NumberObject* object = NumberObject::create(exec->globalData(), asInternalFunction(exec->callee())->globalObject()->numberObjectStructure()); + NumberObject* object = NumberObject::create(exec->vm(), asInternalFunction(exec->callee())->globalObject()->numberObjectStructure()); double n = exec->argumentCount() ? exec->argument(0).toNumber(exec) : 0; - object->setInternalValue(exec->globalData(), jsNumber(n)); + object->setInternalValue(exec->vm(), jsNumber(n)); return JSValue::encode(object); } diff --git a/Source/JavaScriptCore/runtime/NumberConstructor.h b/Source/JavaScriptCore/runtime/NumberConstructor.h index 75f55f88e..45883ede1 100644 --- a/Source/JavaScriptCore/runtime/NumberConstructor.h +++ b/Source/JavaScriptCore/runtime/NumberConstructor.h @@ -46,9 +46,9 @@ namespace JSC { static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { - return Structure::create(globalData, globalObject, proto, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), &s_info); } enum { NaNValue, NegInfinity, PosInfinity, MaxValue, MinValue }; diff --git a/Source/JavaScriptCore/runtime/NumberObject.cpp b/Source/JavaScriptCore/runtime/NumberObject.cpp index b87753d4d..05349ef31 100644 --- a/Source/JavaScriptCore/runtime/NumberObject.cpp +++ b/Source/JavaScriptCore/runtime/NumberObject.cpp @@ -24,6 +24,7 @@ #include "JSGlobalObject.h" #include "NumberPrototype.h" +#include "Operations.h" namespace JSC { @@ -31,21 +32,21 @@ ASSERT_HAS_TRIVIAL_DESTRUCTOR(NumberObject); const ClassInfo NumberObject::s_info = { "Number", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(NumberObject) }; -NumberObject::NumberObject(JSGlobalData& globalData, Structure* structure) - : JSWrapperObject(globalData, structure) +NumberObject::NumberObject(VM& vm, Structure* structure) + : JSWrapperObject(vm, structure) { } -void NumberObject::finishCreation(JSGlobalData& globalData) +void NumberObject::finishCreation(VM& vm) { - Base::finishCreation(globalData); + Base::finishCreation(vm); ASSERT(inherits(&s_info)); } NumberObject* constructNumber(ExecState* exec, JSGlobalObject* globalObject, JSValue number) { - NumberObject* object = NumberObject::create(exec->globalData(), globalObject->numberObjectStructure()); - object->setInternalValue(exec->globalData(), number); + NumberObject* object = NumberObject::create(exec->vm(), globalObject->numberObjectStructure()); + object->setInternalValue(exec->vm(), number); return object; } diff --git a/Source/JavaScriptCore/runtime/NumberObject.h b/Source/JavaScriptCore/runtime/NumberObject.h index ed84207d9..1c7c8982b 100644 --- a/Source/JavaScriptCore/runtime/NumberObject.h +++ b/Source/JavaScriptCore/runtime/NumberObject.h @@ -27,24 +27,24 @@ namespace JSC { class NumberObject : public JSWrapperObject { protected: - NumberObject(JSGlobalData&, Structure*); - void finishCreation(JSGlobalData&); + NumberObject(VM&, Structure*); + void finishCreation(VM&); public: typedef JSWrapperObject Base; - static NumberObject* create(JSGlobalData& globalData, Structure* structure) + static NumberObject* create(VM& vm, Structure* structure) { - NumberObject* number = new (NotNull, allocateCell<NumberObject>(globalData.heap)) NumberObject(globalData, structure); - number->finishCreation(globalData); + NumberObject* number = new (NotNull, allocateCell<NumberObject>(vm.heap)) NumberObject(vm, structure); + number->finishCreation(vm); return number; } static JS_EXPORTDATA const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(NumberObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(NumberObjectType, StructureFlags), &s_info); } }; diff --git a/Source/JavaScriptCore/runtime/NumberPrototype.cpp b/Source/JavaScriptCore/runtime/NumberPrototype.cpp index 23c9dbfdd..54a947303 100644 --- a/Source/JavaScriptCore/runtime/NumberPrototype.cpp +++ b/Source/JavaScriptCore/runtime/NumberPrototype.cpp @@ -71,14 +71,14 @@ const ClassInfo NumberPrototype::s_info = { "Number", &NumberObject::s_info, 0, ASSERT_HAS_TRIVIAL_DESTRUCTOR(NumberPrototype); NumberPrototype::NumberPrototype(ExecState* exec, Structure* structure) - : NumberObject(exec->globalData(), structure) + : NumberObject(exec->vm(), structure) { } void NumberPrototype::finishCreation(ExecState* exec, JSGlobalObject*) { - Base::finishCreation(exec->globalData()); - setInternalValue(exec->globalData(), jsNumber(0)); + Base::finishCreation(exec->vm()); + setInternalValue(exec->vm(), jsNumber(0)); ASSERT(inherits(&s_info)); } @@ -151,7 +151,7 @@ static const char radixDigits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; static char* toStringWithRadix(RadixBuffer& buffer, double number, unsigned radix) { - ASSERT(isfinite(number)); + ASSERT(std::isfinite(number)); ASSERT(radix >= 2 && radix <= 36); // Position the decimal point at the center of the string, set @@ -161,7 +161,7 @@ static char* toStringWithRadix(RadixBuffer& buffer, double number, unsigned radi // Extract the sign. bool isNegative = number < 0; - if (signbit(number)) + if (std::signbit(number)) number = -number; double integerPart = floor(number); @@ -198,12 +198,12 @@ static char* toStringWithRadix(RadixBuffer& buffer, double number, unsigned radi // Calculate the delta from the current number to the next & previous possible IEEE numbers. double nextNumber = nextafter(number, std::numeric_limits<double>::infinity()); double lastNumber = nextafter(number, -std::numeric_limits<double>::infinity()); - ASSERT(isfinite(nextNumber) && !signbit(nextNumber)); - ASSERT(isfinite(lastNumber) && !signbit(lastNumber)); + ASSERT(std::isfinite(nextNumber) && !std::signbit(nextNumber)); + ASSERT(std::isfinite(lastNumber) && !std::signbit(lastNumber)); double deltaNextDouble = nextNumber - number; double deltaLastDouble = number - lastNumber; - ASSERT(isfinite(deltaNextDouble) && !signbit(deltaNextDouble)); - ASSERT(isfinite(deltaLastDouble) && !signbit(deltaLastDouble)); + ASSERT(std::isfinite(deltaNextDouble) && !std::signbit(deltaNextDouble)); + ASSERT(std::isfinite(deltaLastDouble) && !std::signbit(deltaLastDouble)); // We track the delta from the current value to the next, to track how many digits of the // fraction we need to write. For example, if the value we are converting is precisely @@ -380,7 +380,7 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState* exec) return throwVMError(exec, createRangeError(exec, ASCIILiteral("toExponential() argument must be between 0 and 20"))); // Handle NaN and Infinity. - if (!isfinite(x)) + if (!std::isfinite(x)) return JSValue::encode(jsString(exec, String::numberToStringECMAScript(x))); // Round if the argument is not undefined, always format as exponential. @@ -418,7 +418,7 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec) // The check above will return false for NaN or Infinity, these will be // handled by numberToString. - ASSERT(isfinite(x)); + ASSERT(std::isfinite(x)); NumberToStringBuffer buffer; return JSValue::encode(jsString(exec, String(numberToFixedWidthString(x, decimalPlaces, buffer)))); @@ -448,7 +448,7 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec) return JSValue::encode(jsString(exec, String::numberToStringECMAScript(x))); // Handle NaN and Infinity. - if (!isfinite(x)) + if (!std::isfinite(x)) return JSValue::encode(jsString(exec, String::numberToStringECMAScript(x))); NumberToStringBuffer buffer; @@ -475,13 +475,13 @@ static inline EncodedJSValue integerValueToString(ExecState* exec, int32_t radix if (static_cast<unsigned>(value) < static_cast<unsigned>(radix)) { ASSERT(value <= 36); ASSERT(value >= 0); - JSGlobalData* globalData = &exec->globalData(); - return JSValue::encode(globalData->smallStrings.singleCharacterString(globalData, radixDigits[value])); + VM* vm = &exec->vm(); + return JSValue::encode(vm->smallStrings.singleCharacterString(vm, radixDigits[value])); } if (radix == 10) { - JSGlobalData* globalData = &exec->globalData(); - return JSValue::encode(jsString(globalData, globalData->numericStrings.add(value))); + VM* vm = &exec->vm(); + return JSValue::encode(jsString(vm, vm->numericStrings.add(value))); } return JSValue::encode(jsString(exec, toStringWithRadix(value, radix))); @@ -503,11 +503,11 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec) return integerValueToString(exec, radix, integerValue); if (radix == 10) { - JSGlobalData* globalData = &exec->globalData(); - return JSValue::encode(jsString(globalData, globalData->numericStrings.add(doubleValue))); + VM* vm = &exec->vm(); + return JSValue::encode(jsString(vm, vm->numericStrings.add(doubleValue))); } - if (!isfinite(doubleValue)) + if (!std::isfinite(doubleValue)) return JSValue::encode(jsString(exec, String::numberToStringECMAScript(doubleValue))); RadixBuffer s; diff --git a/Source/JavaScriptCore/runtime/NumberPrototype.h b/Source/JavaScriptCore/runtime/NumberPrototype.h index d7caecf3f..b51251c72 100644 --- a/Source/JavaScriptCore/runtime/NumberPrototype.h +++ b/Source/JavaScriptCore/runtime/NumberPrototype.h @@ -38,9 +38,9 @@ namespace JSC { static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(NumberObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(NumberObjectType, StructureFlags), &s_info); } protected: diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp index 7e74a914b..d72cbe84e 100644 --- a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp @@ -30,6 +30,7 @@ #include "JSGlobalObject.h" #include "Lookup.h" #include "ObjectPrototype.h" +#include "Operations.h" #include "PropertyDescriptor.h" #include "PropertyNameArray.h" @@ -84,11 +85,11 @@ ObjectConstructor::ObjectConstructor(JSGlobalObject* globalObject, Structure* st void ObjectConstructor::finishCreation(ExecState* exec, ObjectPrototype* objectPrototype) { - Base::finishCreation(exec->globalData(), Identifier(exec, "Object").string()); + Base::finishCreation(exec->vm(), Identifier(exec, "Object").string()); // ECMA 15.2.3.1 - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, objectPrototype, DontEnum | DontDelete | ReadOnly); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().prototype, objectPrototype, DontEnum | DontDelete | ReadOnly); // no. of arguments for constructor - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontEnum | DontDelete); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontEnum | DontDelete); } bool ObjectConstructor::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot &slot) @@ -101,19 +102,19 @@ bool ObjectConstructor::getOwnPropertyDescriptor(JSObject* object, ExecState* ex return getStaticFunctionDescriptor<JSObject>(exec, ExecState::objectConstructorTable(exec), jsCast<ObjectConstructor*>(object), propertyName, descriptor); } -// ECMA 15.2.2 -static ALWAYS_INLINE JSObject* constructObject(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args) +static ALWAYS_INLINE JSObject* constructObject(ExecState* exec) { + JSGlobalObject* globalObject = exec->callee()->globalObject(); + ArgList args(exec); JSValue arg = args.at(0); if (arg.isUndefinedOrNull()) - return constructEmptyObject(exec, globalObject); + return constructEmptyObject(exec, globalObject->objectPrototype()); return arg.toObject(exec, globalObject); } static EncodedJSValue JSC_HOST_CALL constructWithObjectConstructor(ExecState* exec) { - ArgList args(exec); - return JSValue::encode(constructObject(exec, asInternalFunction(exec->callee())->globalObject(), args)); + return JSValue::encode(constructObject(exec)); } ConstructType ObjectConstructor::getConstructData(JSCell*, ConstructData& constructData) @@ -124,8 +125,7 @@ ConstructType ObjectConstructor::getConstructData(JSCell*, ConstructData& constr static EncodedJSValue JSC_HOST_CALL callObjectConstructor(ExecState* exec) { - ArgList args(exec); - return JSValue::encode(constructObject(exec, asInternalFunction(exec->callee())->globalObject(), args)); + return JSValue::encode(constructObject(exec)); } CallType ObjectConstructor::getCallData(JSCell*, CallData& callData) @@ -160,17 +160,17 @@ EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState JSObject* description = constructEmptyObject(exec); if (!descriptor.isAccessorDescriptor()) { - description->putDirect(exec->globalData(), exec->propertyNames().value, descriptor.value() ? descriptor.value() : jsUndefined(), 0); - description->putDirect(exec->globalData(), exec->propertyNames().writable, jsBoolean(descriptor.writable()), 0); + description->putDirect(exec->vm(), exec->propertyNames().value, descriptor.value() ? descriptor.value() : jsUndefined(), 0); + description->putDirect(exec->vm(), exec->propertyNames().writable, jsBoolean(descriptor.writable()), 0); } else { ASSERT(descriptor.getter()); ASSERT(descriptor.setter()); - description->putDirect(exec->globalData(), exec->propertyNames().get, descriptor.getter(), 0); - description->putDirect(exec->globalData(), exec->propertyNames().set, descriptor.setter(), 0); + description->putDirect(exec->vm(), exec->propertyNames().get, descriptor.getter(), 0); + description->putDirect(exec->vm(), exec->propertyNames().set, descriptor.setter(), 0); } - description->putDirect(exec->globalData(), exec->propertyNames().enumerable, jsBoolean(descriptor.enumerable()), 0); - description->putDirect(exec->globalData(), exec->propertyNames().configurable, jsBoolean(descriptor.configurable()), 0); + description->putDirect(exec->vm(), exec->propertyNames().enumerable, jsBoolean(descriptor.enumerable()), 0); + description->putDirect(exec->vm(), exec->propertyNames().configurable, jsBoolean(descriptor.configurable()), 0); return JSValue::encode(description); } @@ -349,7 +349,9 @@ EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState* exec) if (!exec->argument(0).isObject() && !exec->argument(0).isNull()) return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object prototype may only be an Object or null."))); JSValue proto = exec->argument(0); - JSObject* newObject = proto.isObject() ? constructEmptyObject(exec, asObject(proto)->inheritorID(exec->globalData())) : constructEmptyObject(exec, exec->lexicalGlobalObject()->nullPrototypeObjectStructure()); + JSObject* newObject = proto.isObject() + ? constructEmptyObject(exec, asObject(proto)) + : constructEmptyObject(exec, exec->lexicalGlobalObject()->nullPrototypeObjectStructure()); if (exec->argument(1).isUndefined()) return JSValue::encode(newObject); if (!exec->argument(1).isObject()) @@ -366,7 +368,7 @@ EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState* exec) JSObject* object = asObject(obj); if (isJSFinalObject(object)) { - object->seal(exec->globalData()); + object->seal(exec->vm()); return JSValue::encode(obj); } @@ -388,7 +390,7 @@ EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState* exec) } // 3. Set the [[Extensible]] internal property of O to false. - object->preventExtensions(exec->globalData()); + object->preventExtensions(exec->vm()); // 4. Return O. return JSValue::encode(obj); @@ -403,7 +405,7 @@ EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState* exec) JSObject* object = asObject(obj); if (isJSFinalObject(object) && !hasIndexedProperties(object->structure()->indexingType())) { - object->freeze(exec->globalData()); + object->freeze(exec->vm()); return JSValue::encode(obj); } @@ -429,7 +431,7 @@ EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState* exec) } // 3. Set the [[Extensible]] internal property of O to false. - object->preventExtensions(exec->globalData()); + object->preventExtensions(exec->vm()); // 4. Return O. return JSValue::encode(obj); @@ -440,7 +442,7 @@ EncodedJSValue JSC_HOST_CALL objectConstructorPreventExtensions(ExecState* exec) JSValue obj = exec->argument(0); if (!obj.isObject()) return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.preventExtensions can only be called on Objects."))); - asObject(obj)->preventExtensions(exec->globalData()); + asObject(obj)->preventExtensions(exec->vm()); return JSValue::encode(obj); } @@ -453,7 +455,7 @@ EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState* exec) JSObject* object = asObject(obj); if (isJSFinalObject(object)) - return JSValue::encode(jsBoolean(object->isSealed(exec->globalData()))); + return JSValue::encode(jsBoolean(object->isSealed(exec->vm()))); // 2. For each named own property name P of O, PropertyNameArray properties(exec); @@ -483,7 +485,7 @@ EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState* exec) JSObject* object = asObject(obj); if (isJSFinalObject(object)) - return JSValue::encode(jsBoolean(object->isFrozen(exec->globalData()))); + return JSValue::encode(jsBoolean(object->isFrozen(exec->vm()))); // 2. For each named own property name P of O, PropertyNameArray properties(exec); diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.h b/Source/JavaScriptCore/runtime/ObjectConstructor.h index c89134599..72c895fba 100644 --- a/Source/JavaScriptCore/runtime/ObjectConstructor.h +++ b/Source/JavaScriptCore/runtime/ObjectConstructor.h @@ -22,6 +22,8 @@ #define ObjectConstructor_h #include "InternalFunction.h" +#include "JSGlobalObject.h" +#include "ObjectPrototype.h" namespace JSC { @@ -43,9 +45,9 @@ namespace JSC { static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } protected: @@ -58,6 +60,30 @@ namespace JSC { static CallType getCallData(JSCell*, CallData&); }; + inline JSObject* constructEmptyObject(ExecState* exec, Structure* structure) + { + return JSFinalObject::create(exec, structure); + } + + inline JSObject* constructEmptyObject(ExecState* exec, JSObject* prototype, unsigned inlineCapacity) + { + JSGlobalObject* globalObject = exec->lexicalGlobalObject(); + PrototypeMap& prototypeMap = globalObject->vm().prototypeMap; + Structure* structure = prototypeMap.emptyObjectStructureForPrototype( + prototype, inlineCapacity); + return constructEmptyObject(exec, structure); + } + + inline JSObject* constructEmptyObject(ExecState* exec, JSObject* prototype) + { + return constructEmptyObject(exec, prototype, JSFinalObject::defaultInlineCapacity()); + } + + inline JSObject* constructEmptyObject(ExecState* exec) + { + return constructEmptyObject(exec, exec->lexicalGlobalObject()->objectPrototype()); + } + } // namespace JSC #endif // ObjectConstructor_h diff --git a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp index e94edfadf..eaed425df 100644 --- a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp @@ -25,6 +25,8 @@ #include "JSFunction.h" #include "JSString.h" #include "JSStringBuilder.h" +#include "Operations.h" +#include "StructureRareDataInlines.h" namespace JSC { @@ -38,51 +40,40 @@ static EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState*); static EncodedJSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState*); static EncodedJSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState*); -} - -#include "ObjectPrototype.lut.h" - -namespace JSC { - ASSERT_HAS_TRIVIAL_DESTRUCTOR(ObjectPrototype); -const ClassInfo ObjectPrototype::s_info = { "Object", &JSNonFinalObject::s_info, 0, ExecState::objectPrototypeTable, CREATE_METHOD_TABLE(ObjectPrototype) }; - -/* Source for ObjectPrototype.lut.h -@begin objectPrototypeTable - toString objectProtoFuncToString DontEnum|Function 0 - toLocaleString objectProtoFuncToLocaleString DontEnum|Function 0 - valueOf objectProtoFuncValueOf DontEnum|Function 0 - hasOwnProperty objectProtoFuncHasOwnProperty DontEnum|Function 1 - propertyIsEnumerable objectProtoFuncPropertyIsEnumerable DontEnum|Function 1 - isPrototypeOf objectProtoFuncIsPrototypeOf DontEnum|Function 1 - __defineGetter__ objectProtoFuncDefineGetter DontEnum|Function 2 - __defineSetter__ objectProtoFuncDefineSetter DontEnum|Function 2 - __lookupGetter__ objectProtoFuncLookupGetter DontEnum|Function 1 - __lookupSetter__ objectProtoFuncLookupSetter DontEnum|Function 1 -@end -*/ +const ClassInfo ObjectPrototype::s_info = { "Object", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(ObjectPrototype) }; ObjectPrototype::ObjectPrototype(ExecState* exec, Structure* stucture) - : JSNonFinalObject(exec->globalData(), stucture) + : JSNonFinalObject(exec->vm(), stucture) { } -void ObjectPrototype::finishCreation(JSGlobalData& globalData, JSGlobalObject*) +void ObjectPrototype::finishCreation(ExecState* exec, JSGlobalObject* globalObject) { - Base::finishCreation(globalData); + VM& vm = exec->vm(); + + Base::finishCreation(vm); ASSERT(inherits(&s_info)); - notifyUsedAsPrototype(globalData); -} - -bool ObjectPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot &slot) -{ - return getStaticFunctionSlot<JSNonFinalObject>(exec, ExecState::objectPrototypeTable(exec), jsCast<ObjectPrototype*>(cell), propertyName, slot); + vm.prototypeMap.addPrototype(this); + + JSC_NATIVE_FUNCTION(vm.propertyNames->toString, objectProtoFuncToString, DontEnum, 0); + JSC_NATIVE_FUNCTION(vm.propertyNames->toLocaleString, objectProtoFuncToLocaleString, DontEnum, 0); + JSC_NATIVE_FUNCTION(vm.propertyNames->valueOf, objectProtoFuncValueOf, DontEnum, 0); + JSC_NATIVE_FUNCTION(vm.propertyNames->hasOwnProperty, objectProtoFuncHasOwnProperty, DontEnum, 1); + JSC_NATIVE_FUNCTION(vm.propertyNames->propertyIsEnumerable, objectProtoFuncPropertyIsEnumerable, DontEnum, 1); + JSC_NATIVE_FUNCTION(vm.propertyNames->isPrototypeOf, objectProtoFuncIsPrototypeOf, DontEnum, 1); + JSC_NATIVE_FUNCTION(vm.propertyNames->__defineGetter__, objectProtoFuncDefineGetter, DontEnum, 2); + JSC_NATIVE_FUNCTION(vm.propertyNames->__defineSetter__, objectProtoFuncDefineSetter, DontEnum, 2); + JSC_NATIVE_FUNCTION(vm.propertyNames->__lookupGetter__, objectProtoFuncLookupGetter, DontEnum, 1); + JSC_NATIVE_FUNCTION(vm.propertyNames->__lookupSetter__, objectProtoFuncLookupSetter, DontEnum, 1); } -bool ObjectPrototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor) +ObjectPrototype* ObjectPrototype::create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure) { - return getStaticFunctionDescriptor<JSNonFinalObject>(exec, ExecState::objectPrototypeTable(exec), jsCast<ObjectPrototype*>(object), propertyName, descriptor); + ObjectPrototype* prototype = new (NotNull, allocateCell<ObjectPrototype>(*exec->heap())) ObjectPrototype(exec, structure); + prototype->finishCreation(exec, globalObject); + return prototype; } // ------------------------------ Functions -------------------------------- @@ -227,7 +218,7 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState* exec) return JSValue::encode(throwOutOfMemoryError(exec)); result = jsNontrivialString(exec, newString.release()); - thisObject->structure()->setObjectToStringValue(exec->globalData(), thisObject, result); + thisObject->structure()->setObjectToStringValue(exec->vm(), thisObject, result); } return JSValue::encode(result); } diff --git a/Source/JavaScriptCore/runtime/ObjectPrototype.h b/Source/JavaScriptCore/runtime/ObjectPrototype.h index e3551d6fd..cf0143e29 100644 --- a/Source/JavaScriptCore/runtime/ObjectPrototype.h +++ b/Source/JavaScriptCore/runtime/ObjectPrototype.h @@ -29,29 +29,20 @@ namespace JSC { public: typedef JSNonFinalObject Base; - static ObjectPrototype* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure) - { - ObjectPrototype* prototype = new (NotNull, allocateCell<ObjectPrototype>(*exec->heap())) ObjectPrototype(exec, structure); - prototype->finishCreation(exec->globalData(), globalObject); - return prototype; - } + static ObjectPrototype* create(ExecState*, JSGlobalObject*, Structure*); static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } protected: - static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSNonFinalObject::StructureFlags; - - void finishCreation(JSGlobalData&, JSGlobalObject*); + void finishCreation(ExecState*, JSGlobalObject*); private: ObjectPrototype(ExecState*, Structure*); - static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); - static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); }; JS_EXPORT_PRIVATE EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState*); diff --git a/Source/JavaScriptCore/runtime/Operations.cpp b/Source/JavaScriptCore/runtime/Operations.cpp index d96bae575..d6cc0ff57 100644 --- a/Source/JavaScriptCore/runtime/Operations.cpp +++ b/Source/JavaScriptCore/runtime/Operations.cpp @@ -56,28 +56,32 @@ NEVER_INLINE JSValue jsAddSlowCase(CallFrame* callFrame, JSValue v1, JSValue v2) return jsNumber(p1.toNumber(callFrame) + p2.toNumber(callFrame)); } -JSValue jsTypeStringForValue(CallFrame* callFrame, JSValue v) +JSValue jsTypeStringForValue(VM& vm, JSGlobalObject* globalObject, JSValue v) { - JSGlobalData& globalData = callFrame->globalData(); if (v.isUndefined()) - return globalData.smallStrings.undefinedString(&globalData); + return vm.smallStrings.undefinedString(); if (v.isBoolean()) - return globalData.smallStrings.booleanString(&globalData); + return vm.smallStrings.booleanString(); if (v.isNumber()) - return globalData.smallStrings.numberString(&globalData); + return vm.smallStrings.numberString(); if (v.isString()) - return globalData.smallStrings.stringString(&globalData); + return vm.smallStrings.stringString(); if (v.isObject()) { // Return "undefined" for objects that should be treated // as null when doing comparisons. - if (asObject(v)->structure()->masqueradesAsUndefined(callFrame->lexicalGlobalObject())) - return globalData.smallStrings.undefinedString(&globalData); + if (asObject(v)->structure()->masqueradesAsUndefined(globalObject)) + return vm.smallStrings.undefinedString(); CallData callData; JSObject* object = asObject(v); if (object->methodTable()->getCallData(object, callData) != CallTypeNone) - return globalData.smallStrings.functionString(&globalData); + return vm.smallStrings.functionString(); } - return globalData.smallStrings.objectString(&globalData); + return vm.smallStrings.objectString(); +} + +JSValue jsTypeStringForValue(CallFrame* callFrame, JSValue v) +{ + return jsTypeStringForValue(callFrame->vm(), callFrame->lexicalGlobalObject(), v); } bool jsIsObjectType(CallFrame* callFrame, JSValue v) @@ -86,7 +90,7 @@ bool jsIsObjectType(CallFrame* callFrame, JSValue v) return v.isNull(); JSType type = v.asCell()->structure()->typeInfo().type(); - if (type == NumberType || type == StringType) + if (type == StringType) return false; if (type >= ObjectType) { if (asObject(v)->structure()->masqueradesAsUndefined(callFrame->lexicalGlobalObject())) diff --git a/Source/JavaScriptCore/runtime/Operations.h b/Source/JavaScriptCore/runtime/Operations.h index 8e0a0a393..afac13000 100644 --- a/Source/JavaScriptCore/runtime/Operations.h +++ b/Source/JavaScriptCore/runtime/Operations.h @@ -24,359 +24,263 @@ #include "ExceptionHelpers.h" #include "Interpreter.h" +#include "JSCJSValueInlines.h" +#include "JSFunctionInlines.h" #include "JSProxy.h" #include "JSString.h" -#include "JSValueInlines.h" +#include "StructureInlines.h" namespace JSC { - NEVER_INLINE JSValue jsAddSlowCase(CallFrame*, JSValue, JSValue); - JSValue jsTypeStringForValue(CallFrame*, JSValue); - bool jsIsObjectType(CallFrame*, JSValue); - bool jsIsFunctionType(JSValue); - - ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2) - { - JSGlobalData& globalData = exec->globalData(); - - unsigned length1 = s1->length(); - if (!length1) - return s2; - unsigned length2 = s2->length(); - if (!length2) - return s1; - if ((length1 + length2) < length1) +NEVER_INLINE JSValue jsAddSlowCase(CallFrame*, JSValue, JSValue); +JSValue jsTypeStringForValue(CallFrame*, JSValue); +JSValue jsTypeStringForValue(VM&, JSGlobalObject*, JSValue); +bool jsIsObjectType(CallFrame*, JSValue); +bool jsIsFunctionType(JSValue); + +ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2) +{ + VM& vm = exec->vm(); + + unsigned length1 = s1->length(); + if (!length1) + return s2; + unsigned length2 = s2->length(); + if (!length2) + return s1; + if ((length1 + length2) < length1) + return throwOutOfMemoryError(exec); + + return JSRopeString::create(vm, s1, s2); +} + +ALWAYS_INLINE JSValue jsString(ExecState* exec, const String& u1, const String& u2, const String& u3) +{ + VM* vm = &exec->vm(); + + unsigned length1 = u1.length(); + unsigned length2 = u2.length(); + unsigned length3 = u3.length(); + if (!length1) + return jsString(exec, jsString(vm, u2), jsString(vm, u3)); + if (!length2) + return jsString(exec, jsString(vm, u1), jsString(vm, u3)); + if (!length3) + return jsString(exec, jsString(vm, u1), jsString(vm, u2)); + + if ((length1 + length2) < length1) + return throwOutOfMemoryError(exec); + if ((length1 + length2 + length3) < length3) + return throwOutOfMemoryError(exec); + + return JSRopeString::create(exec->vm(), jsString(vm, u1), jsString(vm, u2), jsString(vm, u3)); +} + +ALWAYS_INLINE JSValue jsString(ExecState* exec, Register* strings, unsigned count) +{ + VM* vm = &exec->vm(); + JSRopeString::RopeBuilder ropeBuilder(*vm); + + unsigned oldLength = 0; + + for (unsigned i = 0; i < count; ++i) { + JSValue v = strings[i].jsValue(); + ropeBuilder.append(v.toString(exec)); + + if (ropeBuilder.length() < oldLength) // True for overflow return throwOutOfMemoryError(exec); - - return JSRopeString::create(globalData, s1, s2); - } - - ALWAYS_INLINE JSValue jsString(ExecState* exec, const String& u1, const String& u2, const String& u3) - { - JSGlobalData* globalData = &exec->globalData(); - - unsigned length1 = u1.length(); - unsigned length2 = u2.length(); - unsigned length3 = u3.length(); - if (!length1) - return jsString(exec, jsString(globalData, u2), jsString(globalData, u3)); - if (!length2) - return jsString(exec, jsString(globalData, u1), jsString(globalData, u3)); - if (!length3) - return jsString(exec, jsString(globalData, u1), jsString(globalData, u2)); - - if ((length1 + length2) < length1) - return throwOutOfMemoryError(exec); - if ((length1 + length2 + length3) < length3) - return throwOutOfMemoryError(exec); - - return JSRopeString::create(exec->globalData(), jsString(globalData, u1), jsString(globalData, u2), jsString(globalData, u3)); + oldLength = ropeBuilder.length(); } - ALWAYS_INLINE JSValue jsString(ExecState* exec, Register* strings, unsigned count) - { - JSGlobalData* globalData = &exec->globalData(); - JSRopeString::RopeBuilder ropeBuilder(*globalData); + return ropeBuilder.release(); +} - unsigned oldLength = 0; - - for (unsigned i = 0; i < count; ++i) { - JSValue v = strings[i].jsValue(); - ropeBuilder.append(v.toString(exec)); - - if (ropeBuilder.length() < oldLength) // True for overflow - return throwOutOfMemoryError(exec); - oldLength = ropeBuilder.length(); - } - - return ropeBuilder.release(); - } +ALWAYS_INLINE JSValue jsStringFromArguments(ExecState* exec, JSValue thisValue) +{ + VM* vm = &exec->vm(); + JSRopeString::RopeBuilder ropeBuilder(*vm); + ropeBuilder.append(thisValue.toString(exec)); - ALWAYS_INLINE JSValue jsStringFromArguments(ExecState* exec, JSValue thisValue) - { - JSGlobalData* globalData = &exec->globalData(); - JSRopeString::RopeBuilder ropeBuilder(*globalData); - ropeBuilder.append(thisValue.toString(exec)); + unsigned oldLength = 0; - unsigned oldLength = 0; - - for (unsigned i = 0; i < exec->argumentCount(); ++i) { - JSValue v = exec->argument(i); - ropeBuilder.append(v.toString(exec)); - - if (ropeBuilder.length() < oldLength) // True for overflow - return throwOutOfMemoryError(exec); - oldLength = ropeBuilder.length(); - } - - return ropeBuilder.release(); - } - - // ECMA 11.9.3 - inline bool JSValue::equal(ExecState* exec, JSValue v1, JSValue v2) - { - if (v1.isInt32() && v2.isInt32()) - return v1 == v2; - - return equalSlowCase(exec, v1, v2); - } - - ALWAYS_INLINE bool JSValue::equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2) - { - do { - if (v1.isNumber() && v2.isNumber()) - return v1.asNumber() == v2.asNumber(); - - bool s1 = v1.isString(); - bool s2 = v2.isString(); - if (s1 && s2) - return asString(v1)->value(exec) == asString(v2)->value(exec); - - if (v1.isUndefinedOrNull()) { - if (v2.isUndefinedOrNull()) - return true; - if (!v2.isCell()) - return false; - return v2.asCell()->structure()->masqueradesAsUndefined(exec->lexicalGlobalObject()); - } - - if (v2.isUndefinedOrNull()) { - if (!v1.isCell()) - return false; - return v1.asCell()->structure()->masqueradesAsUndefined(exec->lexicalGlobalObject()); - } - - if (v1.isObject()) { - if (v2.isObject()) - return v1 == v2; - JSValue p1 = v1.toPrimitive(exec); - if (exec->hadException()) - return false; - v1 = p1; - if (v1.isInt32() && v2.isInt32()) - return v1 == v2; - continue; - } - - if (v2.isObject()) { - JSValue p2 = v2.toPrimitive(exec); - if (exec->hadException()) - return false; - v2 = p2; - if (v1.isInt32() && v2.isInt32()) - return v1 == v2; - continue; - } - - if (s1 || s2) { - double d1 = v1.toNumber(exec); - double d2 = v2.toNumber(exec); - return d1 == d2; - } - - if (v1.isBoolean()) { - if (v2.isNumber()) - return static_cast<double>(v1.asBoolean()) == v2.asNumber(); - } else if (v2.isBoolean()) { - if (v1.isNumber()) - return v1.asNumber() == static_cast<double>(v2.asBoolean()); - } - - return v1 == v2; - } while (true); - } + for (unsigned i = 0; i < exec->argumentCount(); ++i) { + JSValue v = exec->argument(i); + ropeBuilder.append(v.toString(exec)); - // ECMA 11.9.3 - ALWAYS_INLINE bool JSValue::strictEqualSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2) - { - ASSERT(v1.isCell() && v2.isCell()); - - if (v1.asCell()->isString() && v2.asCell()->isString()) - return asString(v1)->value(exec) == asString(v2)->value(exec); - - return v1 == v2; - } - - inline bool JSValue::strictEqual(ExecState* exec, JSValue v1, JSValue v2) - { - if (v1.isInt32() && v2.isInt32()) - return v1 == v2; - - if (v1.isNumber() && v2.isNumber()) - return v1.asNumber() == v2.asNumber(); - - if (!v1.isCell() || !v2.isCell()) - return v1 == v2; - - return strictEqualSlowCaseInline(exec, v1, v2); + if (ropeBuilder.length() < oldLength) // True for overflow + return throwOutOfMemoryError(exec); + oldLength = ropeBuilder.length(); } - // See ES5 11.8.1/11.8.2/11.8.5 for definition of leftFirst, this value ensures correct - // evaluation ordering for argument conversions for '<' and '>'. For '<' pass the value - // true, for leftFirst, for '>' pass the value false (and reverse operand order). - template<bool leftFirst> - ALWAYS_INLINE bool jsLess(CallFrame* callFrame, JSValue v1, JSValue v2) - { - if (v1.isInt32() && v2.isInt32()) - return v1.asInt32() < v2.asInt32(); - - if (v1.isNumber() && v2.isNumber()) - return v1.asNumber() < v2.asNumber(); - - if (isJSString(v1) && isJSString(v2)) - return codePointCompareLessThan(asString(v1)->value(callFrame), asString(v2)->value(callFrame)); - - double n1; - double n2; - JSValue p1; - JSValue p2; - bool wasNotString1; - bool wasNotString2; - if (leftFirst) { - wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1); - wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2); - } else { - wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2); - wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1); - } - - if (wasNotString1 | wasNotString2) - return n1 < n2; - return codePointCompareLessThan(asString(p1)->value(callFrame), asString(p2)->value(callFrame)); + return ropeBuilder.release(); +} + +// See ES5 11.8.1/11.8.2/11.8.5 for definition of leftFirst, this value ensures correct +// evaluation ordering for argument conversions for '<' and '>'. For '<' pass the value +// true, for leftFirst, for '>' pass the value false (and reverse operand order). +template<bool leftFirst> +ALWAYS_INLINE bool jsLess(CallFrame* callFrame, JSValue v1, JSValue v2) +{ + if (v1.isInt32() && v2.isInt32()) + return v1.asInt32() < v2.asInt32(); + + if (v1.isNumber() && v2.isNumber()) + return v1.asNumber() < v2.asNumber(); + + if (isJSString(v1) && isJSString(v2)) + return codePointCompareLessThan(asString(v1)->value(callFrame), asString(v2)->value(callFrame)); + + double n1; + double n2; + JSValue p1; + JSValue p2; + bool wasNotString1; + bool wasNotString2; + if (leftFirst) { + wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1); + wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2); + } else { + wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2); + wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1); } - // See ES5 11.8.3/11.8.4/11.8.5 for definition of leftFirst, this value ensures correct - // evaluation ordering for argument conversions for '<=' and '=>'. For '<=' pass the - // value true, for leftFirst, for '=>' pass the value false (and reverse operand order). - template<bool leftFirst> - ALWAYS_INLINE bool jsLessEq(CallFrame* callFrame, JSValue v1, JSValue v2) - { - if (v1.isInt32() && v2.isInt32()) - return v1.asInt32() <= v2.asInt32(); - - if (v1.isNumber() && v2.isNumber()) - return v1.asNumber() <= v2.asNumber(); - - if (isJSString(v1) && isJSString(v2)) - return !codePointCompareLessThan(asString(v2)->value(callFrame), asString(v1)->value(callFrame)); - - double n1; - double n2; - JSValue p1; - JSValue p2; - bool wasNotString1; - bool wasNotString2; - if (leftFirst) { - wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1); - wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2); - } else { - wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2); - wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1); - } - - if (wasNotString1 | wasNotString2) - return n1 <= n2; - return !codePointCompareLessThan(asString(p2)->value(callFrame), asString(p1)->value(callFrame)); + if (wasNotString1 | wasNotString2) + return n1 < n2; + return codePointCompareLessThan(asString(p1)->value(callFrame), asString(p2)->value(callFrame)); +} + +// See ES5 11.8.3/11.8.4/11.8.5 for definition of leftFirst, this value ensures correct +// evaluation ordering for argument conversions for '<=' and '=>'. For '<=' pass the +// value true, for leftFirst, for '=>' pass the value false (and reverse operand order). +template<bool leftFirst> +ALWAYS_INLINE bool jsLessEq(CallFrame* callFrame, JSValue v1, JSValue v2) +{ + if (v1.isInt32() && v2.isInt32()) + return v1.asInt32() <= v2.asInt32(); + + if (v1.isNumber() && v2.isNumber()) + return v1.asNumber() <= v2.asNumber(); + + if (isJSString(v1) && isJSString(v2)) + return !codePointCompareLessThan(asString(v2)->value(callFrame), asString(v1)->value(callFrame)); + + double n1; + double n2; + JSValue p1; + JSValue p2; + bool wasNotString1; + bool wasNotString2; + if (leftFirst) { + wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1); + wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2); + } else { + wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2); + wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1); } - // Fast-path choices here are based on frequency data from SunSpider: - // <times> Add case: <t1> <t2> - // --------------------------- - // 5626160 Add case: 3 3 (of these, 3637690 are for immediate values) - // 247412 Add case: 5 5 - // 20900 Add case: 5 6 - // 13962 Add case: 5 3 - // 4000 Add case: 3 5 - - ALWAYS_INLINE JSValue jsAdd(CallFrame* callFrame, JSValue v1, JSValue v2) - { - if (v1.isNumber() && v2.isNumber()) - return jsNumber(v1.asNumber() + v2.asNumber()); + if (wasNotString1 | wasNotString2) + return n1 <= n2; + return !codePointCompareLessThan(asString(p2)->value(callFrame), asString(p1)->value(callFrame)); +} + +// Fast-path choices here are based on frequency data from SunSpider: +// <times> Add case: <t1> <t2> +// --------------------------- +// 5626160 Add case: 3 3 (of these, 3637690 are for immediate values) +// 247412 Add case: 5 5 +// 20900 Add case: 5 6 +// 13962 Add case: 5 3 +// 4000 Add case: 3 5 + +ALWAYS_INLINE JSValue jsAdd(CallFrame* callFrame, JSValue v1, JSValue v2) +{ + if (v1.isNumber() && v2.isNumber()) + return jsNumber(v1.asNumber() + v2.asNumber()); - if (v1.isString() && !v2.isObject()) - return jsString(callFrame, asString(v1), v2.toString(callFrame)); + if (v1.isString() && !v2.isObject()) + return jsString(callFrame, asString(v1), v2.toString(callFrame)); - // All other cases are pretty uncommon - return jsAddSlowCase(callFrame, v1, v2); - } + // All other cases are pretty uncommon + return jsAddSlowCase(callFrame, v1, v2); +} #define InvalidPrototypeChain (std::numeric_limits<size_t>::max()) - inline size_t normalizePrototypeChainForChainAccess(CallFrame* callFrame, JSValue base, JSValue slotBase, const Identifier& propertyName, PropertyOffset& slotOffset) - { - JSCell* cell = base.asCell(); - size_t count = 0; +inline size_t normalizePrototypeChainForChainAccess(CallFrame* callFrame, JSValue base, JSValue slotBase, const Identifier& propertyName, PropertyOffset& slotOffset) +{ + JSCell* cell = base.asCell(); + size_t count = 0; - while (slotBase != cell) { - if (cell->isProxy()) - return InvalidPrototypeChain; + while (slotBase != cell) { + if (cell->isProxy()) + return InvalidPrototypeChain; - if (cell->structure()->typeInfo().hasImpureGetOwnPropertySlot()) - return InvalidPrototypeChain; + if (cell->structure()->typeInfo().hasImpureGetOwnPropertySlot()) + return InvalidPrototypeChain; - JSValue v = cell->structure()->prototypeForLookup(callFrame); + JSValue v = cell->structure()->prototypeForLookup(callFrame); - // If we didn't find slotBase in base's prototype chain, then base - // must be a proxy for another object. + // If we didn't find slotBase in base's prototype chain, then base + // must be a proxy for another object. - if (v.isNull()) - return InvalidPrototypeChain; + if (v.isNull()) + return InvalidPrototypeChain; - cell = v.asCell(); + cell = v.asCell(); - // Since we're accessing a prototype in a loop, it's a good bet that it - // should not be treated as a dictionary. - if (cell->structure()->isDictionary()) { - asObject(cell)->flattenDictionaryObject(callFrame->globalData()); - if (slotBase == cell) - slotOffset = cell->structure()->get(callFrame->globalData(), propertyName); - } - - ++count; + // Since we're accessing a prototype in a loop, it's a good bet that it + // should not be treated as a dictionary. + if (cell->structure()->isDictionary()) { + asObject(cell)->flattenDictionaryObject(callFrame->vm()); + if (slotBase == cell) + slotOffset = cell->structure()->get(callFrame->vm(), propertyName); } - - ASSERT(count); - return count; + + ++count; } - - inline size_t normalizePrototypeChain(CallFrame* callFrame, JSCell* base) - { - size_t count = 0; - while (1) { - if (base->isProxy()) - return InvalidPrototypeChain; + + ASSERT(count); + return count; +} + +inline size_t normalizePrototypeChain(CallFrame* callFrame, JSCell* base) +{ + size_t count = 0; + while (1) { + if (base->isProxy()) + return InvalidPrototypeChain; - JSValue v = base->structure()->prototypeForLookup(callFrame); - if (v.isNull()) - return count; + JSValue v = base->structure()->prototypeForLookup(callFrame); + if (v.isNull()) + return count; - base = v.asCell(); + base = v.asCell(); - // Since we're accessing a prototype in a loop, it's a good bet that it - // should not be treated as a dictionary. - if (base->structure()->isDictionary()) - asObject(base)->flattenDictionaryObject(callFrame->globalData()); + // Since we're accessing a prototype in a loop, it's a good bet that it + // should not be treated as a dictionary. + if (base->structure()->isDictionary()) + asObject(base)->flattenDictionaryObject(callFrame->vm()); - ++count; - } + ++count; } +} - inline bool isPrototypeChainNormalized(JSGlobalObject* globalObject, Structure* structure) - { - for (;;) { - if (structure->typeInfo().type() == ProxyType) - return false; +inline bool isPrototypeChainNormalized(JSGlobalObject* globalObject, Structure* structure) +{ + for (;;) { + if (structure->typeInfo().type() == ProxyType) + return false; - JSValue v = structure->prototypeForLookup(globalObject); - if (v.isNull()) - return true; + JSValue v = structure->prototypeForLookup(globalObject); + if (v.isNull()) + return true; - structure = v.asCell()->structure(); + structure = v.asCell()->structure(); - if (structure->isDictionary()) - return false; - } + if (structure->isDictionary()) + return false; } +} } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Options.cpp b/Source/JavaScriptCore/runtime/Options.cpp index 386eb4fcf..40711bfa3 100644 --- a/Source/JavaScriptCore/runtime/Options.cpp +++ b/Source/JavaScriptCore/runtime/Options.cpp @@ -36,7 +36,6 @@ #include <wtf/PageBlock.h> #include <wtf/StdLibExtras.h> #include <wtf/StringExtras.h> -#include <wtf/UnusedParam.h> #if OS(DARWIN) && ENABLE(PARALLEL_GC) #include <sys/sysctl.h> @@ -72,6 +71,11 @@ static bool parse(const char* string, double& value) return sscanf(string, "%lf", &value) == 1; } +static bool parse(const char* string, OptionRange& value) +{ + return value.init(string); +} + template<typename T> void overrideOptionWithHeuristic(T& variable, const char* name) { @@ -105,6 +109,59 @@ static unsigned computeNumberOfGCMarkers(int maxNumberOfGCMarkers) return cpusToUse; } +bool OptionRange::init(const char* rangeString) +{ + // rangeString should be in the form of [!]<low>[:<high>] + // where low and high are unsigned + + bool invert = false; + + if (m_state > Uninitialized) + return true; + + if (!rangeString) { + m_state = InitError; + return false; + } + + m_rangeString = rangeString; + + if (*rangeString == '!') { + invert = true; + rangeString++; + } + + int scanResult = sscanf(rangeString, " %u:%u", &m_lowLimit, &m_highLimit); + + if (!scanResult || scanResult == EOF) { + m_state = InitError; + return false; + } + + if (scanResult == 1) + m_highLimit = m_lowLimit; + + if (m_lowLimit > m_highLimit) { + m_state = InitError; + return false; + } + + m_state = invert ? Inverted : Normal; + + return true; +} + +bool OptionRange::isInRange(unsigned count) +{ + if (m_state < Normal) + return true; + + if ((m_lowLimit <= count) && (count <= m_highLimit)) + return m_state == Normal ? true : false; + + return m_state == Normal ? false : true; +} + Options::Entry Options::s_options[Options::numberOfOptions]; // Realize the names for each of the options: @@ -187,6 +244,7 @@ bool Options::setOption(const char* arg) #define FOR_EACH_OPTION(type_, name_, defaultValue_) \ if (!strncmp(arg, #name_, equalStr - arg)) { \ type_ value; \ + value = 0; \ bool success = parse(valueStr, value); \ if (success) { \ name_() = value; \ @@ -227,6 +285,9 @@ void Options::dumpOption(OptionID id, FILE* stream, const char* header, const ch case int32Type: fprintf(stream, "%d", s_options[id].u.int32Val); break; + case optionRangeType: + fprintf(stream, "%s", s_options[id].u.optionRangeVal.rangeString()); + break; } fprintf(stream, "%s", footer); } diff --git a/Source/JavaScriptCore/runtime/Options.h b/Source/JavaScriptCore/runtime/Options.h index bf4a0cf75..559b6084b 100644 --- a/Source/JavaScriptCore/runtime/Options.h +++ b/Source/JavaScriptCore/runtime/Options.h @@ -60,6 +60,33 @@ namespace JSC { // values after the sanity checks (for your own testing), then you're liable to // ensure that the new values set are sane and reasonable for your own run. +class OptionRange { +private: + enum RangeState { Uninitialized, InitError, Normal, Inverted }; +public: + OptionRange& operator= (const int& rhs) + { // Only needed for initialization + if (!rhs) { + m_state = Uninitialized; + m_rangeString = 0; + m_lowLimit = 0; + m_highLimit = 0; + } + return *this; + } + + bool init(const char*); + bool isInRange(unsigned); + const char* rangeString() { return (m_state > InitError) ? m_rangeString : "<null>"; } + +private: + RangeState m_state; + const char* m_rangeString; + unsigned m_lowLimit; + unsigned m_highLimit; +}; + +typedef OptionRange optionRange; #define JSC_OPTIONS(v) \ v(bool, useJIT, true) \ @@ -74,10 +101,21 @@ namespace JSC { v(bool, showDisassembly, false) \ v(bool, showDFGDisassembly, false) \ v(bool, showAllDFGNodes, false) \ + v(optionRange, bytecodeRangeToDFGCompile, 0) \ + v(bool, dumpBytecodeAtDFGTime, false) \ + v(bool, dumpGraphAtEachPhase, false) \ + v(bool, verboseCompilation, false) \ + v(bool, logCompilationChanges, false) \ + v(bool, printEachOSRExit, false) \ + v(bool, validateGraph, false) \ + v(bool, validateGraphAtEachPhase, false) \ + \ + v(bool, enableProfiler, false) \ \ v(unsigned, maximumOptimizationCandidateInstructionCount, 10000) \ \ v(unsigned, maximumFunctionForCallInlineCandidateInstructionCount, 180) \ + v(unsigned, maximumFunctionForClosureCallInlineCandidateInstructionCount, 100) \ v(unsigned, maximumFunctionForConstructInlineCandidateInstructionCount, 100) \ \ /* Depth of inline stack, so 1 = no inlining, 2 = one level, etc. */ \ @@ -87,21 +125,20 @@ namespace JSC { v(int32, thresholdForJITSoon, 100) \ \ v(int32, thresholdForOptimizeAfterWarmUp, 1000) \ - v(int32, thresholdForOptimizeAfterLongWarmUp, 5000) \ + v(int32, thresholdForOptimizeAfterLongWarmUp, 1000) \ v(int32, thresholdForOptimizeSoon, 1000) \ \ v(int32, executionCounterIncrementForLoop, 1) \ v(int32, executionCounterIncrementForReturn, 15) \ \ + v(int32, evalThresholdMultiplier, 10) \ + \ v(bool, randomizeExecutionCountsBetweenCheckpoints, false) \ v(int32, maximumExecutionCountsBetweenCheckpoints, 1000) \ \ - v(double, likelyToTakeSlowCaseThreshold, 0.15) \ - v(double, couldTakeSlowCaseThreshold, 0.05) \ v(unsigned, likelyToTakeSlowCaseMinimumCount, 100) \ v(unsigned, couldTakeSlowCaseMinimumCount, 10) \ \ - v(double, osrExitProminenceForFrequentExitSite, 0.3) \ v(unsigned, osrExitCountForReoptimization, 100) \ v(unsigned, osrExitCountForReoptimizationFromLoop, 5) \ \ @@ -170,6 +207,7 @@ private: unsignedType, doubleType, int32Type, + optionRangeType, }; // For storing for an option value: @@ -179,6 +217,7 @@ private: unsigned unsignedVal; double doubleVal; int32 int32Val; + OptionRange optionRangeVal; } u; }; diff --git a/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp b/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp index 236a8e5ae..14b42fd9a 100644 --- a/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp +++ b/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp @@ -176,8 +176,8 @@ bool sameValue(ExecState* exec, JSValue a, JSValue b) return false; double x = a.asNumber(); double y = b.asNumber(); - if (isnan(x)) - return isnan(y); + if (std::isnan(x)) + return std::isnan(y); return bitwise_cast<uint64_t>(x) == bitwise_cast<uint64_t>(y); } diff --git a/Source/JavaScriptCore/runtime/PropertyDescriptor.h b/Source/JavaScriptCore/runtime/PropertyDescriptor.h index 2c3878f57..5a5857d1c 100644 --- a/Source/JavaScriptCore/runtime/PropertyDescriptor.h +++ b/Source/JavaScriptCore/runtime/PropertyDescriptor.h @@ -26,7 +26,7 @@ #ifndef PropertyDescriptor_h #define PropertyDescriptor_h -#include "JSValue.h" +#include "JSCJSValue.h" namespace JSC { class GetterSetter; diff --git a/Source/JavaScriptCore/runtime/PropertyMapHashTable.h b/Source/JavaScriptCore/runtime/PropertyMapHashTable.h index 9c6ddb20f..9ddb6997c 100644 --- a/Source/JavaScriptCore/runtime/PropertyMapHashTable.h +++ b/Source/JavaScriptCore/runtime/PropertyMapHashTable.h @@ -22,8 +22,10 @@ #define PropertyMapHashTable_h #include "PropertyOffset.h" +#include "Structure.h" #include "WriteBarrier.h" #include <wtf/HashTable.h> +#include <wtf/MathExtras.h> #include <wtf/PassOwnPtr.h> #include <wtf/Vector.h> #include <wtf/text/StringImpl.h> @@ -50,9 +52,7 @@ namespace JSC { inline bool isPowerOf2(unsigned v) { - // Taken from http://www.cs.utk.edu/~vose/c-stuff/bithacks.html - - return !(v & (v - 1)) && v; + return hasOneBitSet(v); } inline unsigned nextPowerOf2(unsigned v) @@ -77,17 +77,16 @@ struct PropertyMapEntry { unsigned attributes; WriteBarrier<JSCell> specificValue; - PropertyMapEntry(JSGlobalData& globalData, JSCell* owner, StringImpl* key, PropertyOffset offset, unsigned attributes, JSCell* specificValue) + PropertyMapEntry(VM& vm, JSCell* owner, StringImpl* key, PropertyOffset offset, unsigned attributes, JSCell* specificValue) : key(key) , offset(offset) , attributes(attributes) - , specificValue(globalData, owner, specificValue, WriteBarrier<JSCell>::MayBeNull) + , specificValue(vm, owner, specificValue, WriteBarrier<JSCell>::MayBeNull) { } }; -class PropertyTable { - WTF_MAKE_FAST_ALLOCATED; +class PropertyTable : public JSCell { // This is the implementation for 'iterator' and 'const_iterator', // used for iterating over the table in insertion order. @@ -130,6 +129,19 @@ class PropertyTable { }; public: + static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; + static void destroy(JSCell*); + + static JS_EXPORTDATA const ClassInfo s_info; + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, OverridesVisitChildren), &s_info); + } + + static void visitChildren(JSCell*, SlotVisitor&); + typedef StringImpl* KeyType; typedef PropertyMapEntry ValueType; @@ -143,9 +155,9 @@ public: 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&); + static PropertyTable* create(VM&, unsigned initialCapacity); + static PropertyTable* clone(VM&, JSCell* owner, const PropertyTable&); + static PropertyTable* clone(VM&, JSCell* owner, unsigned initialCapacity, const PropertyTable&); ~PropertyTable(); // Ordered iteration methods. @@ -158,7 +170,8 @@ public: find_iterator find(const KeyType&); find_iterator findWithString(const KeyType&); // Add a value to the table - std::pair<find_iterator, bool> add(const ValueType& entry); + enum EffectOnPropertyOffset { PropertyOffsetMayChange, PropertyOffsetMustNotChange }; + std::pair<find_iterator, bool> add(const ValueType& entry, PropertyOffset&, EffectOnPropertyOffset); // Remove a value from the table. void remove(const find_iterator& iter); void remove(const KeyType& key); @@ -181,7 +194,7 @@ public: PropertyOffset nextOffset(PropertyOffset inlineCapacity); // Copy this PropertyTable, ensuring the copy has at least the capacity provided. - PassOwnPtr<PropertyTable> copy(JSGlobalData&, JSCell* owner, unsigned newCapacity); + PropertyTable* copy(VM&, JSCell* owner, unsigned newCapacity); #ifndef NDEBUG size_t sizeInMemory(); @@ -189,6 +202,10 @@ public: #endif private: + PropertyTable(VM&, unsigned initialCapacity); + PropertyTable(VM&, JSCell*, const PropertyTable&); + PropertyTable(VM&, JSCell*, unsigned initialCapacity, const PropertyTable&); + 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); @@ -235,76 +252,10 @@ private: unsigned m_deletedCount; OwnPtr< Vector<PropertyOffset> > m_deletedOffsets; - static const unsigned MinimumTableSize = 16; + static const unsigned MinimumTableSize = 8; 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&, 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(); - Heap::writeBarrier(owner, iter->specificValue.get()); - } - - // Copy the m_deletedOffsets vector. - Vector<PropertyOffset>* otherDeletedOffsets = other.m_deletedOffsets.get(); - if (otherDeletedOffsets) - m_deletedOffsets = adoptPtr(new Vector<PropertyOffset>(*otherDeletedOffsets)); -} - -inline PropertyTable::PropertyTable(JSGlobalData&, 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(); - Heap::writeBarrier(owner, iter->specificValue.get()); - } - - // Copy the m_deletedOffsets vector. - Vector<PropertyOffset>* otherDeletedOffsets = other.m_deletedOffsets.get(); - if (otherDeletedOffsets) - m_deletedOffsets = adoptPtr(new Vector<PropertyOffset>(*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())); @@ -390,12 +341,14 @@ inline PropertyTable::find_iterator PropertyTable::findWithString(const KeyType& } } -inline std::pair<PropertyTable::find_iterator, bool> PropertyTable::add(const ValueType& entry) +inline std::pair<PropertyTable::find_iterator, bool> PropertyTable::add(const ValueType& entry, PropertyOffset& offset, EffectOnPropertyOffset offsetEffect) { // Look for a value with a matching key already in the array. find_iterator iter = find(entry.key); - if (iter.first) + if (iter.first) { + RELEASE_ASSERT(iter.first->offset <= offset); return std::make_pair(iter, false); + } // Ref the key entry.key->ref(); @@ -414,6 +367,12 @@ inline std::pair<PropertyTable::find_iterator, bool> PropertyTable::add(const Va *iter.first = entry; ++m_keyCount; + + if (offsetEffect == PropertyOffsetMayChange) + offset = std::max(offset, entry.offset); + else + RELEASE_ASSERT(offset >= entry.offset); + return std::make_pair(iter, true); } @@ -491,18 +450,18 @@ inline PropertyOffset PropertyTable::nextOffset(PropertyOffset inlineCapacity) if (hasDeletedOffset()) return getDeletedOffset(); - return propertyOffsetFor(size(), inlineCapacity); + return offsetForPropertyNumber(size(), inlineCapacity); } -inline PassOwnPtr<PropertyTable> PropertyTable::copy(JSGlobalData& globalData, JSCell* owner, unsigned newCapacity) +inline PropertyTable* PropertyTable::copy(VM& vm, 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 adoptPtr(new PropertyTable(globalData, owner, *this)); - return adoptPtr(new PropertyTable(globalData, owner, newCapacity, *this)); + return PropertyTable::clone(vm, owner, *this); + return PropertyTable::clone(vm, owner, newCapacity, *this); } #ifndef NDEBUG @@ -588,7 +547,7 @@ inline size_t PropertyTable::dataSize() inline unsigned PropertyTable::sizeForCapacity(unsigned capacity) { - if (capacity < 8) + if (capacity < MinimumTableSize / 2) return MinimumTableSize; return nextPowerOf2(capacity + 1) * 2; } diff --git a/Source/JavaScriptCore/runtime/PropertyNameArray.h b/Source/JavaScriptCore/runtime/PropertyNameArray.h index 1cdac0049..96f1d0afa 100644 --- a/Source/JavaScriptCore/runtime/PropertyNameArray.h +++ b/Source/JavaScriptCore/runtime/PropertyNameArray.h @@ -52,9 +52,9 @@ namespace JSC { // FIXME: Rename to PropertyNameArrayBuilder. class PropertyNameArray { public: - PropertyNameArray(JSGlobalData* globalData) + PropertyNameArray(VM* vm) : m_data(PropertyNameArrayData::create()) - , m_globalData(globalData) + , m_vm(vm) , m_numCacheableSlots(0) , m_baseObject(0) { @@ -62,17 +62,17 @@ namespace JSC { PropertyNameArray(ExecState* exec) : m_data(PropertyNameArrayData::create()) - , m_globalData(&exec->globalData()) + , m_vm(&exec->vm()) , m_numCacheableSlots(0) , m_baseObject(0) { } - JSGlobalData* globalData() { return m_globalData; } + VM* vm() { return m_vm; } void add(const Identifier& identifier) { add(identifier.impl()); } JS_EXPORT_PRIVATE void add(StringImpl*); - void addKnownUnique(StringImpl* identifier) { m_data->propertyNameVector().append(Identifier(m_globalData, identifier)); } + void addKnownUnique(StringImpl* identifier) { m_data->propertyNameVector().append(Identifier(m_vm, identifier)); } Identifier& operator[](unsigned i) { return m_data->propertyNameVector()[i]; } const Identifier& operator[](unsigned i) const { return m_data->propertyNameVector()[i]; } @@ -106,7 +106,7 @@ namespace JSC { RefPtr<PropertyNameArrayData> m_data; IdentifierSet m_set; - JSGlobalData* m_globalData; + VM* m_vm; size_t m_numCacheableSlots; JSObject* m_baseObject; }; diff --git a/Source/JavaScriptCore/runtime/PropertyOffset.h b/Source/JavaScriptCore/runtime/PropertyOffset.h index 1a2bba446..dc0297bf7 100644 --- a/Source/JavaScriptCore/runtime/PropertyOffset.h +++ b/Source/JavaScriptCore/runtime/PropertyOffset.h @@ -28,16 +28,9 @@ #include <wtf/Platform.h> #include <wtf/StdLibExtras.h> -#include <wtf/UnusedParam.h> namespace JSC { -#if USE(JSVALUE32_64) -#define INLINE_STORAGE_CAPACITY 7 -#else -#define INLINE_STORAGE_CAPACITY 6 -#endif - typedef int PropertyOffset; static const PropertyOffset invalidOffset = -1; @@ -45,9 +38,9 @@ static const PropertyOffset firstOutOfLineOffset = 100; // Declare all of the functions because they tend to do forward calls. inline void checkOffset(PropertyOffset); -inline void checkOffset(PropertyOffset, PropertyOffset inlineCapacity); +inline void checkOffset(PropertyOffset, int inlineCapacity); inline void validateOffset(PropertyOffset); -inline void validateOffset(PropertyOffset, PropertyOffset inlineCapacity); +inline void validateOffset(PropertyOffset, int inlineCapacity); inline bool isValidOffset(PropertyOffset); inline bool isInlineOffset(PropertyOffset); inline bool isOutOfLineOffset(PropertyOffset); @@ -55,7 +48,7 @@ inline size_t offsetInInlineStorage(PropertyOffset); inline size_t offsetInOutOfLineStorage(PropertyOffset); inline size_t offsetInRespectiveStorage(PropertyOffset); inline size_t numberOfOutOfLineSlotsForLastOffset(PropertyOffset); -inline size_t numberOfSlotsForLastOffset(PropertyOffset, PropertyOffset inlineCapacity); +inline size_t numberOfSlotsForLastOffset(PropertyOffset, int inlineCapacity); inline void checkOffset(PropertyOffset offset) { @@ -63,7 +56,7 @@ inline void checkOffset(PropertyOffset offset) ASSERT(offset >= invalidOffset); } -inline void checkOffset(PropertyOffset offset, PropertyOffset inlineCapacity) +inline void checkOffset(PropertyOffset offset, int inlineCapacity) { UNUSED_PARAM(offset); UNUSED_PARAM(inlineCapacity); @@ -79,7 +72,7 @@ inline void validateOffset(PropertyOffset offset) ASSERT(isValidOffset(offset)); } -inline void validateOffset(PropertyOffset offset, PropertyOffset inlineCapacity) +inline void validateOffset(PropertyOffset offset, int inlineCapacity) { checkOffset(offset, inlineCapacity); ASSERT(isValidOffset(offset)); @@ -132,7 +125,7 @@ inline size_t numberOfOutOfLineSlotsForLastOffset(PropertyOffset offset) return offset - firstOutOfLineOffset + 1; } -inline size_t numberOfSlotsForLastOffset(PropertyOffset offset, PropertyOffset inlineCapacity) +inline size_t numberOfSlotsForLastOffset(PropertyOffset offset, int inlineCapacity) { checkOffset(offset, inlineCapacity); if (offset < inlineCapacity) @@ -140,7 +133,7 @@ inline size_t numberOfSlotsForLastOffset(PropertyOffset offset, PropertyOffset i return inlineCapacity + numberOfOutOfLineSlotsForLastOffset(offset); } -inline PropertyOffset propertyOffsetFor(PropertyOffset propertyNumber, PropertyOffset inlineCapacity) +inline PropertyOffset offsetForPropertyNumber(int propertyNumber, int inlineCapacity) { PropertyOffset offset = propertyNumber; if (offset >= inlineCapacity) { diff --git a/Source/JavaScriptCore/runtime/PropertySlot.cpp b/Source/JavaScriptCore/runtime/PropertySlot.cpp index 8ac874115..291ea487c 100644 --- a/Source/JavaScriptCore/runtime/PropertySlot.cpp +++ b/Source/JavaScriptCore/runtime/PropertySlot.cpp @@ -23,6 +23,7 @@ #include "JSFunction.h" #include "JSGlobalObject.h" +#include "Operations.h" namespace JSC { diff --git a/Source/JavaScriptCore/runtime/PropertySlot.h b/Source/JavaScriptCore/runtime/PropertySlot.h index c673eaa50..6fb80d23d 100644 --- a/Source/JavaScriptCore/runtime/PropertySlot.h +++ b/Source/JavaScriptCore/runtime/PropertySlot.h @@ -21,7 +21,7 @@ #ifndef PropertySlot_h #define PropertySlot_h -#include "JSValue.h" +#include "JSCJSValue.h" #include "PropertyName.h" #include "PropertyOffset.h" #include "Register.h" diff --git a/Source/JavaScriptCore/runtime/PropertyTable.cpp b/Source/JavaScriptCore/runtime/PropertyTable.cpp new file mode 100644 index 000000000..bb5ecce4a --- /dev/null +++ b/Source/JavaScriptCore/runtime/PropertyTable.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2013 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 COMPUTER, 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 COMPUTER, 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 "PropertyMapHashTable.h" + +#include "JSCJSValueInlines.h" +#include "JSCellInlines.h" +#include "SlotVisitorInlines.h" +#include "StructureInlines.h" + +namespace JSC { + +const ClassInfo PropertyTable::s_info = { "PropertyTable", 0, 0, 0, CREATE_METHOD_TABLE(PropertyTable) }; + +PropertyTable* PropertyTable::create(VM& vm, unsigned initialCapacity) +{ + PropertyTable* table = new (NotNull, allocateCell<PropertyTable>(vm.heap)) PropertyTable(vm, initialCapacity); + table->finishCreation(vm); + return table; +} + +PropertyTable* PropertyTable::clone(VM& vm, JSCell* owner, const PropertyTable& other) +{ + PropertyTable* table = new (NotNull, allocateCell<PropertyTable>(vm.heap)) PropertyTable(vm, owner, other); + table->finishCreation(vm); + return table; +} + +PropertyTable* PropertyTable::clone(VM& vm, JSCell* owner, unsigned initialCapacity, const PropertyTable& other) +{ + PropertyTable* table = new (NotNull, allocateCell<PropertyTable>(vm.heap)) PropertyTable(vm, owner, initialCapacity, other); + table->finishCreation(vm); + return table; +} + +PropertyTable::PropertyTable(VM& vm, unsigned initialCapacity) + : JSCell(vm, vm.propertyTableStructure.get()) + , 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)); +} + +PropertyTable::PropertyTable(VM& vm, JSCell* owner, const PropertyTable& other) + : JSCell(vm, vm.propertyTableStructure.get()) + , 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(); + Heap::writeBarrier(owner, iter->specificValue.get()); + } + + // Copy the m_deletedOffsets vector. + Vector<PropertyOffset>* otherDeletedOffsets = other.m_deletedOffsets.get(); + if (otherDeletedOffsets) + m_deletedOffsets = adoptPtr(new Vector<PropertyOffset>(*otherDeletedOffsets)); +} + +PropertyTable::PropertyTable(VM& vm, JSCell* owner, unsigned initialCapacity, const PropertyTable& other) + : JSCell(vm, vm.propertyTableStructure.get()) + , 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(); + Heap::writeBarrier(owner, iter->specificValue.get()); + } + + // Copy the m_deletedOffsets vector. + Vector<PropertyOffset>* otherDeletedOffsets = other.m_deletedOffsets.get(); + if (otherDeletedOffsets) + m_deletedOffsets = adoptPtr(new Vector<PropertyOffset>(*otherDeletedOffsets)); +} + +void PropertyTable::destroy(JSCell* cell) +{ + static_cast<PropertyTable*>(cell)->PropertyTable::~PropertyTable(); +} + +PropertyTable::~PropertyTable() +{ + iterator end = this->end(); + for (iterator iter = begin(); iter != end; ++iter) + iter->key->deref(); + + fastFree(m_index); +} + +void PropertyTable::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + PropertyTable* thisObject = jsCast<PropertyTable*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + + JSCell::visitChildren(thisObject, visitor); + + PropertyTable::iterator end = thisObject->end(); + for (PropertyTable::iterator ptr = thisObject->begin(); ptr != end; ++ptr) + visitor.append(&ptr->specificValue); +} + +} diff --git a/Source/JavaScriptCore/runtime/Protect.h b/Source/JavaScriptCore/runtime/Protect.h index 843c9e111..78dd319a3 100644 --- a/Source/JavaScriptCore/runtime/Protect.h +++ b/Source/JavaScriptCore/runtime/Protect.h @@ -23,7 +23,7 @@ #define Protect_h #include "Heap.h" -#include "JSValue.h" +#include "JSCJSValue.h" namespace JSC { diff --git a/Source/JavaScriptCore/runtime/PrototypeMap.cpp b/Source/JavaScriptCore/runtime/PrototypeMap.cpp new file mode 100644 index 000000000..29de45b10 --- /dev/null +++ b/Source/JavaScriptCore/runtime/PrototypeMap.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2013 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 "PrototypeMap.h" + +#include "JSGlobalObject.h" +#include "Operations.h" + +namespace JSC { + +void PrototypeMap::addPrototype(JSObject* object) +{ + m_prototypes.add(object, object); + + // Note that this method makes the somewhat odd decision to not check if this + // object currently has indexed accessors. We could do that check here, and if + // indexed accessors were found, we could tell the global object to have a bad + // time. But we avoid this, to allow the following to be always fast: + // + // 1) Create an object. + // 2) Give it a setter or read-only property that happens to have a numeric name. + // 3) Allocate objects that use this object as a prototype. + // + // This avoids anyone having a bad time. Even if the instance objects end up + // having indexed storage, the creation of indexed storage leads to a prototype + // chain walk that detects the presence of indexed setters and then does the + // right thing. As a result, having a bad time only happens if you add an + // indexed setter (or getter, or read-only field) to an object that is already + // used as a prototype. +} + +Structure* PrototypeMap::emptyObjectStructureForPrototype(JSObject* prototype, unsigned inlineCapacity) +{ + StructureMap::AddResult addResult = m_structures.add(std::make_pair(prototype, inlineCapacity), nullptr); + if (!addResult.isNewEntry) { + ASSERT(isPrototype(prototype)); + return addResult.iterator->value.get(); + } + + addPrototype(prototype); + Structure* structure = JSFinalObject::createStructure( + prototype->globalObject()->vm(), prototype->globalObject(), prototype, inlineCapacity); + addResult.iterator->value = structure; + return structure; +} + +void PrototypeMap::clearEmptyObjectStructureForPrototype(JSObject* object, unsigned inlineCapacity) +{ + m_structures.remove(std::make_pair(object, inlineCapacity)); +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/PrototypeMap.h b/Source/JavaScriptCore/runtime/PrototypeMap.h new file mode 100644 index 000000000..9752ca7ea --- /dev/null +++ b/Source/JavaScriptCore/runtime/PrototypeMap.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2013 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 PrototypeMap_h +#define PrototypeMap_h + +#include "WeakGCMap.h" +#include <wtf/TriState.h> + +namespace JSC { + +class JSObject; +class Structure; + +// Tracks the canonical structure an object should be allocated with when inheriting from a given prototype. +class PrototypeMap { +public: + JS_EXPORT_PRIVATE Structure* emptyObjectStructureForPrototype(JSObject*, unsigned inlineCapacity); + void clearEmptyObjectStructureForPrototype(JSObject*, unsigned inlineCapacity); + void addPrototype(JSObject*); + TriState isPrototype(JSObject*) const; // Returns a conservative estimate. + +private: + WeakGCMap<JSObject*, JSObject> m_prototypes; + typedef WeakGCMap<std::pair<JSObject*, unsigned>, Structure> StructureMap; + StructureMap m_structures; +}; + +inline TriState PrototypeMap::isPrototype(JSObject* object) const +{ + if (!m_prototypes.contains(object)) + return FalseTriState; + + // We know that 'object' was used as a prototype at one time, so be + // conservative and say that it might still be so. (It would be expensive + // to find out for sure, and we don't know of any cases where being precise + // would improve performance.) + return MixedTriState; +} + +} // namespace JSC + +#endif // PrototypeMap_h diff --git a/Source/JavaScriptCore/runtime/RegExp.cpp b/Source/JavaScriptCore/runtime/RegExp.cpp index 3229f5207..d27bc1eb1 100644 --- a/Source/JavaScriptCore/runtime/RegExp.cpp +++ b/Source/JavaScriptCore/runtime/RegExp.cpp @@ -24,16 +24,16 @@ #include "RegExp.h" #include "Lexer.h" +#include "Operations.h" #include "RegExpCache.h" -#include "yarr/Yarr.h" -#include "yarr/YarrJIT.h" +#include "Yarr.h" +#include "YarrJIT.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <wtf/Assertions.h> #include <wtf/OwnArrayPtr.h> - #define REGEXP_FUNC_TEST_DATA_GEN 0 namespace JSC { @@ -217,8 +217,8 @@ void RegExpFunctionalTestCollector::outputEscapedString(const String& s, bool es } #endif -RegExp::RegExp(JSGlobalData& globalData, const String& patternString, RegExpFlags flags) - : JSCell(globalData, globalData.regExpStructure.get()) +RegExp::RegExp(VM& vm, const String& patternString, RegExpFlags flags) + : JSCell(vm, vm.regExpStructure.get()) , m_state(NotCompiled) , m_patternString(patternString) , m_flags(flags) @@ -231,9 +231,9 @@ RegExp::RegExp(JSGlobalData& globalData, const String& patternString, RegExpFlag { } -void RegExp::finishCreation(JSGlobalData& globalData) +void RegExp::finishCreation(VM& vm) { - Base::finishCreation(globalData); + Base::finishCreation(vm); Yarr::YarrPattern pattern(m_patternString, ignoreCase(), multiline(), &m_constructionError); if (m_constructionError) m_state = ParseError; @@ -250,23 +250,23 @@ void RegExp::destroy(JSCell* cell) thisObject->RegExp::~RegExp(); } -RegExp* RegExp::createWithoutCaching(JSGlobalData& globalData, const String& patternString, RegExpFlags flags) +RegExp* RegExp::createWithoutCaching(VM& vm, const String& patternString, RegExpFlags flags) { - RegExp* regExp = new (NotNull, allocateCell<RegExp>(globalData.heap)) RegExp(globalData, patternString, flags); - regExp->finishCreation(globalData); + RegExp* regExp = new (NotNull, allocateCell<RegExp>(vm.heap)) RegExp(vm, patternString, flags); + regExp->finishCreation(vm); return regExp; } -RegExp* RegExp::create(JSGlobalData& globalData, const String& patternString, RegExpFlags flags) +RegExp* RegExp::create(VM& vm, const String& patternString, RegExpFlags flags) { - return globalData.regExpCache()->lookupOrCreate(patternString, flags); + return vm.regExpCache()->lookupOrCreate(patternString, flags); } -void RegExp::compile(JSGlobalData* globalData, Yarr::YarrCharSize charSize) +void RegExp::compile(VM* vm, Yarr::YarrCharSize charSize) { Yarr::YarrPattern pattern(m_patternString, ignoreCase(), multiline(), &m_constructionError); if (m_constructionError) { - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); m_state = ParseError; return; } @@ -274,13 +274,13 @@ void RegExp::compile(JSGlobalData* globalData, Yarr::YarrCharSize charSize) if (!hasCode()) { ASSERT(m_state == NotCompiled); - globalData->regExpCache()->addToStrongCache(this); + vm->regExpCache()->addToStrongCache(this); m_state = ByteCode; } #if ENABLE(YARR_JIT) - if (!pattern.m_containsBackreferences && globalData->canUseRegExpJIT()) { - Yarr::jitCompile(pattern, charSize, globalData, m_regExpJITCode); + if (!pattern.m_containsBackreferences && vm->canUseRegExpJIT()) { + Yarr::jitCompile(pattern, charSize, vm, m_regExpJITCode); #if ENABLE(YARR_JIT_DEBUG) if (!m_regExpJITCode.isFallBack()) m_state = JITCode; @@ -297,10 +297,10 @@ void RegExp::compile(JSGlobalData* globalData, Yarr::YarrCharSize charSize) UNUSED_PARAM(charSize); #endif - m_regExpBytecode = Yarr::byteCompile(pattern, &globalData->m_regExpAllocator); + m_regExpBytecode = Yarr::byteCompile(pattern, &vm->m_regExpAllocator); } -void RegExp::compileIfNecessary(JSGlobalData& globalData, Yarr::YarrCharSize charSize) +void RegExp::compileIfNecessary(VM& vm, Yarr::YarrCharSize charSize) { if (hasCode()) { #if ENABLE(YARR_JIT) @@ -315,17 +315,17 @@ void RegExp::compileIfNecessary(JSGlobalData& globalData, Yarr::YarrCharSize cha #endif } - compile(&globalData, charSize); + compile(&vm, charSize); } -int RegExp::match(JSGlobalData& globalData, const String& s, unsigned startOffset, Vector<int, 32>& ovector) +int RegExp::match(VM& vm, const String& s, unsigned startOffset, Vector<int, 32>& ovector) { #if ENABLE(REGEXP_TRACING) m_rtMatchCallCount++; #endif ASSERT(m_state != ParseError); - compileIfNecessary(globalData, s.is8Bit() ? Yarr::Char8 : Yarr::Char16); + compileIfNecessary(vm, s.is8Bit() ? Yarr::Char8 : Yarr::Char16); int offsetVectorSize = (m_numSubpatterns + 1) * 2; ovector.resize(offsetVectorSize); @@ -384,11 +384,11 @@ int RegExp::match(JSGlobalData& globalData, const String& s, unsigned startOffse return result; } -void RegExp::compileMatchOnly(JSGlobalData* globalData, Yarr::YarrCharSize charSize) +void RegExp::compileMatchOnly(VM* vm, Yarr::YarrCharSize charSize) { Yarr::YarrPattern pattern(m_patternString, ignoreCase(), multiline(), &m_constructionError); if (m_constructionError) { - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); m_state = ParseError; return; } @@ -396,13 +396,13 @@ void RegExp::compileMatchOnly(JSGlobalData* globalData, Yarr::YarrCharSize charS if (!hasCode()) { ASSERT(m_state == NotCompiled); - globalData->regExpCache()->addToStrongCache(this); + vm->regExpCache()->addToStrongCache(this); m_state = ByteCode; } #if ENABLE(YARR_JIT) - if (!pattern.m_containsBackreferences && globalData->canUseRegExpJIT()) { - Yarr::jitCompile(pattern, charSize, globalData, m_regExpJITCode, Yarr::MatchOnly); + if (!pattern.m_containsBackreferences && vm->canUseRegExpJIT()) { + Yarr::jitCompile(pattern, charSize, vm, m_regExpJITCode, Yarr::MatchOnly); #if ENABLE(YARR_JIT_DEBUG) if (!m_regExpJITCode.isFallBack()) m_state = JITCode; @@ -419,10 +419,10 @@ void RegExp::compileMatchOnly(JSGlobalData* globalData, Yarr::YarrCharSize charS UNUSED_PARAM(charSize); #endif - m_regExpBytecode = Yarr::byteCompile(pattern, &globalData->m_regExpAllocator); + m_regExpBytecode = Yarr::byteCompile(pattern, &vm->m_regExpAllocator); } -void RegExp::compileIfNecessaryMatchOnly(JSGlobalData& globalData, Yarr::YarrCharSize charSize) +void RegExp::compileIfNecessaryMatchOnly(VM& vm, Yarr::YarrCharSize charSize) { if (hasCode()) { #if ENABLE(YARR_JIT) @@ -437,17 +437,17 @@ void RegExp::compileIfNecessaryMatchOnly(JSGlobalData& globalData, Yarr::YarrCha #endif } - compileMatchOnly(&globalData, charSize); + compileMatchOnly(&vm, charSize); } -MatchResult RegExp::match(JSGlobalData& globalData, const String& s, unsigned startOffset) +MatchResult RegExp::match(VM& vm, const String& s, unsigned startOffset) { #if ENABLE(REGEXP_TRACING) m_rtMatchCallCount++; #endif ASSERT(m_state != ParseError); - compileIfNecessaryMatchOnly(globalData, s.is8Bit() ? Yarr::Char8 : Yarr::Char16); + compileIfNecessaryMatchOnly(vm, s.is8Bit() ? Yarr::Char8 : Yarr::Char16); #if ENABLE(YARR_JIT) if (m_state == JITCode) { diff --git a/Source/JavaScriptCore/runtime/RegExp.h b/Source/JavaScriptCore/runtime/RegExp.h index b2b65d90c..94ea316a8 100644 --- a/Source/JavaScriptCore/runtime/RegExp.h +++ b/Source/JavaScriptCore/runtime/RegExp.h @@ -38,7 +38,7 @@ namespace JSC { struct RegExpRepresentation; - class JSGlobalData; + class VM; JS_EXPORT_PRIVATE RegExpFlags regExpFlags(const String&); @@ -46,7 +46,7 @@ namespace JSC { public: typedef JSCell Base; - JS_EXPORT_PRIVATE static RegExp* create(JSGlobalData&, const String& pattern, RegExpFlags); + JS_EXPORT_PRIVATE static RegExp* create(VM&, const String& pattern, RegExpFlags); static const bool needsDestruction = true; static const bool hasImmortalStructure = true; static void destroy(JSCell*); @@ -60,8 +60,8 @@ namespace JSC { bool isValid() const { return !m_constructionError && m_flags != InvalidFlags; } const char* errorMessage() const { return m_constructionError; } - JS_EXPORT_PRIVATE int match(JSGlobalData&, const String&, unsigned startOffset, Vector<int, 32>& ovector); - MatchResult match(JSGlobalData&, const String&, unsigned startOffset); + JS_EXPORT_PRIVATE int match(VM&, const String&, unsigned startOffset, Vector<int, 32>& ovector); + MatchResult match(VM&, const String&, unsigned startOffset); unsigned numSubpatterns() const { return m_numSubpatterns; } bool hasCode() @@ -75,9 +75,9 @@ namespace JSC { void printTraceData(); #endif - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(LeafType, 0), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(LeafType, 0), &s_info); } static const ClassInfo s_info; @@ -85,13 +85,13 @@ namespace JSC { RegExpKey key() { return RegExpKey(m_flags, m_patternString); } protected: - void finishCreation(JSGlobalData&); + void finishCreation(VM&); private: friend class RegExpCache; - RegExp(JSGlobalData&, const String&, RegExpFlags); + RegExp(VM&, const String&, RegExpFlags); - static RegExp* createWithoutCaching(JSGlobalData&, const String&, RegExpFlags); + static RegExp* createWithoutCaching(VM&, const String&, RegExpFlags); enum RegExpState { ParseError, @@ -100,11 +100,11 @@ namespace JSC { NotCompiled } m_state; - void compile(JSGlobalData*, Yarr::YarrCharSize); - void compileIfNecessary(JSGlobalData&, Yarr::YarrCharSize); + void compile(VM*, Yarr::YarrCharSize); + void compileIfNecessary(VM&, Yarr::YarrCharSize); - void compileMatchOnly(JSGlobalData*, Yarr::YarrCharSize); - void compileIfNecessaryMatchOnly(JSGlobalData&, Yarr::YarrCharSize); + void compileMatchOnly(VM*, Yarr::YarrCharSize); + void compileIfNecessaryMatchOnly(VM&, Yarr::YarrCharSize); #if ENABLE(YARR_JIT_DEBUG) void matchCompareWithInterpreter(const String&, int startOffset, int* offsetVector, int jitResult); diff --git a/Source/JavaScriptCore/runtime/RegExpCache.cpp b/Source/JavaScriptCore/runtime/RegExpCache.cpp index 8acafba23..1ab3f5f51 100644 --- a/Source/JavaScriptCore/runtime/RegExpCache.cpp +++ b/Source/JavaScriptCore/runtime/RegExpCache.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2010 University of Szeged * Copyright (C) 2010 Renata Hodovan (hodovan@inf.u-szeged.hu) + * Copyright (C) 2012 Apple Inc. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,8 +27,9 @@ */ #include "config.h" - #include "RegExpCache.h" + +#include "Operations.h" #include "RegExpObject.h" #include "StrongInlines.h" @@ -39,18 +41,18 @@ RegExp* RegExpCache::lookupOrCreate(const String& patternString, RegExpFlags fla if (RegExp* regExp = m_weakCache.get(key)) return regExp; - RegExp* regExp = RegExp::createWithoutCaching(*m_globalData, patternString, flags); + RegExp* regExp = RegExp::createWithoutCaching(*m_vm, patternString, flags); #if ENABLE(REGEXP_TRACING) - m_globalData->addRegExpToTrace(regExp); + m_vm->addRegExpToTrace(regExp); #endif weakAdd(m_weakCache, key, PassWeak<RegExp>(regExp, this)); return regExp; } -RegExpCache::RegExpCache(JSGlobalData* globalData) +RegExpCache::RegExpCache(VM* vm) : m_nextEntryInStrongCache(0) - , m_globalData(globalData) + , m_vm(vm) { } @@ -66,7 +68,7 @@ void RegExpCache::addToStrongCache(RegExp* regExp) String pattern = regExp->pattern(); if (pattern.length() > maxStrongCacheablePatternLength) return; - m_strongCache[m_nextEntryInStrongCache].set(*m_globalData, regExp); + m_strongCache[m_nextEntryInStrongCache].set(*m_vm, regExp); m_nextEntryInStrongCache++; if (m_nextEntryInStrongCache == maxStrongCacheableEntries) m_nextEntryInStrongCache = 0; diff --git a/Source/JavaScriptCore/runtime/RegExpCache.h b/Source/JavaScriptCore/runtime/RegExpCache.h index c6a4a0aa2..4f854d1ba 100644 --- a/Source/JavaScriptCore/runtime/RegExpCache.h +++ b/Source/JavaScriptCore/runtime/RegExpCache.h @@ -29,6 +29,7 @@ #include "RegExpKey.h" #include "Strong.h" #include "Weak.h" +#include "WeakInlines.h" #include <wtf/FixedArray.h> #include <wtf/HashMap.h> @@ -42,7 +43,7 @@ friend class RegExp; typedef HashMap<RegExpKey, Weak<RegExp> > RegExpCacheMap; public: - RegExpCache(JSGlobalData* globalData); + RegExpCache(VM* vm); void invalidateCode(); private: @@ -58,7 +59,7 @@ private: RegExpCacheMap m_weakCache; // Holds all regular expressions currently live. int m_nextEntryInStrongCache; WTF::FixedArray<Strong<RegExp>, maxStrongCacheableEntries> m_strongCache; // Holds a select few regular expressions that have compiled and executed - JSGlobalData* m_globalData; + VM* m_vm; }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp b/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp index 47cff15f1..c54b4783d 100644 --- a/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp +++ b/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "RegExpCachedResult.h" +#include "Operations.h" #include "RegExpMatchesArray.h" namespace JSC { @@ -41,8 +42,8 @@ void RegExpCachedResult::visitChildren(SlotVisitor& visitor) RegExpMatchesArray* RegExpCachedResult::lastResult(ExecState* exec, JSObject* owner) { if (m_result) { - m_reifiedInput.set(exec->globalData(), owner, m_lastInput.get()); - m_reifiedResult.set(exec->globalData(), owner, RegExpMatchesArray::create(exec, m_lastInput.get(), m_lastRegExp.get(), m_result)); + m_reifiedInput.set(exec->vm(), owner, m_lastInput.get()); + m_reifiedResult.set(exec->vm(), owner, RegExpMatchesArray::create(exec, m_lastInput.get(), m_lastRegExp.get(), m_result)); m_result = MatchResult::failed(); } return m_reifiedResult.get(); @@ -53,7 +54,7 @@ void RegExpCachedResult::setInput(ExecState* exec, JSObject* owner, JSString* in // Make sure we're reified, otherwise m_reifiedInput will be ignored. lastResult(exec, owner); ASSERT(!m_result); - m_reifiedInput.set(exec->globalData(), owner, input); + m_reifiedInput.set(exec->vm(), owner, input); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/RegExpCachedResult.h b/Source/JavaScriptCore/runtime/RegExpCachedResult.h index 812ff4336..d2763bc77 100644 --- a/Source/JavaScriptCore/runtime/RegExpCachedResult.h +++ b/Source/JavaScriptCore/runtime/RegExpCachedResult.h @@ -44,17 +44,17 @@ namespace JSC { // m_reifiedResult and m_reifiedInput hold the cached results. class RegExpCachedResult { public: - RegExpCachedResult(JSGlobalData& globalData, JSObject* owner, RegExp* emptyRegExp) + RegExpCachedResult(VM& vm, JSObject* owner, RegExp* emptyRegExp) : m_result(0, 0) { - m_lastInput.set(globalData, owner, jsEmptyString(&globalData)); - m_lastRegExp.set(globalData, owner, emptyRegExp); + m_lastInput.set(vm, owner, jsEmptyString(&vm)); + m_lastRegExp.set(vm, owner, emptyRegExp); } - ALWAYS_INLINE void record(JSGlobalData& globalData, JSObject* owner, RegExp* regExp, JSString* input, MatchResult result) + ALWAYS_INLINE void record(VM& vm, JSObject* owner, RegExp* regExp, JSString* input, MatchResult result) { - m_lastRegExp.set(globalData, owner, regExp); - m_lastInput.set(globalData, owner, input); + m_lastRegExp.set(vm, owner, regExp); + m_lastInput.set(vm, owner, input); m_result = result; } diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp index cc6ceb1d1..8b12a5a05 100644 --- a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp +++ b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp @@ -23,6 +23,7 @@ #include "RegExpConstructor.h" #include "Error.h" +#include "Operations.h" #include "RegExpMatchesArray.h" #include "RegExpPrototype.h" @@ -83,21 +84,21 @@ const ClassInfo RegExpConstructor::s_info = { "Function", &InternalFunction::s_i RegExpConstructor::RegExpConstructor(JSGlobalObject* globalObject, Structure* structure, RegExpPrototype* regExpPrototype) : InternalFunction(globalObject, structure) - , m_cachedResult(globalObject->globalData(), this, regExpPrototype->regExp()) + , m_cachedResult(globalObject->vm(), this, regExpPrototype->regExp()) , m_multiline(false) { } void RegExpConstructor::finishCreation(ExecState* exec, RegExpPrototype* regExpPrototype) { - Base::finishCreation(exec->globalData(), Identifier(exec, "RegExp").string()); + Base::finishCreation(exec->vm(), Identifier(exec, "RegExp").string()); ASSERT(inherits(&s_info)); // ECMA 15.10.5.1 RegExp.prototype - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, regExpPrototype, DontEnum | DontDelete | ReadOnly); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().prototype, regExpPrototype, DontEnum | DontDelete | ReadOnly); // no. of arguments for constructor - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(2), ReadOnly | DontDelete | DontEnum); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().length, jsNumber(2), ReadOnly | DontDelete | DontEnum); } void RegExpConstructor::destroy(JSCell* cell) @@ -282,7 +283,7 @@ JSObject* constructRegExp(ExecState* exec, JSGlobalObject* globalObject, const A return throwError(exec, createSyntaxError(exec, ASCIILiteral("Invalid flags supplied to RegExp constructor."))); } - RegExp* regExp = RegExp::create(exec->globalData(), pattern, flags); + RegExp* regExp = RegExp::create(exec->vm(), pattern, flags); if (!regExp->isValid()) return throwError(exec, createSyntaxError(exec, regExp->errorMessage())); return RegExpObject::create(exec, exec->lexicalGlobalObject(), globalObject->regExpStructure(), regExp); diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.h b/Source/JavaScriptCore/runtime/RegExpConstructor.h index 2cb1c1204..0942070d5 100644 --- a/Source/JavaScriptCore/runtime/RegExpConstructor.h +++ b/Source/JavaScriptCore/runtime/RegExpConstructor.h @@ -43,9 +43,9 @@ namespace JSC { return constructor; } - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); @@ -55,8 +55,8 @@ namespace JSC { static const ClassInfo s_info; - MatchResult performMatch(JSGlobalData&, RegExp*, JSString*, const String&, int startOffset, int** ovector); - MatchResult performMatch(JSGlobalData&, RegExp*, JSString*, const String&, int startOffset); + MatchResult performMatch(VM&, RegExp*, JSString*, const String&, int startOffset, int** ovector); + MatchResult performMatch(VM&, RegExp*, JSString*, const String&, int startOffset); void setMultiline(bool multiline) { m_multiline = multiline; } bool multiline() const { return m_multiline; } @@ -101,9 +101,9 @@ namespace JSC { expression matching through the performMatch function. We use cached results to calculate, e.g., RegExp.lastMatch and RegExp.leftParen. */ - ALWAYS_INLINE MatchResult RegExpConstructor::performMatch(JSGlobalData& globalData, RegExp* regExp, JSString* string, const String& input, int startOffset, int** ovector) + ALWAYS_INLINE MatchResult RegExpConstructor::performMatch(VM& vm, RegExp* regExp, JSString* string, const String& input, int startOffset, int** ovector) { - int position = regExp->match(globalData, input, startOffset, m_ovector); + int position = regExp->match(vm, input, startOffset, m_ovector); if (ovector) *ovector = m_ovector.data(); @@ -116,15 +116,15 @@ namespace JSC { ASSERT(m_ovector[1] >= position); size_t end = m_ovector[1]; - m_cachedResult.record(globalData, this, regExp, string, MatchResult(position, end)); + m_cachedResult.record(vm, this, regExp, string, MatchResult(position, end)); return MatchResult(position, end); } - ALWAYS_INLINE MatchResult RegExpConstructor::performMatch(JSGlobalData& globalData, RegExp* regExp, JSString* string, const String& input, int startOffset) + ALWAYS_INLINE MatchResult RegExpConstructor::performMatch(VM& vm, RegExp* regExp, JSString* string, const String& input, int startOffset) { - MatchResult result = regExp->match(globalData, input, startOffset); + MatchResult result = regExp->match(vm, input, startOffset); if (result) - m_cachedResult.record(globalData, this, regExp, string, result); + m_cachedResult.record(vm, this, regExp, string, result); return result; } diff --git a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp index 19f3b81ad..062650a86 100644 --- a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp +++ b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp @@ -27,33 +27,34 @@ #include "RegExpMatchesArray.h" #include "ButterflyInlines.h" +#include "Operations.h" namespace JSC { const ClassInfo RegExpMatchesArray::s_info = {"Array", &JSArray::s_info, 0, 0, CREATE_METHOD_TABLE(RegExpMatchesArray)}; -RegExpMatchesArray::RegExpMatchesArray(JSGlobalData& globalData, Butterfly* butterfly, JSGlobalObject* globalObject, JSString* input, RegExp* regExp, MatchResult result) - : JSArray(globalData, globalObject->regExpMatchesArrayStructure(), butterfly) +RegExpMatchesArray::RegExpMatchesArray(VM& vm, Butterfly* butterfly, JSGlobalObject* globalObject, JSString* input, RegExp* regExp, MatchResult result) + : JSArray(vm, globalObject->regExpMatchesArrayStructure(), butterfly) , m_result(result) , m_state(ReifiedNone) { - m_input.set(globalData, this, input); - m_regExp.set(globalData, this, regExp); + m_input.set(vm, this, input); + m_regExp.set(vm, this, regExp); } RegExpMatchesArray* RegExpMatchesArray::create(ExecState* exec, JSString* input, RegExp* regExp, MatchResult result) { ASSERT(result); - JSGlobalData& globalData = exec->globalData(); - Butterfly* butterfly = createArrayButterfly(globalData, regExp->numSubpatterns() + 1); - RegExpMatchesArray* array = new (NotNull, allocateCell<RegExpMatchesArray>(globalData.heap)) RegExpMatchesArray(globalData, butterfly, exec->lexicalGlobalObject(), input, regExp, result); - array->finishCreation(globalData); + VM& vm = exec->vm(); + Butterfly* butterfly = createArrayButterfly(vm, regExp->numSubpatterns() + 1); + RegExpMatchesArray* array = new (NotNull, allocateCell<RegExpMatchesArray>(vm.heap)) RegExpMatchesArray(vm, butterfly, exec->lexicalGlobalObject(), input, regExp, result); + array->finishCreation(vm); return array; } -void RegExpMatchesArray::finishCreation(JSGlobalData& globalData) +void RegExpMatchesArray::finishCreation(VM& vm) { - Base::finishCreation(globalData); + Base::finishCreation(vm); } void RegExpMatchesArray::visitChildren(JSCell* cell, SlotVisitor& visitor) @@ -77,7 +78,7 @@ void RegExpMatchesArray::reifyAllProperties(ExecState* exec) if (unsigned numSubpatterns = m_regExp->numSubpatterns()) { Vector<int, 32> subpatternResults; - int position = m_regExp->match(exec->globalData(), m_input->value(exec), m_result.start, subpatternResults); + int position = m_regExp->match(exec->vm(), m_input->value(exec), m_result.start, subpatternResults); ASSERT_UNUSED(position, position >= 0 && static_cast<size_t>(position) == m_result.start); ASSERT(m_result.start == static_cast<size_t>(subpatternResults[0])); ASSERT(m_result.end == static_cast<size_t>(subpatternResults[1])); diff --git a/Source/JavaScriptCore/runtime/RegExpMatchesArray.h b/Source/JavaScriptCore/runtime/RegExpMatchesArray.h index a5b860b9d..c7c942052 100644 --- a/Source/JavaScriptCore/runtime/RegExpMatchesArray.h +++ b/Source/JavaScriptCore/runtime/RegExpMatchesArray.h @@ -28,7 +28,7 @@ namespace JSC { class RegExpMatchesArray : public JSArray { private: - RegExpMatchesArray(JSGlobalData&, Butterfly*, JSGlobalObject*, JSString*, RegExp*, MatchResult); + RegExpMatchesArray(VM&, Butterfly*, JSGlobalObject*, JSString*, RegExp*, MatchResult); enum ReifiedState { ReifiedNone, ReifiedMatch, ReifiedAll }; @@ -42,15 +42,15 @@ namespace JSC { static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info, ArrayWithArrayStorage); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info, ArrayWithSlowPutArrayStorage); } static void visitChildren(JSCell*, SlotVisitor&); protected: - void finishCreation(JSGlobalData&); + void finishCreation(VM&); static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags; diff --git a/Source/JavaScriptCore/runtime/RegExpObject.cpp b/Source/JavaScriptCore/runtime/RegExpObject.cpp index 00dd1ed74..8b2d03c02 100644 --- a/Source/JavaScriptCore/runtime/RegExpObject.cpp +++ b/Source/JavaScriptCore/runtime/RegExpObject.cpp @@ -30,6 +30,7 @@ #include "JSString.h" #include "Lexer.h" #include "Lookup.h" +#include "Operations.h" #include "RegExpConstructor.h" #include "RegExpMatchesArray.h" #include "RegExpPrototype.h" @@ -63,8 +64,8 @@ const ClassInfo RegExpObject::s_info = { "RegExp", &Base::s_info, 0, ExecState:: */ RegExpObject::RegExpObject(JSGlobalObject* globalObject, Structure* structure, RegExp* regExp) - : JSNonFinalObject(globalObject->globalData(), structure) - , m_regExp(globalObject->globalData(), this, regExp) + : JSNonFinalObject(globalObject->vm(), structure) + , m_regExp(globalObject->vm(), this, regExp) , m_lastIndexIsWritable(true) { m_lastIndex.setWithoutWriteBarrier(jsNumber(0)); @@ -72,7 +73,7 @@ RegExpObject::RegExpObject(JSGlobalObject* globalObject, Structure* structure, R void RegExpObject::finishCreation(JSGlobalObject* globalObject) { - Base::finishCreation(globalObject->globalData()); + Base::finishCreation(globalObject->vm()); ASSERT(inherits(&s_info)); } @@ -314,9 +315,9 @@ MatchResult RegExpObject::match(ExecState* exec, JSString* string) RegExp* regExp = this->regExp(); RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); String input = string->value(exec); - JSGlobalData& globalData = exec->globalData(); + VM& vm = exec->vm(); if (!regExp->global()) - return regExpConstructor->performMatch(globalData, regExp, string, input, 0); + return regExpConstructor->performMatch(vm, regExp, string, input, 0); JSValue jsLastIndex = getLastIndex(); unsigned lastIndex; @@ -335,7 +336,7 @@ MatchResult RegExpObject::match(ExecState* exec, JSString* string) lastIndex = static_cast<unsigned>(doubleLastIndex); } - MatchResult result = regExpConstructor->performMatch(globalData, regExp, string, input, lastIndex); + MatchResult result = regExpConstructor->performMatch(vm, regExp, string, input, lastIndex); setLastIndex(exec, result.end); return result; } diff --git a/Source/JavaScriptCore/runtime/RegExpObject.h b/Source/JavaScriptCore/runtime/RegExpObject.h index f43d6bc79..7ed3dea91 100644 --- a/Source/JavaScriptCore/runtime/RegExpObject.h +++ b/Source/JavaScriptCore/runtime/RegExpObject.h @@ -37,14 +37,14 @@ namespace JSC { return object; } - static RegExpObject* create(JSGlobalData& globalData, JSGlobalObject* globalObject, Structure* structure, RegExp* regExp) + static RegExpObject* create(VM& vm, JSGlobalObject* globalObject, Structure* structure, RegExp* regExp) { - RegExpObject* object = new (NotNull, allocateCell<RegExpObject>(globalData.heap)) RegExpObject(globalObject, structure, regExp); + RegExpObject* object = new (NotNull, allocateCell<RegExpObject>(vm.heap)) RegExpObject(globalObject, structure, regExp); object->finishCreation(globalObject); return object; } - void setRegExp(JSGlobalData& globalData, RegExp* r) { m_regExp.set(globalData, this, r); } + void setRegExp(VM& vm, RegExp* r) { m_regExp.set(vm, this, r); } RegExp* regExp() const { return m_regExp.get(); } void setLastIndex(ExecState* exec, size_t lastIndex) @@ -58,7 +58,7 @@ namespace JSC { void setLastIndex(ExecState* exec, JSValue lastIndex, bool shouldThrow) { if (LIKELY(m_lastIndexIsWritable)) - m_lastIndex.set(exec->globalData(), this, lastIndex); + m_lastIndex.set(exec->vm(), this, lastIndex); else if (shouldThrow) throwTypeError(exec, StrictModeReadonlyPropertyWriteError); } @@ -76,9 +76,9 @@ namespace JSC { static JS_EXPORTDATA const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } protected: diff --git a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp index e4bf2cf9a..daebcbc1d 100644 --- a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp +++ b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp @@ -24,12 +24,13 @@ #include "ArrayPrototype.h" #include "Error.h" #include "JSArray.h" +#include "JSCJSValue.h" #include "JSFunction.h" #include "JSObject.h" #include "JSString.h" #include "JSStringBuilder.h" -#include "JSValue.h" #include "ObjectPrototype.h" +#include "Operations.h" #include "RegExpObject.h" #include "RegExp.h" #include "RegExpCache.h" @@ -119,13 +120,13 @@ EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec) if (flags == InvalidFlags) return throwVMError(exec, createSyntaxError(exec, ASCIILiteral("Invalid flags supplied to RegExp constructor."))); } - regExp = RegExp::create(exec->globalData(), pattern, flags); + regExp = RegExp::create(exec->vm(), pattern, flags); } if (!regExp->isValid()) return throwVMError(exec, createSyntaxError(exec, regExp->errorMessage())); - asRegExpObject(thisValue)->setRegExp(exec->globalData(), regExp); + asRegExpObject(thisValue)->setRegExp(exec->vm(), regExp); asRegExpObject(thisValue)->setLastIndex(exec, 0); return JSValue::encode(jsUndefined()); } diff --git a/Source/JavaScriptCore/runtime/RegExpPrototype.h b/Source/JavaScriptCore/runtime/RegExpPrototype.h index 78c6ae1d4..703306be7 100644 --- a/Source/JavaScriptCore/runtime/RegExpPrototype.h +++ b/Source/JavaScriptCore/runtime/RegExpPrototype.h @@ -39,9 +39,9 @@ namespace JSC { static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } protected: diff --git a/Source/JavaScriptCore/runtime/SmallStrings.cpp b/Source/JavaScriptCore/runtime/SmallStrings.cpp index 56a359279..5f35cca5e 100644 --- a/Source/JavaScriptCore/runtime/SmallStrings.cpp +++ b/Source/JavaScriptCore/runtime/SmallStrings.cpp @@ -29,6 +29,7 @@ #include "HeapRootVisitor.h" #include "JSGlobalObject.h" #include "JSString.h" +#include "Operations.h" #include <wtf/Noncopyable.h> #include <wtf/PassOwnPtr.h> #include <wtf/text/StringImpl.h> @@ -80,6 +81,22 @@ SmallStrings::SmallStrings() m_singleCharacterStrings[i] = 0; } +void SmallStrings::initializeCommonStrings(VM& vm) +{ + createEmptyString(&vm); +#define JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE(name) initialize(&vm, m_##name, #name); + JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE) +#undef JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE +} + +void SmallStrings::visitStrongReferences(SlotVisitor& visitor) +{ + visitor.appendUnbarrieredPointer(&m_emptyString); +#define JSC_COMMON_STRINGS_ATTRIBUTE_VISIT(name) visitor.appendUnbarrieredPointer(&m_##name); + JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_VISIT) +#undef JSC_COMMON_STRINGS_ATTRIBUTE_VISIT +} + SmallStrings::~SmallStrings() { } @@ -89,23 +106,20 @@ void SmallStrings::finalizeSmallStrings() finalize(m_emptyString); for (unsigned i = 0; i < singleCharacterStringCount; ++i) finalize(m_singleCharacterStrings[i]); -#define JSC_COMMON_STRINGS_ATTRIBUTE_FINALIZE(name) finalize(m_##name); - JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_FINALIZE) -#undef JSC_COMMON_STRINGS_ATTRIBUTE_FINALIZE } -void SmallStrings::createEmptyString(JSGlobalData* globalData) +void SmallStrings::createEmptyString(VM* vm) { ASSERT(!m_emptyString); - m_emptyString = JSString::createHasOtherOwner(*globalData, StringImpl::empty()); + m_emptyString = JSString::createHasOtherOwner(*vm, StringImpl::empty()); } -void SmallStrings::createSingleCharacterString(JSGlobalData* globalData, unsigned char character) +void SmallStrings::createSingleCharacterString(VM* vm, unsigned char character) { if (!m_storage) m_storage = adoptPtr(new SmallStringsStorage); ASSERT(!m_singleCharacterStrings[character]); - m_singleCharacterStrings[character] = JSString::createHasOtherOwner(*globalData, PassRefPtr<StringImpl>(m_storage->rep(character))); + m_singleCharacterStrings[character] = JSString::createHasOtherOwner(*vm, PassRefPtr<StringImpl>(m_storage->rep(character))); } StringImpl* SmallStrings::singleCharacterStringRep(unsigned char character) @@ -115,9 +129,9 @@ StringImpl* SmallStrings::singleCharacterStringRep(unsigned char character) return m_storage->rep(character); } -void SmallStrings::initialize(JSGlobalData* globalData, JSString*& string, const char* value) const +void SmallStrings::initialize(VM* vm, JSString*& string, const char* value) const { - string = JSString::create(*globalData, StringImpl::create(value)); + string = JSString::create(*vm, StringImpl::create(value)); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/SmallStrings.h b/Source/JavaScriptCore/runtime/SmallStrings.h index 5bc9d2252..f00043021 100644 --- a/Source/JavaScriptCore/runtime/SmallStrings.h +++ b/Source/JavaScriptCore/runtime/SmallStrings.h @@ -26,6 +26,8 @@ #ifndef SmallStrings_h #define SmallStrings_h +#include "WriteBarrier.h" + #include <wtf/FixedArray.h> #include <wtf/Noncopyable.h> #include <wtf/OwnPtr.h> @@ -48,7 +50,7 @@ class StringImpl; namespace JSC { class HeapRootVisitor; - class JSGlobalData; + class VM; class JSString; class SmallStringsStorage; class SlotVisitor; @@ -61,17 +63,15 @@ namespace JSC { SmallStrings(); ~SmallStrings(); - JSString* emptyString(JSGlobalData* globalData) + JSString* emptyString() { - if (!m_emptyString) - createEmptyString(globalData); return m_emptyString; } - JSString* singleCharacterString(JSGlobalData* globalData, unsigned char character) + JSString* singleCharacterString(VM* vm, unsigned char character) { if (!m_singleCharacterStrings[character]) - createSingleCharacterString(globalData, character); + createSingleCharacterString(vm, character); return m_singleCharacterStrings[character]; } @@ -81,11 +81,12 @@ namespace JSC { JSString** singleCharacterStrings() { return &m_singleCharacterStrings[0]; } + void initializeCommonStrings(VM&); + void visitStrongReferences(SlotVisitor&); + #define JSC_COMMON_STRINGS_ACCESSOR_DEFINITION(name) \ - JSString* name##String(JSGlobalData* globalData) const \ + JSString* name##String() const \ { \ - if (!m_##name) \ - initialize(globalData, m_##name, #name); \ return m_##name; \ } JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ACCESSOR_DEFINITION) @@ -94,13 +95,13 @@ namespace JSC { private: static const unsigned singleCharacterStringCount = maxSingleCharacterString + 1; - JS_EXPORT_PRIVATE void createEmptyString(JSGlobalData*); - JS_EXPORT_PRIVATE void createSingleCharacterString(JSGlobalData*, unsigned char); + JS_EXPORT_PRIVATE void createEmptyString(VM*); + JS_EXPORT_PRIVATE void createSingleCharacterString(VM*, unsigned char); - void initialize(JSGlobalData* globalData, JSString*& string, const char* value) const; + void initialize(VM* vm, JSString*& string, const char* value) const; JSString* m_emptyString; -#define JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION(name) mutable JSString* m_##name; +#define JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION(name) JSString* m_##name; JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION) #undef JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION JSString* m_singleCharacterStrings[singleCharacterStringCount]; diff --git a/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp b/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp index 7f21e2c9f..1997c5b70 100644 --- a/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp +++ b/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp @@ -29,6 +29,7 @@ #include "ClassInfo.h" #include "GetterSetter.h" #include "JSObject.h" +#include "Operations.h" #include "PropertySlot.h" #include "Reject.h" #include "SlotVisitor.h" @@ -38,8 +39,8 @@ namespace JSC { const ClassInfo SparseArrayValueMap::s_info = { "SparseArrayValueMap", 0, 0, 0, CREATE_METHOD_TABLE(SparseArrayValueMap) }; -SparseArrayValueMap::SparseArrayValueMap(JSGlobalData& globalData) - : Base(globalData, globalData.sparseArrayValueMapStructure.get()) +SparseArrayValueMap::SparseArrayValueMap(VM& vm) + : Base(vm, vm.sparseArrayValueMapStructure.get()) , m_flags(Normal) , m_reportedCapacity(0) { @@ -49,15 +50,15 @@ SparseArrayValueMap::~SparseArrayValueMap() { } -void SparseArrayValueMap::finishCreation(JSGlobalData& globalData) +void SparseArrayValueMap::finishCreation(VM& vm) { - Base::finishCreation(globalData); + Base::finishCreation(vm); } -SparseArrayValueMap* SparseArrayValueMap::create(JSGlobalData& globalData) +SparseArrayValueMap* SparseArrayValueMap::create(VM& vm) { - SparseArrayValueMap* result = new (NotNull, allocateCell<SparseArrayValueMap>(globalData.heap)) SparseArrayValueMap(globalData); - result->finishCreation(globalData); + SparseArrayValueMap* result = new (NotNull, allocateCell<SparseArrayValueMap>(vm.heap)) SparseArrayValueMap(vm); + result->finishCreation(vm); return result; } @@ -66,9 +67,9 @@ void SparseArrayValueMap::destroy(JSCell* cell) static_cast<SparseArrayValueMap*>(cell)->SparseArrayValueMap::~SparseArrayValueMap(); } -Structure* SparseArrayValueMap::createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) +Structure* SparseArrayValueMap::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(CompoundType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, StructureFlags), &s_info); } SparseArrayValueMap::AddResult SparseArrayValueMap::add(JSObject* array, unsigned i) @@ -117,7 +118,7 @@ bool SparseArrayValueMap::putDirect(ExecState* exec, JSObject* array, unsigned i } entry.attributes = attributes; - entry.set(exec->globalData(), this, value); + entry.set(exec->vm(), this, value); return true; } @@ -171,7 +172,7 @@ void SparseArrayEntry::put(ExecState* exec, JSValue thisValue, SparseArrayValueM return; } - set(exec->globalData(), map, value); + set(exec->vm(), map, value); return; } diff --git a/Source/JavaScriptCore/runtime/SparseArrayValueMap.h b/Source/JavaScriptCore/runtime/SparseArrayValueMap.h index 366a7b8ba..31b279fa7 100644 --- a/Source/JavaScriptCore/runtime/SparseArrayValueMap.h +++ b/Source/JavaScriptCore/runtime/SparseArrayValueMap.h @@ -65,10 +65,10 @@ private: LengthIsReadOnly = 2, }; - SparseArrayValueMap(JSGlobalData&); + SparseArrayValueMap(VM&); ~SparseArrayValueMap(); - void finishCreation(JSGlobalData&); + void finishCreation(VM&); static const unsigned StructureFlags = OverridesVisitChildren | JSCell::StructureFlags; @@ -79,13 +79,13 @@ public: typedef Map::const_iterator const_iterator; typedef Map::AddResult AddResult; - static SparseArrayValueMap* create(JSGlobalData&); + static SparseArrayValueMap* create(VM&); static const bool needsDestruction = true; static const bool hasImmortalStructure = true; static void destroy(JSCell*); - static Structure* createStructure(JSGlobalData&, JSGlobalObject*, JSValue prototype); + static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype); static void visitChildren(JSCell*, SlotVisitor&); diff --git a/Source/JavaScriptCore/runtime/StrictEvalActivation.cpp b/Source/JavaScriptCore/runtime/StrictEvalActivation.cpp index b1f28c8aa..eaef9397b 100644 --- a/Source/JavaScriptCore/runtime/StrictEvalActivation.cpp +++ b/Source/JavaScriptCore/runtime/StrictEvalActivation.cpp @@ -27,6 +27,7 @@ #include "StrictEvalActivation.h" #include "JSGlobalObject.h" +#include "Operations.h" namespace JSC { @@ -36,7 +37,7 @@ const ClassInfo StrictEvalActivation::s_info = { "Object", &Base::s_info, 0, 0, StrictEvalActivation::StrictEvalActivation(ExecState* exec) : Base( - exec->globalData(), + exec->vm(), exec->lexicalGlobalObject()->strictEvalActivationStructure(), exec->scope() ) diff --git a/Source/JavaScriptCore/runtime/StrictEvalActivation.h b/Source/JavaScriptCore/runtime/StrictEvalActivation.h index 9f64feb15..df490d5e7 100644 --- a/Source/JavaScriptCore/runtime/StrictEvalActivation.h +++ b/Source/JavaScriptCore/runtime/StrictEvalActivation.h @@ -37,16 +37,16 @@ public: static StrictEvalActivation* create(ExecState* exec) { StrictEvalActivation* activation = new (NotNull, allocateCell<StrictEvalActivation>(*exec->heap())) StrictEvalActivation(exec); - activation->finishCreation(exec->globalData()); + activation->finishCreation(exec->vm()); return activation; } static bool deleteProperty(JSCell*, ExecState*, PropertyName); static JSObject* toThisObject(JSCell*, ExecState*); - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } static const ClassInfo s_info; diff --git a/Source/JavaScriptCore/runtime/StringConstructor.cpp b/Source/JavaScriptCore/runtime/StringConstructor.cpp index 7f36a84be..df507ce07 100644 --- a/Source/JavaScriptCore/runtime/StringConstructor.cpp +++ b/Source/JavaScriptCore/runtime/StringConstructor.cpp @@ -25,6 +25,7 @@ #include "JITCode.h" #include "JSFunction.h" #include "JSGlobalObject.h" +#include "Operations.h" #include "StringPrototype.h" namespace JSC { @@ -54,9 +55,9 @@ StringConstructor::StringConstructor(JSGlobalObject* globalObject, Structure* st void StringConstructor::finishCreation(ExecState* exec, StringPrototype* stringPrototype) { - Base::finishCreation(exec->globalData(), stringPrototype->classInfo()->className); - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, stringPrototype, ReadOnly | DontEnum | DontDelete); - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontEnum | DontDelete); + Base::finishCreation(exec->vm(), stringPrototype->classInfo()->className); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().prototype, stringPrototype, ReadOnly | DontEnum | DontDelete); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontEnum | DontDelete); } bool StringConstructor::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot &slot) @@ -88,6 +89,11 @@ static EncodedJSValue JSC_HOST_CALL stringFromCharCode(ExecState* exec) return JSValue::encode(stringFromCharCodeSlowCase(exec)); } +JSCell* JSC_HOST_CALL stringFromCharCode(ExecState* exec, int32_t arg) +{ + return jsSingleCharacterString(exec, arg); +} + static EncodedJSValue JSC_HOST_CALL constructWithStringConstructor(ExecState* exec) { JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject(); diff --git a/Source/JavaScriptCore/runtime/StringConstructor.h b/Source/JavaScriptCore/runtime/StringConstructor.h index 11f70d499..40e574c02 100644 --- a/Source/JavaScriptCore/runtime/StringConstructor.h +++ b/Source/JavaScriptCore/runtime/StringConstructor.h @@ -40,9 +40,9 @@ namespace JSC { static const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } protected: @@ -57,6 +57,8 @@ namespace JSC { static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); }; + + JSCell* JSC_HOST_CALL stringFromCharCode(ExecState*, int32_t); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/StringObject.cpp b/Source/JavaScriptCore/runtime/StringObject.cpp index ab7d6cb23..bdbe27fe6 100644 --- a/Source/JavaScriptCore/runtime/StringObject.cpp +++ b/Source/JavaScriptCore/runtime/StringObject.cpp @@ -23,6 +23,7 @@ #include "Error.h" #include "JSGlobalObject.h" +#include "Operations.h" #include "PropertyNameArray.h" namespace JSC { @@ -31,16 +32,16 @@ ASSERT_HAS_TRIVIAL_DESTRUCTOR(StringObject); const ClassInfo StringObject::s_info = { "String", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(StringObject) }; -StringObject::StringObject(JSGlobalData& globalData, Structure* structure) - : JSWrapperObject(globalData, structure) +StringObject::StringObject(VM& vm, Structure* structure) + : JSWrapperObject(vm, structure) { } -void StringObject::finishCreation(JSGlobalData& globalData, JSString* string) +void StringObject::finishCreation(VM& vm, JSString* string) { - Base::finishCreation(globalData); + Base::finishCreation(vm); ASSERT(inherits(&s_info)); - setInternalValue(globalData, string); + setInternalValue(vm, string); } bool StringObject::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot) @@ -165,7 +166,7 @@ void StringObject::getOwnPropertyNames(JSObject* object, ExecState* exec, Proper StringObject* constructString(ExecState* exec, JSGlobalObject* globalObject, JSValue string) { StringObject* object = StringObject::create(exec, globalObject->stringObjectStructure()); - object->setInternalValue(exec->globalData(), string); + object->setInternalValue(exec->vm(), string); return object; } diff --git a/Source/JavaScriptCore/runtime/StringObject.h b/Source/JavaScriptCore/runtime/StringObject.h index 4369eace1..6a92541c1 100644 --- a/Source/JavaScriptCore/runtime/StringObject.h +++ b/Source/JavaScriptCore/runtime/StringObject.h @@ -33,14 +33,14 @@ namespace JSC { static StringObject* create(ExecState* exec, Structure* structure) { JSString* string = jsEmptyString(exec); - StringObject* object = new (NotNull, allocateCell<StringObject>(*exec->heap())) StringObject(exec->globalData(), structure); - object->finishCreation(exec->globalData(), string); + StringObject* object = new (NotNull, allocateCell<StringObject>(*exec->heap())) StringObject(exec->vm(), structure); + object->finishCreation(exec->vm(), string); return object; } static StringObject* create(ExecState* exec, Structure* structure, JSString* string) { - StringObject* object = new (NotNull, allocateCell<StringObject>(*exec->heap())) StringObject(exec->globalData(), structure); - object->finishCreation(exec->globalData(), string); + StringObject* object = new (NotNull, allocateCell<StringObject>(*exec->heap())) StringObject(exec->vm(), structure); + object->finishCreation(exec->vm(), string); return object; } static StringObject* create(ExecState*, JSGlobalObject*, JSString*); @@ -61,15 +61,15 @@ namespace JSC { JSString* internalValue() const { return asString(JSWrapperObject::internalValue());} - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } protected: - JS_EXPORT_PRIVATE void finishCreation(JSGlobalData&, JSString*); + JS_EXPORT_PRIVATE void finishCreation(VM&, JSString*); static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames | JSWrapperObject::StructureFlags; - JS_EXPORT_PRIVATE StringObject(JSGlobalData&, Structure*); + JS_EXPORT_PRIVATE StringObject(VM&, Structure*); }; StringObject* asStringObject(JSValue); diff --git a/Source/JavaScriptCore/runtime/StringPrototype.cpp b/Source/JavaScriptCore/runtime/StringPrototype.cpp index 25f989776..c422fd17b 100644 --- a/Source/JavaScriptCore/runtime/StringPrototype.cpp +++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013 Apple Inc. All rights reserved. * Copyright (C) 2009 Torch Mobile, Inc. * * This library is free software; you can redistribute it and/or @@ -82,80 +82,67 @@ static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState*); static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState*); static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState*); -} - -#include "StringPrototype.lut.h" - -namespace JSC { - -const ClassInfo StringPrototype::s_info = { "String", &StringObject::s_info, 0, ExecState::stringTable, CREATE_METHOD_TABLE(StringPrototype) }; - -/* Source for StringPrototype.lut.h -@begin stringTable 26 - toString stringProtoFuncToString DontEnum|Function 0 - valueOf stringProtoFuncToString DontEnum|Function 0 - charAt stringProtoFuncCharAt DontEnum|Function 1 - charCodeAt stringProtoFuncCharCodeAt DontEnum|Function 1 - concat stringProtoFuncConcat DontEnum|Function 1 - indexOf stringProtoFuncIndexOf DontEnum|Function 1 - lastIndexOf stringProtoFuncLastIndexOf DontEnum|Function 1 - match stringProtoFuncMatch DontEnum|Function 1 - replace stringProtoFuncReplace DontEnum|Function 2 - search stringProtoFuncSearch DontEnum|Function 1 - slice stringProtoFuncSlice DontEnum|Function 2 - split stringProtoFuncSplit DontEnum|Function 2 - substr stringProtoFuncSubstr DontEnum|Function 2 - substring stringProtoFuncSubstring DontEnum|Function 2 - toLowerCase stringProtoFuncToLowerCase DontEnum|Function 0 - toUpperCase stringProtoFuncToUpperCase DontEnum|Function 0 - localeCompare stringProtoFuncLocaleCompare DontEnum|Function 1 - - # toLocaleLowerCase and toLocaleUpperCase are currently identical to toLowerCase and toUpperCase - toLocaleLowerCase stringProtoFuncToLowerCase DontEnum|Function 0 - toLocaleUpperCase stringProtoFuncToUpperCase DontEnum|Function 0 - - big stringProtoFuncBig DontEnum|Function 0 - small stringProtoFuncSmall DontEnum|Function 0 - blink stringProtoFuncBlink DontEnum|Function 0 - bold stringProtoFuncBold DontEnum|Function 0 - fixed stringProtoFuncFixed DontEnum|Function 0 - italics stringProtoFuncItalics DontEnum|Function 0 - strike stringProtoFuncStrike DontEnum|Function 0 - sub stringProtoFuncSub DontEnum|Function 0 - sup stringProtoFuncSup DontEnum|Function 0 - fontcolor stringProtoFuncFontcolor DontEnum|Function 1 - fontsize stringProtoFuncFontsize DontEnum|Function 1 - anchor stringProtoFuncAnchor DontEnum|Function 1 - link stringProtoFuncLink DontEnum|Function 1 - trim stringProtoFuncTrim DontEnum|Function 0 - trimLeft stringProtoFuncTrimLeft DontEnum|Function 0 - trimRight stringProtoFuncTrimRight DontEnum|Function 0 -@end -*/ +const ClassInfo StringPrototype::s_info = { "String", &StringObject::s_info, 0, 0, CREATE_METHOD_TABLE(StringPrototype) }; // ECMA 15.5.4 StringPrototype::StringPrototype(ExecState* exec, Structure* structure) - : StringObject(exec->globalData(), structure) + : StringObject(exec->vm(), structure) { } -void StringPrototype::finishCreation(ExecState* exec, JSGlobalObject*, JSString* nameAndMessage) +void StringPrototype::finishCreation(ExecState* exec, JSGlobalObject* globalObject, JSString* nameAndMessage) { - Base::finishCreation(exec->globalData(), nameAndMessage); + VM& vm = exec->vm(); + + Base::finishCreation(vm, nameAndMessage); ASSERT(inherits(&s_info)); - // The constructor will be added later, after StringConstructor has been built - putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum); -} + JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->toString, stringProtoFuncToString, DontEnum, 0, StringPrototypeValueOfIntrinsic); + JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->valueOf, stringProtoFuncToString, DontEnum, 0, StringPrototypeValueOfIntrinsic); + JSC_NATIVE_INTRINSIC_FUNCTION("charAt", stringProtoFuncCharAt, DontEnum, 1, CharAtIntrinsic); + JSC_NATIVE_INTRINSIC_FUNCTION("charCodeAt", stringProtoFuncCharCodeAt, DontEnum, 1, CharCodeAtIntrinsic); + JSC_NATIVE_FUNCTION("concat", stringProtoFuncConcat, DontEnum, 1); + JSC_NATIVE_FUNCTION("indexOf", stringProtoFuncIndexOf, DontEnum, 1); + JSC_NATIVE_FUNCTION("lastIndexOf", stringProtoFuncLastIndexOf, DontEnum, 1); + JSC_NATIVE_FUNCTION("match", stringProtoFuncMatch, DontEnum, 1); + JSC_NATIVE_FUNCTION("replace", stringProtoFuncReplace, DontEnum, 2); + JSC_NATIVE_FUNCTION("search", stringProtoFuncSearch, DontEnum, 1); + JSC_NATIVE_FUNCTION("slice", stringProtoFuncSlice, DontEnum, 2); + JSC_NATIVE_FUNCTION("split", stringProtoFuncSplit, DontEnum, 2); + JSC_NATIVE_FUNCTION("substr", stringProtoFuncSubstr, DontEnum, 2); + JSC_NATIVE_FUNCTION("substring", stringProtoFuncSubstring, DontEnum, 2); + JSC_NATIVE_FUNCTION("toLowerCase", stringProtoFuncToLowerCase, DontEnum, 0); + JSC_NATIVE_FUNCTION("toUpperCase", stringProtoFuncToUpperCase, DontEnum, 0); + JSC_NATIVE_FUNCTION("localeCompare", stringProtoFuncLocaleCompare, DontEnum, 1); + JSC_NATIVE_FUNCTION("toLocaleLowerCase", stringProtoFuncToLowerCase, DontEnum, 0); + JSC_NATIVE_FUNCTION("toLocaleUpperCase", stringProtoFuncToUpperCase, DontEnum, 0); + JSC_NATIVE_FUNCTION("big", stringProtoFuncBig, DontEnum, 0); + JSC_NATIVE_FUNCTION("small", stringProtoFuncSmall, DontEnum, 0); + JSC_NATIVE_FUNCTION("blink", stringProtoFuncBlink, DontEnum, 0); + JSC_NATIVE_FUNCTION("bold", stringProtoFuncBold, DontEnum, 0); + JSC_NATIVE_FUNCTION("fixed", stringProtoFuncFixed, DontEnum, 0); + JSC_NATIVE_FUNCTION("italics", stringProtoFuncItalics, DontEnum, 0); + JSC_NATIVE_FUNCTION("strike", stringProtoFuncStrike, DontEnum, 0); + JSC_NATIVE_FUNCTION("sub", stringProtoFuncSub, DontEnum, 0); + JSC_NATIVE_FUNCTION("sup", stringProtoFuncSup, DontEnum, 0); + JSC_NATIVE_FUNCTION("fontcolor", stringProtoFuncFontcolor, DontEnum, 1); + JSC_NATIVE_FUNCTION("fontsize", stringProtoFuncFontsize, DontEnum, 1); + JSC_NATIVE_FUNCTION("anchor", stringProtoFuncAnchor, DontEnum, 1); + JSC_NATIVE_FUNCTION("link", stringProtoFuncLink, DontEnum, 1); + JSC_NATIVE_FUNCTION("trim", stringProtoFuncTrim, DontEnum, 0); + JSC_NATIVE_FUNCTION("trimLeft", stringProtoFuncTrimLeft, DontEnum, 0); + JSC_NATIVE_FUNCTION("trimRight", stringProtoFuncTrimRight, DontEnum, 0); -bool StringPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot &slot) -{ - return getStaticFunctionSlot<StringObject>(exec, ExecState::stringTable(exec), jsCast<StringPrototype*>(cell), propertyName, slot); + // The constructor will be added later, after StringConstructor has been built + putDirectWithoutTransition(exec->vm(), exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum); } -bool StringPrototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor) +StringPrototype* StringPrototype::create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure) { - return getStaticFunctionDescriptor<StringObject>(exec, ExecState::stringTable(exec), jsCast<StringPrototype*>(object), propertyName, descriptor); + JSString* empty = jsEmptyString(exec); + StringPrototype* prototype = new (NotNull, allocateCell<StringPrototype>(*exec->heap())) StringPrototype(exec, structure); + prototype->finishCreation(exec, globalObject, empty); + return prototype; } // ------------------------------ Functions -------------------------- @@ -418,12 +405,12 @@ static NEVER_INLINE EncodedJSValue removeUsingRegExpSearch(ExecState* exec, JSSt unsigned startPosition = 0; Vector<StringRange, 16> sourceRanges; - JSGlobalData* globalData = &exec->globalData(); + VM* vm = &exec->vm(); RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); unsigned sourceLen = source.length(); while (true) { - MatchResult result = regExpConstructor->performMatch(*globalData, regExp, string, source, startPosition); + MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, source, startPosition); if (!result) break; @@ -493,11 +480,11 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS CachedCall cachedCall(exec, func, argCount); if (exec->hadException()) return JSValue::encode(jsNull()); - JSGlobalData* globalData = &exec->globalData(); + VM* vm = &exec->vm(); if (source.is8Bit()) { while (true) { int* ovector; - MatchResult result = regExpConstructor->performMatch(*globalData, regExp, string, source, startPosition, &ovector); + MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, source, startPosition, &ovector); if (!result) break; @@ -511,7 +498,7 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS if (matchStart < 0) cachedCall.setArgument(i, jsUndefined()); else - cachedCall.setArgument(i, jsSubstring8(globalData, source, matchStart, matchLen)); + cachedCall.setArgument(i, jsSubstring8(vm, source, matchStart, matchLen)); } cachedCall.setArgument(i++, jsNumber(result.start)); @@ -536,7 +523,7 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS } else { while (true) { int* ovector; - MatchResult result = regExpConstructor->performMatch(*globalData, regExp, string, source, startPosition, &ovector); + MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, source, startPosition, &ovector); if (!result) break; @@ -550,7 +537,7 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS if (matchStart < 0) cachedCall.setArgument(i, jsUndefined()); else - cachedCall.setArgument(i, jsSubstring(globalData, source, matchStart, matchLen)); + cachedCall.setArgument(i, jsSubstring(vm, source, matchStart, matchLen)); } cachedCall.setArgument(i++, jsNumber(result.start)); @@ -574,10 +561,10 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS } } } else { - JSGlobalData* globalData = &exec->globalData(); + VM* vm = &exec->vm(); do { int* ovector; - MatchResult result = regExpConstructor->performMatch(*globalData, regExp, string, source, startPosition, &ovector); + MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, source, startPosition, &ovector); if (!result) break; @@ -810,7 +797,12 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState* exec) else if (!(dpos <= len)) // true for NaN dpos = len; - size_t result = s.reverseFind(u2, static_cast<unsigned>(dpos)); + size_t result; + unsigned startPosition = static_cast<unsigned>(dpos); + if (!startPosition) + result = s.startsWith(u2) ? 0 : notFound; + else + result = s.reverseFind(u2, startPosition); if (result == notFound) return JSValue::encode(jsNumber(-1)); return JSValue::encode(jsNumber(result)); @@ -823,7 +815,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec) return throwVMTypeError(exec); JSString* string = thisValue.toString(exec); String s = string->value(exec); - JSGlobalData* globalData = &exec->globalData(); + VM* vm = &exec->vm(); JSValue a0 = exec->argument(0); @@ -845,12 +837,12 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec) * replaced with the result of the expression new RegExp(regexp). * Per ECMA 15.10.4.1, if a0 is undefined substitute the empty string. */ - regExp = RegExp::create(exec->globalData(), a0.isUndefined() ? String("") : a0.toString(exec)->value(exec), NoFlags); + regExp = RegExp::create(exec->vm(), a0.isUndefined() ? String("") : a0.toString(exec)->value(exec), NoFlags); if (!regExp->isValid()) return throwVMError(exec, createSyntaxError(exec, regExp->errorMessage())); } RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); - MatchResult result = regExpConstructor->performMatch(*globalData, regExp, string, s, 0); + MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, s, 0); // case without 'g' flag is handled like RegExp.prototype.exec if (!global) return JSValue::encode(result ? RegExpMatchesArray::create(exec, string, regExp, result) : jsNull()); @@ -863,7 +855,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec) list.append(jsSubstring(exec, s, result.start, length)); if (!length) ++end; - result = regExpConstructor->performMatch(*globalData, regExp, string, s, end); + result = regExpConstructor->performMatch(*vm, regExp, string, s, end); } if (list.isEmpty()) { // if there are no matches at all, it's important to return @@ -882,7 +874,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec) return throwVMTypeError(exec); JSString* string = thisValue.toString(exec); String s = string->value(exec); - JSGlobalData* globalData = &exec->globalData(); + VM* vm = &exec->vm(); JSValue a0 = exec->argument(0); @@ -896,12 +888,12 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec) * replaced with the result of the expression new RegExp(regexp). * Per ECMA 15.10.4.1, if a0 is undefined substitute the empty string. */ - reg = RegExp::create(exec->globalData(), a0.isUndefined() ? String("") : a0.toString(exec)->value(exec), NoFlags); + reg = RegExp::create(exec->vm(), a0.isUndefined() ? String("") : a0.toString(exec)->value(exec), NoFlags); if (!reg->isValid()) return throwVMError(exec, createSyntaxError(exec, reg->errorMessage())); } RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); - MatchResult result = regExpConstructor->performMatch(*globalData, reg, string, s, 0); + MatchResult result = regExpConstructor->performMatch(*vm, reg, string, s, 0); return JSValue::encode(result ? jsNumber(result.start) : jsNumber(-1)); } @@ -991,7 +983,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec) // otherwise let R = ToString(separator). JSValue separatorValue = exec->argument(0); if (separatorValue.inherits(&RegExpObject::s_info)) { - JSGlobalData* globalData = &exec->globalData(); + VM* vm = &exec->vm(); RegExp* reg = asRegExpObject(separatorValue)->regExp(); // 9. If lim == 0, return A. @@ -1014,7 +1006,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec) // c. Call the [[DefineOwnProperty]] internal method of A with arguments "0", // Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false. // d. Return A. - if (!reg->match(*globalData, input, 0)) + if (!reg->match(*vm, input, 0)) result->putDirectIndex(exec, 0, jsStringWithReuse(exec, thisValue, input)); return JSValue::encode(result); } @@ -1025,7 +1017,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec) while (matchPosition < input.length()) { // a. Call SplitMatch(S, q, R) and let z be its MatchResult result. Vector<int, 32> ovector; - int mpos = reg->match(*globalData, input, matchPosition, ovector); + int mpos = reg->match(*vm, input, matchPosition, ovector); // b. If z is failure, then let q = q + 1. if (mpos < 0) break; @@ -1290,9 +1282,6 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState* exec) { - if (exec->argumentCount() < 1) - return JSValue::encode(jsNumber(0)); - JSValue thisValue = exec->hostThisValue(); if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible return throwVMTypeError(exec); diff --git a/Source/JavaScriptCore/runtime/StringPrototype.h b/Source/JavaScriptCore/runtime/StringPrototype.h index b846c7bb3..a7aca4c3e 100644 --- a/Source/JavaScriptCore/runtime/StringPrototype.h +++ b/Source/JavaScriptCore/runtime/StringPrototype.h @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2013 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 @@ -34,27 +34,18 @@ namespace JSC { public: typedef StringObject Base; - static StringPrototype* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure) - { - JSString* empty = jsEmptyString(exec); - StringPrototype* prototype = new (NotNull, allocateCell<StringPrototype>(*exec->heap())) StringPrototype(exec, structure); - prototype->finishCreation(exec, globalObject, empty); - return prototype; - } - - static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); - static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); + static StringPrototype* create(ExecState*, JSGlobalObject*, Structure*); - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } static const ClassInfo s_info; protected: void finishCreation(ExecState*, JSGlobalObject*, JSString*); - static const unsigned StructureFlags = OverridesGetOwnPropertySlot | StringObject::StructureFlags; + static const unsigned StructureFlags = StringObject::StructureFlags; }; diff --git a/Source/JavaScriptCore/runtime/StringRecursionChecker.cpp b/Source/JavaScriptCore/runtime/StringRecursionChecker.cpp index 22b7367bc..8835a5c1c 100644 --- a/Source/JavaScriptCore/runtime/StringRecursionChecker.cpp +++ b/Source/JavaScriptCore/runtime/StringRecursionChecker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,6 +22,7 @@ #include "Error.h" #include "ExceptionHelpers.h" +#include "Operations.h" namespace JSC { diff --git a/Source/JavaScriptCore/runtime/StringRecursionChecker.h b/Source/JavaScriptCore/runtime/StringRecursionChecker.h index a1b4a51fe..6f236f1f1 100644 --- a/Source/JavaScriptCore/runtime/StringRecursionChecker.h +++ b/Source/JavaScriptCore/runtime/StringRecursionChecker.h @@ -21,6 +21,7 @@ #define StringRecursionChecker_h #include "Interpreter.h" +#include "VMStackBounds.h" #include <wtf/StackStats.h> #include <wtf/WTFThreadData.h> @@ -49,10 +50,11 @@ private: inline JSValue StringRecursionChecker::performCheck() { - const StackBounds& nativeStack = wtfThreadData().stack(); + VM& vm = m_exec->vm(); + const VMStackBounds nativeStack(vm, wtfThreadData().stack()); if (!nativeStack.isSafeToRecurse()) return throwStackOverflowError(); - bool alreadyVisited = !m_exec->globalData().stringRecursionCheckVisitedObjects.add(m_thisObject).isNewEntry; + bool alreadyVisited = !vm.stringRecursionCheckVisitedObjects.add(m_thisObject).isNewEntry; if (alreadyVisited) return emptyString(); // Return empty string to avoid infinite recursion. return JSValue(); // Indicate success. @@ -74,8 +76,8 @@ inline StringRecursionChecker::~StringRecursionChecker() { if (m_earlyReturnValue) return; - ASSERT(m_exec->globalData().stringRecursionCheckVisitedObjects.contains(m_thisObject)); - m_exec->globalData().stringRecursionCheckVisitedObjects.remove(m_thisObject); + ASSERT(m_exec->vm().stringRecursionCheckVisitedObjects.contains(m_thisObject)); + m_exec->vm().stringRecursionCheckVisitedObjects.remove(m_thisObject); } } diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp index 9ffe3b060..f551eaecc 100644 --- a/Source/JavaScriptCore/runtime/Structure.cpp +++ b/Source/JavaScriptCore/runtime/Structure.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009, 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,11 +26,13 @@ #include "config.h" #include "Structure.h" +#include "CodeBlock.h" #include "JSObject.h" #include "JSPropertyNameIterator.h" #include "Lookup.h" #include "PropertyNameArray.h" #include "StructureChain.h" +#include "StructureRareDataInlines.h" #include <wtf/RefCountedLeakCounter.h> #include <wtf/RefPtr.h> #include <wtf/Threading.h> @@ -79,21 +81,21 @@ inline Structure* StructureTransitionTable::get(StringImpl* rep, unsigned attrib return map()->get(make_pair(rep, attributes)); } -inline void StructureTransitionTable::add(JSGlobalData& globalData, Structure* structure) +inline void StructureTransitionTable::add(VM& vm, Structure* structure) { if (isUsingSingleSlot()) { Structure* existingTransition = singleTransition(); // This handles the first transition being added. if (!existingTransition) { - setSingleTransition(globalData, structure); + setSingleTransition(vm, structure); return; } // This handles the second transition being added // (or the first transition being despecified!) setMap(new TransitionMap()); - add(globalData, existingTransition); + add(vm, existingTransition); } // Add the structure to the map. @@ -101,7 +103,7 @@ inline void StructureTransitionTable::add(JSGlobalData& globalData, Structure* s // Newer versions of the STL have an std::make_pair function that takes rvalue references. // When either of the parameters are bitfields, the C++ compiler will try to bind them as lvalues, which is invalid. To work around this, use unary "+" to make the parameter an rvalue. // See https://bugs.webkit.org/show_bug.cgi?id=59261 for more details - map()->set(globalData, make_pair(structure->m_nameInPrevious, +structure->m_attributesInPrevious), structure); + map()->set(make_pair(structure->m_nameInPrevious, +structure->m_attributesInPrevious), structure); } void Structure::dumpStatistics() @@ -120,7 +122,7 @@ void Structure::dumpStatistics() switch (structure->m_transitionTable.size()) { case 0: ++numberLeaf; - if (!structure->m_previous) + if (!structure->previousID()) ++numberSingletons; break; @@ -129,9 +131,9 @@ void Structure::dumpStatistics() break; } - if (structure->m_propertyTable) { + if (structure->propertyTable()) { ++numberWithPropertyMaps; - totalPropertyMapsSize += structure->m_propertyTable->sizeInMemory(); + totalPropertyMapsSize += structure->propertyTable()->sizeInMemory(); } } @@ -149,17 +151,16 @@ void Structure::dumpStatistics() #endif } -Structure::Structure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, PropertyOffset inlineCapacity) - : JSCell(globalData, globalData.structureStructure.get()) - , m_typeInfo(typeInfo) - , m_indexingType(indexingType) - , m_globalObject(globalData, this, globalObject, WriteBarrier<JSGlobalObject>::MayBeNull) - , m_prototype(globalData, this, prototype) +Structure::Structure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, unsigned inlineCapacity) + : JSCell(vm, vm.structureStructure.get()) + , m_globalObject(vm, this, globalObject, WriteBarrier<JSGlobalObject>::MayBeNull) + , m_prototype(vm, this, prototype) , m_classInfo(classInfo) , m_transitionWatchpointSet(InitializedWatching) - , m_outOfLineCapacity(0) - , m_inlineCapacity(inlineCapacity) , m_offset(invalidOffset) + , m_typeInfo(typeInfo) + , m_indexingType(indexingType) + , m_inlineCapacity(inlineCapacity) , m_dictionaryKind(NoneDictionaryKind) , m_isPinnedPropertyTable(false) , m_hasGetterSetterProperties(false) @@ -171,20 +172,22 @@ Structure::Structure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSV , m_didTransition(false) , m_staticFunctionReified(false) { + ASSERT(inlineCapacity <= JSFinalObject::maxInlineCapacity()); + ASSERT(static_cast<PropertyOffset>(inlineCapacity) < firstOutOfLineOffset); + ASSERT(!typeInfo.structureHasRareData()); } const ClassInfo Structure::s_info = { "Structure", 0, 0, 0, CREATE_METHOD_TABLE(Structure) }; -Structure::Structure(JSGlobalData& globalData) +Structure::Structure(VM& vm) : JSCell(CreatingEarlyCell) - , m_typeInfo(CompoundType, OverridesVisitChildren) - , m_indexingType(0) - , m_prototype(globalData, this, jsNull()) + , m_prototype(vm, this, jsNull()) , m_classInfo(&s_info) , m_transitionWatchpointSet(InitializedWatching) - , m_outOfLineCapacity(0) - , m_inlineCapacity(0) , m_offset(invalidOffset) + , m_typeInfo(CompoundType, OverridesVisitChildren) + , m_indexingType(0) + , m_inlineCapacity(0) , m_dictionaryKind(NoneDictionaryKind) , m_isPinnedPropertyTable(false) , m_hasGetterSetterProperties(false) @@ -198,16 +201,15 @@ Structure::Structure(JSGlobalData& globalData) { } -Structure::Structure(JSGlobalData& globalData, const Structure* previous) - : JSCell(globalData, globalData.structureStructure.get()) - , m_typeInfo(previous->typeInfo()) - , m_indexingType(previous->indexingTypeIncludingHistory()) - , m_prototype(globalData, this, previous->storedPrototype()) +Structure::Structure(VM& vm, const Structure* previous) + : JSCell(vm, vm.structureStructure.get()) + , m_prototype(vm, this, previous->storedPrototype()) , m_classInfo(previous->m_classInfo) , m_transitionWatchpointSet(InitializedWatching) - , m_outOfLineCapacity(previous->m_outOfLineCapacity) - , m_inlineCapacity(previous->m_inlineCapacity) , m_offset(invalidOffset) + , m_typeInfo(previous->typeInfo().type(), previous->typeInfo().flags() & ~StructureHasRareData) + , m_indexingType(previous->indexingTypeIncludingHistory()) + , m_inlineCapacity(previous->m_inlineCapacity) , m_dictionaryKind(previous->m_dictionaryKind) , m_isPinnedPropertyTable(false) , m_hasGetterSetterProperties(previous->m_hasGetterSetterProperties) @@ -219,9 +221,14 @@ Structure::Structure(JSGlobalData& globalData, const Structure* previous) , m_didTransition(true) , m_staticFunctionReified(previous->m_staticFunctionReified) { + if (previous->typeInfo().structureHasRareData() && previous->rareData()->needsCloning()) + cloneRareDataFrom(vm, previous); + else if (previous->previousID()) + m_previousOrRareData.set(vm, this, previous->previousID()); + previous->notifyTransitionFromThisStructure(); if (previous->m_globalObject) - m_globalObject.set(globalData, this, previous->m_globalObject.get()); + m_globalObject.set(vm, this, previous->m_globalObject.get()); } void Structure::destroy(JSCell* cell) @@ -229,10 +236,10 @@ void Structure::destroy(JSCell* cell) static_cast<Structure*>(cell)->Structure::~Structure(); } -void Structure::materializePropertyMap(JSGlobalData& globalData) +void Structure::materializePropertyMap(VM& vm) { ASSERT(structure()->classInfo() == &s_info); - ASSERT(!m_propertyTable); + ASSERT(!propertyTable()); Vector<Structure*, 8> structures; structures.append(this); @@ -242,26 +249,28 @@ void Structure::materializePropertyMap(JSGlobalData& globalData) // 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); + ASSERT(structure->propertyTable()); + ASSERT(!structure->previousID()); - m_propertyTable = structure->m_propertyTable->copy(globalData, 0, numberOfSlotsForLastOffset(m_offset, m_typeInfo.type())); + propertyTable().set(vm, this, structure->propertyTable()->copy(vm, 0, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity))); break; } structures.append(structure); } - if (!m_propertyTable) - createPropertyMap(numberOfSlotsForLastOffset(m_offset, m_typeInfo.type())); + if (!propertyTable()) + createPropertyMap(vm, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity)); - for (ptrdiff_t i = structures.size() - 2; i >= 0; --i) { + for (ptrdiff_t i = structures.size() - 1; i >= 0; --i) { structure = structures[i]; if (!structure->m_nameInPrevious) continue; - PropertyMapEntry entry(globalData, this, structure->m_nameInPrevious.get(), structure->m_offset, structure->m_attributesInPrevious, structure->m_specificValueInPrevious.get()); - m_propertyTable->add(entry); + PropertyMapEntry entry(vm, this, structure->m_nameInPrevious.get(), structure->m_offset, structure->m_attributesInPrevious, structure->m_specificValueInPrevious.get()); + propertyTable()->add(entry, m_offset, PropertyTable::PropertyOffsetMustNotChange); } + + checkOffsetConsistency(); } inline size_t nextOutOfLineStorageCapacity(size_t currentCapacity) @@ -271,26 +280,21 @@ inline size_t nextOutOfLineStorageCapacity(size_t currentCapacity) return currentCapacity * outOfLineGrowthFactor; } -void Structure::growOutOfLineCapacity() -{ - m_outOfLineCapacity = nextOutOfLineStorageCapacity(m_outOfLineCapacity); -} - size_t Structure::suggestedNewOutOfLineStorageCapacity() { - return nextOutOfLineStorageCapacity(m_outOfLineCapacity); + return nextOutOfLineStorageCapacity(outOfLineCapacity()); } -void Structure::despecifyDictionaryFunction(JSGlobalData& globalData, PropertyName propertyName) +void Structure::despecifyDictionaryFunction(VM& vm, PropertyName propertyName) { StringImpl* rep = propertyName.uid(); - materializePropertyMapIfNecessary(globalData); + materializePropertyMapIfNecessary(vm); ASSERT(isDictionary()); - ASSERT(m_propertyTable); + ASSERT(propertyTable()); - PropertyMapEntry* entry = m_propertyTable->find(rep).first; + PropertyMapEntry* entry = propertyTable()->find(rep).first; ASSERT(entry); entry->specificValue.clear(); } @@ -304,7 +308,7 @@ Structure* Structure::addPropertyTransitionToExistingStructure(Structure* struct JSCell* specificValueInPrevious = existingTransition->m_specificValueInPrevious.get(); if (specificValueInPrevious && specificValueInPrevious != specificValue) return 0; - validateOffset(existingTransition->m_offset, structure->m_typeInfo.type()); + validateOffset(existingTransition->m_offset, existingTransition->inlineCapacity()); offset = existingTransition->m_offset; return existingTransition; } @@ -340,7 +344,7 @@ NonPropertyTransition Structure::suggestedArrayStorageTransition() const return AllocateArrayStorage; } -Structure* Structure::addPropertyTransition(JSGlobalData& globalData, Structure* structure, PropertyName propertyName, unsigned attributes, JSCell* specificValue, PropertyOffset& offset) +Structure* Structure::addPropertyTransition(VM& vm, Structure* structure, PropertyName propertyName, unsigned attributes, JSCell* specificValue, PropertyOffset& offset) { // If we have a specific function, we may have got to this point if there is // already a transition with the correct property name and attributes, but @@ -360,185 +364,190 @@ Structure* Structure::addPropertyTransition(JSGlobalData& globalData, Structure* specificValue = 0; if (structure->transitionCount() > s_maxTransitionLength) { - Structure* transition = toCacheableDictionaryTransition(globalData, structure); + Structure* transition = toCacheableDictionaryTransition(vm, structure); ASSERT(structure != transition); - offset = transition->putSpecificValue(globalData, propertyName, attributes, specificValue); - if (transition->outOfLineSize() > transition->outOfLineCapacity()) - transition->growOutOfLineCapacity(); + offset = transition->putSpecificValue(vm, propertyName, attributes, specificValue); return transition; } - Structure* transition = create(globalData, structure); + Structure* transition = create(vm, structure); - transition->m_cachedPrototypeChain.setMayBeNull(globalData, transition, structure->m_cachedPrototypeChain.get()); - transition->m_previous.set(globalData, transition, structure); + transition->m_cachedPrototypeChain.setMayBeNull(vm, transition, structure->m_cachedPrototypeChain.get()); + transition->setPreviousID(vm, transition, structure); transition->m_nameInPrevious = propertyName.uid(); transition->m_attributesInPrevious = attributes; - transition->m_specificValueInPrevious.setMayBeNull(globalData, transition, specificValue); - - if (structure->m_propertyTable) { - if (structure->m_isPinnedPropertyTable) - transition->m_propertyTable = structure->m_propertyTable->copy(globalData, transition, structure->m_propertyTable->size() + 1); - else - transition->m_propertyTable = structure->m_propertyTable.release(); - } else { - if (structure->m_previous) - transition->materializePropertyMap(globalData); - else - transition->createPropertyMap(); - } + transition->m_specificValueInPrevious.setMayBeNull(vm, transition, specificValue); + transition->propertyTable().set(vm, transition, structure->takePropertyTableOrCloneIfPinned(vm, transition)); + transition->m_offset = structure->m_offset; - offset = transition->putSpecificValue(globalData, propertyName, attributes, specificValue); - if (transition->outOfLineSize() > transition->outOfLineCapacity()) - transition->growOutOfLineCapacity(); + offset = transition->putSpecificValue(vm, propertyName, attributes, specificValue); - transition->m_offset = offset; - structure->m_transitionTable.add(globalData, transition); + checkOffset(transition->m_offset, transition->inlineCapacity()); + structure->m_transitionTable.add(vm, transition); + transition->checkOffsetConsistency(); + structure->checkOffsetConsistency(); return transition; } -Structure* Structure::removePropertyTransition(JSGlobalData& globalData, Structure* structure, PropertyName propertyName, PropertyOffset& offset) +Structure* Structure::removePropertyTransition(VM& vm, Structure* structure, PropertyName propertyName, PropertyOffset& offset) { ASSERT(!structure->isUncacheableDictionary()); - Structure* transition = toUncacheableDictionaryTransition(globalData, structure); + Structure* transition = toUncacheableDictionaryTransition(vm, structure); offset = transition->remove(propertyName); + transition->checkOffsetConsistency(); return transition; } -Structure* Structure::changePrototypeTransition(JSGlobalData& globalData, Structure* structure, JSValue prototype) +Structure* Structure::changePrototypeTransition(VM& vm, Structure* structure, JSValue prototype) { - Structure* transition = create(globalData, structure); + Structure* transition = create(vm, structure); - transition->m_prototype.set(globalData, transition, prototype); + transition->m_prototype.set(vm, transition, prototype); - // Don't set m_offset, as one can not transition to this. - - structure->materializePropertyMapIfNecessary(globalData); - transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition); + structure->materializePropertyMapIfNecessary(vm); + transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition)); + transition->m_offset = structure->m_offset; transition->pin(); + transition->checkOffsetConsistency(); return transition; } -Structure* Structure::despecifyFunctionTransition(JSGlobalData& globalData, Structure* structure, PropertyName replaceFunction) +Structure* Structure::despecifyFunctionTransition(VM& vm, Structure* structure, PropertyName replaceFunction) { ASSERT(structure->m_specificFunctionThrashCount < maxSpecificFunctionThrashCount); - Structure* transition = create(globalData, structure); + Structure* transition = create(vm, structure); ++transition->m_specificFunctionThrashCount; - // Don't set m_offset, as one can not transition to this. - - structure->materializePropertyMapIfNecessary(globalData); - transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition); + structure->materializePropertyMapIfNecessary(vm); + transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition)); + transition->m_offset = structure->m_offset; transition->pin(); if (transition->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount) - transition->despecifyAllFunctions(globalData); + transition->despecifyAllFunctions(vm); else { - bool removed = transition->despecifyFunction(globalData, replaceFunction); + bool removed = transition->despecifyFunction(vm, replaceFunction); ASSERT_UNUSED(removed, removed); } + transition->checkOffsetConsistency(); return transition; } -Structure* Structure::attributeChangeTransition(JSGlobalData& globalData, Structure* structure, PropertyName propertyName, unsigned attributes) +Structure* Structure::attributeChangeTransition(VM& vm, Structure* structure, PropertyName propertyName, unsigned attributes) { if (!structure->isUncacheableDictionary()) { - Structure* transition = create(globalData, structure); - - // Don't set m_offset, as one can not transition to this. + Structure* transition = create(vm, structure); - structure->materializePropertyMapIfNecessary(globalData); - transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition); + structure->materializePropertyMapIfNecessary(vm); + transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition)); + transition->m_offset = structure->m_offset; transition->pin(); structure = transition; } - ASSERT(structure->m_propertyTable); - PropertyMapEntry* entry = structure->m_propertyTable->find(propertyName.uid()).first; + ASSERT(structure->propertyTable()); + PropertyMapEntry* entry = structure->propertyTable()->find(propertyName.uid()).first; ASSERT(entry); entry->attributes = attributes; + structure->checkOffsetConsistency(); return structure; } -Structure* Structure::toDictionaryTransition(JSGlobalData& globalData, Structure* structure, DictionaryKind kind) +Structure* Structure::toDictionaryTransition(VM& vm, Structure* structure, DictionaryKind kind) { ASSERT(!structure->isUncacheableDictionary()); - Structure* transition = create(globalData, structure); + Structure* transition = create(vm, structure); - structure->materializePropertyMapIfNecessary(globalData); - transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition); + structure->materializePropertyMapIfNecessary(vm); + transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition)); + transition->m_offset = structure->m_offset; transition->m_dictionaryKind = kind; transition->pin(); + transition->checkOffsetConsistency(); return transition; } -Structure* Structure::toCacheableDictionaryTransition(JSGlobalData& globalData, Structure* structure) +Structure* Structure::toCacheableDictionaryTransition(VM& vm, Structure* structure) { - return toDictionaryTransition(globalData, structure, CachedDictionaryKind); + return toDictionaryTransition(vm, structure, CachedDictionaryKind); } -Structure* Structure::toUncacheableDictionaryTransition(JSGlobalData& globalData, Structure* structure) +Structure* Structure::toUncacheableDictionaryTransition(VM& vm, Structure* structure) { - return toDictionaryTransition(globalData, structure, UncachedDictionaryKind); + return toDictionaryTransition(vm, structure, UncachedDictionaryKind); } // In future we may want to cache this transition. -Structure* Structure::sealTransition(JSGlobalData& globalData, Structure* structure) +Structure* Structure::sealTransition(VM& vm, Structure* structure) { - Structure* transition = preventExtensionsTransition(globalData, structure); + Structure* transition = preventExtensionsTransition(vm, structure); - if (transition->m_propertyTable) { - PropertyTable::iterator end = transition->m_propertyTable->end(); - for (PropertyTable::iterator iter = transition->m_propertyTable->begin(); iter != end; ++iter) + if (transition->propertyTable()) { + PropertyTable::iterator end = transition->propertyTable()->end(); + for (PropertyTable::iterator iter = transition->propertyTable()->begin(); iter != end; ++iter) iter->attributes |= DontDelete; } + transition->checkOffsetConsistency(); return transition; } // In future we may want to cache this transition. -Structure* Structure::freezeTransition(JSGlobalData& globalData, Structure* structure) +Structure* Structure::freezeTransition(VM& vm, Structure* structure) { - Structure* transition = preventExtensionsTransition(globalData, structure); + Structure* transition = preventExtensionsTransition(vm, structure); - if (transition->m_propertyTable) { - PropertyTable::iterator iter = transition->m_propertyTable->begin(); - PropertyTable::iterator end = transition->m_propertyTable->end(); + if (transition->propertyTable()) { + PropertyTable::iterator iter = transition->propertyTable()->begin(); + PropertyTable::iterator end = transition->propertyTable()->end(); if (iter != end) transition->m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true; for (; iter != end; ++iter) iter->attributes |= iter->attributes & Accessor ? DontDelete : (DontDelete | ReadOnly); } + transition->checkOffsetConsistency(); return transition; } // In future we may want to cache this transition. -Structure* Structure::preventExtensionsTransition(JSGlobalData& globalData, Structure* structure) +Structure* Structure::preventExtensionsTransition(VM& vm, Structure* structure) { - Structure* transition = create(globalData, structure); + Structure* transition = create(vm, structure); // Don't set m_offset, as one can not transition to this. - structure->materializePropertyMapIfNecessary(globalData); - transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition); + structure->materializePropertyMapIfNecessary(vm); + transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition)); + transition->m_offset = structure->m_offset; transition->m_preventExtensions = true; transition->pin(); + transition->checkOffsetConsistency(); return transition; } -Structure* Structure::nonPropertyTransition(JSGlobalData& globalData, Structure* structure, NonPropertyTransition transitionKind) +PropertyTable* Structure::takePropertyTableOrCloneIfPinned(VM& vm, Structure* owner) +{ + materializePropertyMapIfNecessaryForPinning(vm); + if (m_isPinnedPropertyTable) + return propertyTable()->copy(vm, owner, propertyTable()->size() + 1); + PropertyTable* takenPropertyTable = propertyTable().get(); + propertyTable().clear(); + return takenPropertyTable; +} + +Structure* Structure::nonPropertyTransition(VM& vm, Structure* structure, NonPropertyTransition transitionKind) { unsigned attributes = toAttributes(transitionKind); IndexingType indexingType = newIndexingType(structure->indexingTypeIncludingHistory(), transitionKind); @@ -559,40 +568,31 @@ Structure* Structure::nonPropertyTransition(JSGlobalData& globalData, Structure* return existingTransition; } - Structure* transition = create(globalData, structure); - transition->m_previous.set(globalData, transition, structure); + Structure* transition = create(vm, structure); + transition->setPreviousID(vm, transition, structure); transition->m_attributesInPrevious = attributes; transition->m_indexingType = indexingType; + transition->propertyTable().set(vm, transition, structure->takePropertyTableOrCloneIfPinned(vm, transition)); transition->m_offset = structure->m_offset; + checkOffset(transition->m_offset, transition->inlineCapacity()); - if (structure->m_propertyTable) { - if (structure->m_isPinnedPropertyTable) - transition->m_propertyTable = structure->m_propertyTable->copy(globalData, transition, structure->m_propertyTable->size() + 1); - else - transition->m_propertyTable = structure->m_propertyTable.release(); - } else { - if (structure->m_previous) - transition->materializePropertyMap(globalData); - else - transition->createPropertyMap(); - } - - structure->m_transitionTable.add(globalData, transition); + structure->m_transitionTable.add(vm, transition); + transition->checkOffsetConsistency(); return transition; } // In future we may want to cache this property. -bool Structure::isSealed(JSGlobalData& globalData) +bool Structure::isSealed(VM& vm) { if (isExtensible()) return false; - materializePropertyMapIfNecessary(globalData); - if (!m_propertyTable) + materializePropertyMapIfNecessary(vm); + if (!propertyTable()) return true; - PropertyTable::iterator end = m_propertyTable->end(); - for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) { + PropertyTable::iterator end = propertyTable()->end(); + for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) { if ((iter->attributes & DontDelete) != DontDelete) return false; } @@ -600,17 +600,17 @@ bool Structure::isSealed(JSGlobalData& globalData) } // In future we may want to cache this property. -bool Structure::isFrozen(JSGlobalData& globalData) +bool Structure::isFrozen(VM& vm) { if (isExtensible()) return false; - materializePropertyMapIfNecessary(globalData); - if (!m_propertyTable) + materializePropertyMapIfNecessary(vm); + if (!propertyTable()) return true; - PropertyTable::iterator end = m_propertyTable->end(); - for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) { + PropertyTable::iterator end = propertyTable()->end(); + for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) { if (!(iter->attributes & DontDelete)) return false; if (!(iter->attributes & (ReadOnly | Accessor))) @@ -619,59 +619,59 @@ bool Structure::isFrozen(JSGlobalData& globalData) return true; } -Structure* Structure::flattenDictionaryStructure(JSGlobalData& globalData, JSObject* object) +Structure* Structure::flattenDictionaryStructure(VM& vm, JSObject* object) { + checkOffsetConsistency(); ASSERT(isDictionary()); if (isUncacheableDictionary()) { - ASSERT(m_propertyTable); + ASSERT(propertyTable()); - size_t propertyCount = m_propertyTable->size(); + size_t propertyCount = propertyTable()->size(); // Holds our values compacted by insertion order. Vector<JSValue> values(propertyCount); // Copies out our values from their hashed locations, compacting property table offsets as we go. unsigned i = 0; - PropertyTable::iterator end = m_propertyTable->end(); - for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter, ++i) { - values[i] = object->getDirectOffset(iter->offset); - iter->offset = propertyOffsetFor(i, m_inlineCapacity); + PropertyTable::iterator end = propertyTable()->end(); + m_offset = invalidOffset; + for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter, ++i) { + values[i] = object->getDirect(iter->offset); + m_offset = iter->offset = offsetForPropertyNumber(i, m_inlineCapacity); } // Copies in our values to their compacted locations. for (unsigned i = 0; i < propertyCount; i++) - object->putDirectOffset(globalData, propertyOffsetFor(i, m_inlineCapacity), values[i]); + object->putDirect(vm, offsetForPropertyNumber(i, m_inlineCapacity), values[i]); - m_propertyTable->clearDeletedOffsets(); + propertyTable()->clearDeletedOffsets(); + checkOffsetConsistency(); } m_dictionaryKind = NoneDictionaryKind; return this; } -PropertyOffset Structure::addPropertyWithoutTransition(JSGlobalData& globalData, PropertyName propertyName, unsigned attributes, JSCell* specificValue) +PropertyOffset Structure::addPropertyWithoutTransition(VM& vm, PropertyName propertyName, unsigned attributes, JSCell* specificValue) { - ASSERT(!m_enumerationCache); + ASSERT(!enumerationCache()); if (m_specificFunctionThrashCount == maxSpecificFunctionThrashCount) specificValue = 0; - materializePropertyMapIfNecessaryForPinning(globalData); + materializePropertyMapIfNecessaryForPinning(vm); pin(); - PropertyOffset offset = putSpecificValue(globalData, propertyName, attributes, specificValue); - if (outOfLineSize() > outOfLineCapacity()) - growOutOfLineCapacity(); - return offset; + return putSpecificValue(vm, propertyName, attributes, specificValue); } -PropertyOffset Structure::removePropertyWithoutTransition(JSGlobalData& globalData, PropertyName propertyName) +PropertyOffset Structure::removePropertyWithoutTransition(VM& vm, PropertyName propertyName) { ASSERT(isUncacheableDictionary()); - ASSERT(!m_enumerationCache); + ASSERT(!enumerationCache()); - materializePropertyMapIfNecessaryForPinning(globalData); + materializePropertyMapIfNecessaryForPinning(vm); pin(); return remove(propertyName); @@ -679,12 +679,28 @@ PropertyOffset Structure::removePropertyWithoutTransition(JSGlobalData& globalDa void Structure::pin() { - ASSERT(m_propertyTable); + ASSERT(propertyTable()); m_isPinnedPropertyTable = true; - m_previous.clear(); + clearPreviousID(); m_nameInPrevious.clear(); } +void Structure::allocateRareData(VM& vm) +{ + ASSERT(!typeInfo().structureHasRareData()); + StructureRareData* rareData = StructureRareData::create(vm, previous()); + m_typeInfo = TypeInfo(typeInfo().type(), typeInfo().flags() | StructureHasRareData); + m_previousOrRareData.set(vm, this, rareData); +} + +void Structure::cloneRareDataFrom(VM& vm, const Structure* other) +{ + ASSERT(other->typeInfo().structureHasRareData()); + StructureRareData* newRareData = StructureRareData::clone(vm, other->rareData()); + m_typeInfo = TypeInfo(typeInfo().type(), typeInfo().flags() | StructureHasRareData); + m_previousOrRareData.set(vm, this, newRareData); +} + #if DUMP_PROPERTYMAP_STATS struct PropertyMapStatisticsExitLogger { @@ -708,29 +724,34 @@ PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger() inline void Structure::checkConsistency() { + checkOffsetConsistency(); } #endif -PassOwnPtr<PropertyTable> Structure::copyPropertyTable(JSGlobalData& globalData, Structure* owner) +PropertyTable* Structure::copyPropertyTable(VM& vm, Structure* owner) { - return adoptPtr(m_propertyTable ? new PropertyTable(globalData, owner, *m_propertyTable) : 0); + if (!propertyTable()) + return 0; + return PropertyTable::clone(vm, owner, *propertyTable().get()); } -PassOwnPtr<PropertyTable> Structure::copyPropertyTableForPinning(JSGlobalData& globalData, Structure* owner) +PropertyTable* Structure::copyPropertyTableForPinning(VM& vm, Structure* owner) { - return adoptPtr(m_propertyTable ? new PropertyTable(globalData, owner, *m_propertyTable) : new PropertyTable(numberOfSlotsForLastOffset(m_offset, m_typeInfo.type()))); + if (propertyTable()) + return PropertyTable::clone(vm, owner, *propertyTable().get()); + return PropertyTable::create(vm, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity)); } -PropertyOffset Structure::get(JSGlobalData& globalData, PropertyName propertyName, unsigned& attributes, JSCell*& specificValue) +PropertyOffset Structure::get(VM& vm, PropertyName propertyName, unsigned& attributes, JSCell*& specificValue) { ASSERT(structure()->classInfo() == &s_info); - materializePropertyMapIfNecessary(globalData); - if (!m_propertyTable) + materializePropertyMapIfNecessary(vm); + if (!propertyTable()) return invalidOffset; - PropertyMapEntry* entry = m_propertyTable->find(propertyName.uid()).first; + PropertyMapEntry* entry = propertyTable()->find(propertyName.uid()).first; if (!entry) return invalidOffset; @@ -739,13 +760,13 @@ PropertyOffset Structure::get(JSGlobalData& globalData, PropertyName propertyNam return entry->offset; } -bool Structure::despecifyFunction(JSGlobalData& globalData, PropertyName propertyName) +bool Structure::despecifyFunction(VM& vm, PropertyName propertyName) { - materializePropertyMapIfNecessary(globalData); - if (!m_propertyTable) + materializePropertyMapIfNecessary(vm); + if (!propertyTable()) return false; - PropertyMapEntry* entry = m_propertyTable->find(propertyName.uid()).first; + PropertyMapEntry* entry = propertyTable()->find(propertyName.uid()).first; if (!entry) return false; @@ -754,20 +775,20 @@ bool Structure::despecifyFunction(JSGlobalData& globalData, PropertyName propert return true; } -void Structure::despecifyAllFunctions(JSGlobalData& globalData) +void Structure::despecifyAllFunctions(VM& vm) { - materializePropertyMapIfNecessary(globalData); - if (!m_propertyTable) + materializePropertyMapIfNecessary(vm); + if (!propertyTable()) return; - PropertyTable::iterator end = m_propertyTable->end(); - for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) + PropertyTable::iterator end = propertyTable()->end(); + for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) iter->specificValue.clear(); } -PropertyOffset Structure::putSpecificValue(JSGlobalData& globalData, PropertyName propertyName, unsigned attributes, JSCell* specificValue) +PropertyOffset Structure::putSpecificValue(VM& vm, PropertyName propertyName, unsigned attributes, JSCell* specificValue) { - ASSERT(!JSC::isValidOffset(get(globalData, propertyName))); + ASSERT(!JSC::isValidOffset(get(vm, propertyName))); checkConsistency(); if (attributes & DontEnum) @@ -775,13 +796,13 @@ PropertyOffset Structure::putSpecificValue(JSGlobalData& globalData, PropertyNam StringImpl* rep = propertyName.uid(); - if (!m_propertyTable) - createPropertyMap(); - - PropertyOffset newOffset = m_propertyTable->nextOffset(m_inlineCapacity); + if (!propertyTable()) + createPropertyMap(vm); - m_propertyTable->add(PropertyMapEntry(globalData, this, rep, newOffset, attributes, specificValue)); + PropertyOffset newOffset = propertyTable()->nextOffset(m_inlineCapacity); + propertyTable()->add(PropertyMapEntry(vm, this, rep, newOffset, attributes, specificValue), m_offset, PropertyTable::PropertyOffsetMayChange); + checkConsistency(); return newOffset; } @@ -792,41 +813,40 @@ PropertyOffset Structure::remove(PropertyName propertyName) StringImpl* rep = propertyName.uid(); - if (!m_propertyTable) + if (!propertyTable()) return invalidOffset; - PropertyTable::find_iterator position = m_propertyTable->find(rep); + PropertyTable::find_iterator position = propertyTable()->find(rep); if (!position.first) return invalidOffset; PropertyOffset offset = position.first->offset; - m_propertyTable->remove(position); - m_propertyTable->addDeletedOffset(offset); + propertyTable()->remove(position); + propertyTable()->addDeletedOffset(offset); checkConsistency(); return offset; } -void Structure::createPropertyMap(unsigned capacity) +void Structure::createPropertyMap(VM& vm, unsigned capacity) { - ASSERT(!m_propertyTable); + ASSERT(!propertyTable()); checkConsistency(); - m_propertyTable = adoptPtr(new PropertyTable(capacity)); - checkConsistency(); + propertyTable().set(vm, this, PropertyTable::create(vm, capacity)); } -void Structure::getPropertyNamesFromStructure(JSGlobalData& globalData, PropertyNameArray& propertyNames, EnumerationMode mode) +void Structure::getPropertyNamesFromStructure(VM& vm, PropertyNameArray& propertyNames, EnumerationMode mode) { - materializePropertyMapIfNecessary(globalData); - if (!m_propertyTable) + materializePropertyMapIfNecessary(vm); + if (!propertyTable()) return; bool knownUnique = !propertyNames.size(); - PropertyTable::iterator end = m_propertyTable->end(); - for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) { + PropertyTable::iterator end = propertyTable()->end(); + for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) { ASSERT(m_hasNonEnumerableProperties || !(iter->attributes & DontEnum)); if (iter->key->isIdentifier() && (!(iter->attributes & DontEnum) || mode == IncludeDontEnumProperties)) { if (knownUnique) @@ -837,6 +857,11 @@ void Structure::getPropertyNamesFromStructure(JSGlobalData& globalData, Property } } +JSValue Structure::prototypeForLookup(CodeBlock* codeBlock) const +{ + return prototypeForLookup(codeBlock->globalObject()); +} + void Structure::visitChildren(JSCell* cell, SlotVisitor& visitor) { Structure* thisObject = jsCast<Structure*>(cell); @@ -851,18 +876,17 @@ void Structure::visitChildren(JSCell* cell, SlotVisitor& visitor) visitor.append(&thisObject->m_prototype); visitor.append(&thisObject->m_cachedPrototypeChain); } - visitor.append(&thisObject->m_previous); + visitor.append(&thisObject->m_previousOrRareData); visitor.append(&thisObject->m_specificValueInPrevious); - visitor.append(&thisObject->m_enumerationCache); - if (thisObject->m_propertyTable) { - PropertyTable::iterator end = thisObject->m_propertyTable->end(); - for (PropertyTable::iterator ptr = thisObject->m_propertyTable->begin(); ptr != end; ++ptr) - visitor.append(&ptr->specificValue); - } - visitor.append(&thisObject->m_objectToStringValue); + + if (thisObject->m_isPinnedPropertyTable) { + ASSERT(thisObject->m_propertyTableUnsafe); + visitor.append(&thisObject->m_propertyTableUnsafe); + } else if (thisObject->m_propertyTableUnsafe) + thisObject->m_propertyTableUnsafe.clear(); } -bool Structure::prototypeChainMayInterceptStoreTo(JSGlobalData& globalData, PropertyName propertyName) +bool Structure::prototypeChainMayInterceptStoreTo(VM& vm, PropertyName propertyName) { unsigned i = propertyName.asIndex(); if (i != PropertyName::NotAnIndex) @@ -877,7 +901,7 @@ bool Structure::prototypeChainMayInterceptStoreTo(JSGlobalData& globalData, Prop unsigned attributes; JSCell* specificValue; - PropertyOffset offset = current->get(globalData, propertyName, attributes, specificValue); + PropertyOffset offset = current->get(vm, propertyName, attributes, specificValue); if (!JSC::isValidOffset(offset)) continue; @@ -892,6 +916,7 @@ bool Structure::prototypeChainMayInterceptStoreTo(JSGlobalData& globalData, Prop void PropertyTable::checkConsistency() { + checkOffsetConsistency(); ASSERT(m_indexSize >= PropertyTable::MinimumTableSize); ASSERT(m_indexMask); ASSERT(m_indexSize == m_indexMask + 1); @@ -949,17 +974,17 @@ void PropertyTable::checkConsistency() void Structure::checkConsistency() { - if (!m_propertyTable) + if (!propertyTable()) return; if (!m_hasNonEnumerableProperties) { - PropertyTable::iterator end = m_propertyTable->end(); - for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) { + PropertyTable::iterator end = propertyTable()->end(); + for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) { ASSERT(!(iter->attributes & DontEnum)); } } - m_propertyTable->checkConsistency(); + propertyTable()->checkConsistency(); } #endif // DO_PROPERTYMAP_CONSTENCY_CHECK diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h index 6e4402c52..45379efd6 100644 --- a/Source/JavaScriptCore/runtime/Structure.h +++ b/Source/JavaScriptCore/runtime/Structure.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009, 2012, 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,18 +28,17 @@ #include "ClassInfo.h" #include "IndexingType.h" +#include "JSCJSValue.h" #include "JSCell.h" #include "JSType.h" -#include "JSValue.h" -#include "PropertyMapHashTable.h" #include "PropertyName.h" #include "PropertyNameArray.h" +#include "PropertyOffset.h" #include "Protect.h" +#include "StructureRareData.h" #include "StructureTransitionTable.h" #include "JSTypeInfo.h" #include "Watchpoint.h" -#include "Weak.h" -#include <wtf/PassOwnPtr.h> #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> #include <wtf/text/StringImpl.h> @@ -47,562 +46,436 @@ namespace JSC { - class LLIntOffsetsExtractor; - class PropertyNameArray; - class PropertyNameArrayData; - class StructureChain; - class SlotVisitor; - class JSString; - - // The out-of-line property storage capacity to use when first allocating out-of-line - // storage. Note that all objects start out without having any out-of-line storage; - // this comes into play only on the first property store that exhausts inline storage. - static const unsigned initialOutOfLineCapacity = 4; - - // The factor by which to grow out-of-line storage when it is exhausted, after the - // initial allocation. - static const unsigned outOfLineGrowthFactor = 2; - - class Structure : public JSCell { - public: - friend class StructureTransitionTable; - - typedef JSCell Base; - - static Structure* create(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, PropertyOffset inlineCapacity = 0); - - protected: - void finishCreation(JSGlobalData& globalData) - { - Base::finishCreation(globalData); - ASSERT(m_prototype); - ASSERT(m_prototype.isObject() || m_prototype.isNull()); - } - - void finishCreation(JSGlobalData& globalData, CreatingEarlyCellTag) - { - Base::finishCreation(globalData, this, CreatingEarlyCell); - ASSERT(m_prototype); - ASSERT(m_prototype.isNull()); - ASSERT(!globalData.structureStructure); - } - - public: - static void dumpStatistics(); - - JS_EXPORT_PRIVATE static Structure* addPropertyTransition(JSGlobalData&, Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&); - JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&); - static Structure* removePropertyTransition(JSGlobalData&, Structure*, PropertyName, PropertyOffset&); - JS_EXPORT_PRIVATE static Structure* changePrototypeTransition(JSGlobalData&, Structure*, JSValue prototype); - JS_EXPORT_PRIVATE static Structure* despecifyFunctionTransition(JSGlobalData&, Structure*, PropertyName); - static Structure* attributeChangeTransition(JSGlobalData&, Structure*, PropertyName, unsigned attributes); - 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*); - static Structure* nonPropertyTransition(JSGlobalData&, Structure*, NonPropertyTransition); - - bool isSealed(JSGlobalData&); - bool isFrozen(JSGlobalData&); - bool isExtensible() const { return !m_preventExtensions; } - bool didTransition() const { return m_didTransition; } - bool putWillGrowOutOfLineStorage() - { - ASSERT(outOfLineCapacity() >= outOfLineSize()); - - if (!m_propertyTable) { - unsigned currentSize = numberOfOutOfLineSlotsForLastOffset(m_offset); - ASSERT(outOfLineCapacity() >= currentSize); - return currentSize == outOfLineCapacity(); - } - - ASSERT(totalStorageCapacity() >= m_propertyTable->propertyStorageSize()); - if (m_propertyTable->hasDeletedOffset()) - return false; - - ASSERT(totalStorageCapacity() >= m_propertyTable->size()); - return m_propertyTable->size() == totalStorageCapacity(); - } - JS_EXPORT_PRIVATE size_t suggestedNewOutOfLineStorageCapacity(); +class LLIntOffsetsExtractor; +class PropertyNameArray; +class PropertyNameArrayData; +class PropertyTable; +class StructureChain; +class SlotVisitor; +class JSString; - Structure* flattenDictionaryStructure(JSGlobalData&, JSObject*); +// The out-of-line property storage capacity to use when first allocating out-of-line +// storage. Note that all objects start out without having any out-of-line storage; +// this comes into play only on the first property store that exhausts inline storage. +static const unsigned initialOutOfLineCapacity = 4; - static const bool needsDestruction = true; - static const bool hasImmortalStructure = true; - static void destroy(JSCell*); +// The factor by which to grow out-of-line storage when it is exhausted, after the +// initial allocation. +static const unsigned outOfLineGrowthFactor = 2; - // These should be used with caution. - JS_EXPORT_PRIVATE PropertyOffset addPropertyWithoutTransition(JSGlobalData&, PropertyName, unsigned attributes, JSCell* specificValue); - PropertyOffset removePropertyWithoutTransition(JSGlobalData&, 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; } +class Structure : public JSCell { +public: + friend class StructureTransitionTable; - bool propertyAccessesAreCacheable() { return m_dictionaryKind != UncachedDictionaryKind && !typeInfo().prohibitsPropertyCaching(); } + typedef JSCell Base; - // Type accessors. - const TypeInfo& typeInfo() const { ASSERT(structure()->classInfo() == &s_info); return m_typeInfo; } - bool isObject() const { return typeInfo().isObject(); } + static Structure* create(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, unsigned inlineCapacity = 0); - IndexingType indexingType() const { return m_indexingType & AllArrayTypes; } - IndexingType indexingTypeIncludingHistory() const { return m_indexingType; } - - bool mayInterceptIndexedAccesses() const - { - return !!(indexingTypeIncludingHistory() & MayHaveIndexedAccessors); - } - - bool anyObjectInChainMayInterceptIndexedAccesses() const; - - bool needsSlowPutIndexing() const; - NonPropertyTransition suggestedArrayStorageTransition() const; - - JSGlobalObject* globalObject() const { return m_globalObject.get(); } - void setGlobalObject(JSGlobalData& globalData, JSGlobalObject* globalObject) { m_globalObject.set(globalData, this, globalObject); } - - JSValue storedPrototype() const { return m_prototype.get(); } - JSValue prototypeForLookup(ExecState*) const; - JSValue prototypeForLookup(JSGlobalObject*) const; - JSValue prototypeForLookup(CodeBlock*) const; - StructureChain* prototypeChain(JSGlobalData&, JSGlobalObject*) const; - StructureChain* prototypeChain(ExecState*) const; - static void visitChildren(JSCell*, SlotVisitor&); - - // Will just the prototype chain intercept this property access? - bool prototypeChainMayInterceptStoreTo(JSGlobalData&, PropertyName); - - bool transitionDidInvolveSpecificValue() const { return !!m_specificValueInPrevious; } - - Structure* previousID() const - { - ASSERT(structure()->classInfo() == &s_info); - return m_previous.get(); - } - bool transitivelyTransitionedFrom(Structure* structureToFind); - - void growOutOfLineCapacity(); - unsigned outOfLineCapacity() const - { - ASSERT(structure()->classInfo() == &s_info); - return m_outOfLineCapacity; - } - unsigned outOfLineSize() const - { - ASSERT(structure()->classInfo() == &s_info); - if (m_propertyTable) { - unsigned totalSize = m_propertyTable->propertyStorageSize(); - unsigned inlineCapacity = this->inlineCapacity(); - if (totalSize < inlineCapacity) - return 0; - return totalSize - inlineCapacity; - } - return numberOfOutOfLineSlotsForLastOffset(m_offset); - } - bool hasInlineStorage() const - { - return !!m_inlineCapacity; - } - unsigned inlineCapacity() const - { - return m_inlineCapacity; - } - unsigned inlineSize() const - { - unsigned result; - if (m_propertyTable) - result = m_propertyTable->propertyStorageSize(); - else - result = m_offset + 1; - return std::min<unsigned>(result, m_inlineCapacity); - } - unsigned totalStorageSize() const - { - if (m_propertyTable) - return m_propertyTable->propertyStorageSize(); - return numberOfSlotsForLastOffset(m_offset, m_typeInfo.type()); - } - unsigned totalStorageCapacity() const - { - ASSERT(structure()->classInfo() == &s_info); - return m_outOfLineCapacity + inlineCapacity(); - } - - PropertyOffset firstValidOffset() const - { - if (hasInlineStorage()) - return 0; - return firstOutOfLineOffset; - } - PropertyOffset lastValidOffset() const - { - if (m_propertyTable) - return propertyOffsetFor(m_propertyTable->propertyStorageSize() - 1, m_inlineCapacity); - return m_offset; - } - bool isValidOffset(PropertyOffset offset) const - { - return offset >= firstValidOffset() - && offset <= lastValidOffset(); - } - - bool masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject); - - PropertyOffset get(JSGlobalData&, PropertyName); - PropertyOffset get(JSGlobalData&, const WTF::String& name); - JS_EXPORT_PRIVATE PropertyOffset get(JSGlobalData&, PropertyName, unsigned& attributes, JSCell*& specificValue); - - bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; } - bool hasReadOnlyOrGetterSetterPropertiesExcludingProto() const { return m_hasReadOnlyOrGetterSetterPropertiesExcludingProto; } - void setHasGetterSetterProperties(bool is__proto__) - { - m_hasGetterSetterProperties = true; - if (!is__proto__) - m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true; - } - void setContainsReadOnlyProperties() - { - m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true; - } +protected: + void finishCreation(VM& vm) + { + Base::finishCreation(vm); + ASSERT(m_prototype); + ASSERT(m_prototype.isObject() || m_prototype.isNull()); + } - bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; } - - bool isEmpty() const - { - if (m_propertyTable) - return m_propertyTable->isEmpty(); - return !JSC::isValidOffset(m_offset); - } - - JS_EXPORT_PRIVATE void despecifyDictionaryFunction(JSGlobalData&, PropertyName); - void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; } - - void setEnumerationCache(JSGlobalData&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h. - JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h. - void getPropertyNamesFromStructure(JSGlobalData&, PropertyNameArray&, EnumerationMode); - - JSString* objectToStringValue() { return m_objectToStringValue.get(); } - - void setObjectToStringValue(JSGlobalData& globalData, const JSCell* owner, JSString* value) - { - m_objectToStringValue.set(globalData, owner, value); - } - - bool staticFunctionsReified() - { - return m_staticFunctionReified; - } - - void setStaticFunctionsReified() - { - m_staticFunctionReified = true; - } - - const ClassInfo* classInfo() const { return m_classInfo; } - - static ptrdiff_t prototypeOffset() - { - return OBJECT_OFFSETOF(Structure, m_prototype); - } - - static ptrdiff_t globalObjectOffset() - { - return OBJECT_OFFSETOF(Structure, m_globalObject); - } - - 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 ptrdiff_t classInfoOffset() - { - return OBJECT_OFFSETOF(Structure, m_classInfo); - } + void finishCreation(VM& vm, CreatingEarlyCellTag) + { + Base::finishCreation(vm, this, CreatingEarlyCell); + ASSERT(m_prototype); + ASSERT(m_prototype.isNull()); + ASSERT(!vm.structureStructure); + } + +public: + static void dumpStatistics(); + + JS_EXPORT_PRIVATE static Structure* addPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&); + JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&); + static Structure* removePropertyTransition(VM&, Structure*, PropertyName, PropertyOffset&); + JS_EXPORT_PRIVATE static Structure* changePrototypeTransition(VM&, Structure*, JSValue prototype); + JS_EXPORT_PRIVATE static Structure* despecifyFunctionTransition(VM&, Structure*, PropertyName); + static Structure* attributeChangeTransition(VM&, Structure*, PropertyName, unsigned attributes); + static Structure* toCacheableDictionaryTransition(VM&, Structure*); + static Structure* toUncacheableDictionaryTransition(VM&, Structure*); + static Structure* sealTransition(VM&, Structure*); + static Structure* freezeTransition(VM&, Structure*); + static Structure* preventExtensionsTransition(VM&, Structure*); + static Structure* nonPropertyTransition(VM&, Structure*, NonPropertyTransition); + + bool isSealed(VM&); + bool isFrozen(VM&); + bool isExtensible() const { return !m_preventExtensions; } + bool didTransition() const { return m_didTransition; } + bool putWillGrowOutOfLineStorage(); + JS_EXPORT_PRIVATE size_t suggestedNewOutOfLineStorageCapacity(); + + Structure* flattenDictionaryStructure(VM&, JSObject*); + + static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; + static void destroy(JSCell*); + + // These should be used with caution. + JS_EXPORT_PRIVATE PropertyOffset addPropertyWithoutTransition(VM&, PropertyName, unsigned attributes, JSCell* specificValue); + PropertyOffset removePropertyWithoutTransition(VM&, PropertyName); + void setPrototypeWithoutTransition(VM& vm, JSValue prototype) { m_prototype.set(vm, this, prototype); } - static ptrdiff_t indexingTypeOffset() - { - return OBJECT_OFFSETOF(Structure, m_indexingType); - } + bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; } + bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; } + + bool propertyAccessesAreCacheable() { return m_dictionaryKind != UncachedDictionaryKind && !typeInfo().prohibitsPropertyCaching(); } + + // Type accessors. + const TypeInfo& typeInfo() const { ASSERT(structure()->classInfo() == &s_info); return m_typeInfo; } + bool isObject() const { return typeInfo().isObject(); } - static Structure* createStructure(JSGlobalData&); + IndexingType indexingType() const { return m_indexingType & AllArrayTypes; } + IndexingType indexingTypeIncludingHistory() const { return m_indexingType; } - bool transitionWatchpointSetHasBeenInvalidated() const - { - return m_transitionWatchpointSet.hasBeenInvalidated(); - } + bool mayInterceptIndexedAccesses() const + { + return !!(indexingTypeIncludingHistory() & MayHaveIndexedAccessors); + } - bool transitionWatchpointSetIsStillValid() const - { - return m_transitionWatchpointSet.isStillValid(); - } + bool anyObjectInChainMayInterceptIndexedAccesses() const; - void addTransitionWatchpoint(Watchpoint* watchpoint) const - { - ASSERT(transitionWatchpointSetIsStillValid()); - m_transitionWatchpointSet.add(watchpoint); - } + bool needsSlowPutIndexing() const; + NonPropertyTransition suggestedArrayStorageTransition() const; - void notifyTransitionFromThisStructure() const - { - m_transitionWatchpointSet.notifyWrite(); - } + JSGlobalObject* globalObject() const { return m_globalObject.get(); } + void setGlobalObject(VM& vm, JSGlobalObject* globalObject) { m_globalObject.set(vm, this, globalObject); } - static JS_EXPORTDATA const ClassInfo s_info; - - private: - friend class LLIntOffsetsExtractor; - - JS_EXPORT_PRIVATE Structure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType, PropertyOffset inlineCapacity); - Structure(JSGlobalData&); - Structure(JSGlobalData&, const Structure*); - - static Structure* create(JSGlobalData&, const Structure*); + JSValue storedPrototype() const { return m_prototype.get(); } + JSValue prototypeForLookup(ExecState*) const; + JSValue prototypeForLookup(JSGlobalObject*) const; + JSValue prototypeForLookup(CodeBlock*) const; + StructureChain* prototypeChain(VM&, JSGlobalObject*) const; + StructureChain* prototypeChain(ExecState*) const; + static void visitChildren(JSCell*, SlotVisitor&); - typedef enum { - NoneDictionaryKind = 0, - CachedDictionaryKind = 1, - UncachedDictionaryKind = 2 - } DictionaryKind; - static Structure* toDictionaryTransition(JSGlobalData&, Structure*, DictionaryKind); - - PropertyOffset putSpecificValue(JSGlobalData&, PropertyName, unsigned attributes, JSCell* specificValue); - PropertyOffset remove(PropertyName); - - void createPropertyMap(unsigned keyCount = 0); - void checkConsistency(); - - bool despecifyFunction(JSGlobalData&, PropertyName); - void despecifyAllFunctions(JSGlobalData&); - - PassOwnPtr<PropertyTable> copyPropertyTable(JSGlobalData&, Structure* owner); - PassOwnPtr<PropertyTable> copyPropertyTableForPinning(JSGlobalData&, Structure* owner); - JS_EXPORT_PRIVATE void materializePropertyMap(JSGlobalData&); - void materializePropertyMapIfNecessary(JSGlobalData& globalData) - { - ASSERT(structure()->classInfo() == &s_info); - if (!m_propertyTable && m_previous) - materializePropertyMap(globalData); - } - void materializePropertyMapIfNecessaryForPinning(JSGlobalData& globalData) - { - ASSERT(structure()->classInfo() == &s_info); - if (!m_propertyTable) - materializePropertyMap(globalData); - } - - int transitionCount() const - { - // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both. - return numberOfSlotsForLastOffset(m_offset, m_typeInfo.type()); - } - - bool isValid(JSGlobalObject*, StructureChain* cachedPrototypeChain) const; - bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const; + // Will just the prototype chain intercept this property access? + bool prototypeChainMayInterceptStoreTo(VM&, PropertyName); - void pin(); - - static const int s_maxTransitionLength = 64; - - static const unsigned maxSpecificFunctionThrashCount = 3; - - TypeInfo m_typeInfo; - IndexingType m_indexingType; + bool transitionDidInvolveSpecificValue() const { return !!m_specificValueInPrevious; } - WriteBarrier<JSGlobalObject> m_globalObject; - WriteBarrier<Unknown> m_prototype; - mutable WriteBarrier<StructureChain> m_cachedPrototypeChain; - - WriteBarrier<Structure> m_previous; - RefPtr<StringImpl> m_nameInPrevious; - WriteBarrier<JSCell> m_specificValueInPrevious; - - const ClassInfo* m_classInfo; + Structure* previousID() const + { + ASSERT(structure()->classInfo() == &s_info); + if (typeInfo().structureHasRareData()) + return rareData()->previousID(); + return previous(); + } + bool transitivelyTransitionedFrom(Structure* structureToFind); - StructureTransitionTable m_transitionTable; + unsigned outOfLineCapacity() const + { + ASSERT(checkOffsetConsistency()); + + unsigned outOfLineSize = this->outOfLineSize(); - WriteBarrier<JSPropertyNameIterator> m_enumerationCache; + if (!outOfLineSize) + return 0; - OwnPtr<PropertyTable> m_propertyTable; + if (outOfLineSize <= initialOutOfLineCapacity) + return initialOutOfLineCapacity; - WriteBarrier<JSString> m_objectToStringValue; - - mutable InlineWatchpointSet m_transitionWatchpointSet; - - uint32_t m_outOfLineCapacity; - uint8_t m_inlineCapacity; - COMPILE_ASSERT(firstOutOfLineOffset < 256, firstOutOfLineOffset_fits); - - // m_offset does not account for anonymous slots - PropertyOffset m_offset; - - unsigned m_dictionaryKind : 2; - bool m_isPinnedPropertyTable : 1; - bool m_hasGetterSetterProperties : 1; - bool m_hasReadOnlyOrGetterSetterPropertiesExcludingProto : 1; - bool m_hasNonEnumerableProperties : 1; - unsigned m_attributesInPrevious : 22; - unsigned m_specificFunctionThrashCount : 2; - unsigned m_preventExtensions : 1; - unsigned m_didTransition : 1; - unsigned m_staticFunctionReified; - }; - - inline Structure* Structure::create(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, PropertyOffset inlineCapacity) - { - ASSERT(globalData.structureStructure); - ASSERT(classInfo); - Structure* structure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData, globalObject, prototype, typeInfo, classInfo, indexingType, inlineCapacity); - structure->finishCreation(globalData); - return structure; + ASSERT(outOfLineSize > initialOutOfLineCapacity); + COMPILE_ASSERT(outOfLineGrowthFactor == 2, outOfLineGrowthFactor_is_two); + return WTF::roundUpToPowerOfTwo(outOfLineSize); } - - inline Structure* Structure::createStructure(JSGlobalData& globalData) + unsigned outOfLineSize() const { - ASSERT(!globalData.structureStructure); - Structure* structure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData); - structure->finishCreation(globalData, CreatingEarlyCell); - return structure; + ASSERT(checkOffsetConsistency()); + ASSERT(structure()->classInfo() == &s_info); + + return numberOfOutOfLineSlotsForLastOffset(m_offset); } - - inline Structure* Structure::create(JSGlobalData& globalData, const Structure* structure) + bool hasInlineStorage() const { - ASSERT(globalData.structureStructure); - Structure* newStructure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData, structure); - newStructure->finishCreation(globalData); - return newStructure; + return !!m_inlineCapacity; } - - inline PropertyOffset Structure::get(JSGlobalData& globalData, PropertyName propertyName) + unsigned inlineCapacity() const + { + return m_inlineCapacity; + } + unsigned inlineSize() const + { + return std::min<unsigned>(m_offset + 1, m_inlineCapacity); + } + unsigned totalStorageSize() const + { + return numberOfSlotsForLastOffset(m_offset, m_inlineCapacity); + } + unsigned totalStorageCapacity() const { ASSERT(structure()->classInfo() == &s_info); - materializePropertyMapIfNecessary(globalData); - if (!m_propertyTable) - return invalidOffset; - - PropertyMapEntry* entry = m_propertyTable->find(propertyName.uid()).first; - return entry ? entry->offset : invalidOffset; + return outOfLineCapacity() + inlineCapacity(); } - inline PropertyOffset Structure::get(JSGlobalData& globalData, const WTF::String& name) + PropertyOffset firstValidOffset() const { - ASSERT(structure()->classInfo() == &s_info); - materializePropertyMapIfNecessary(globalData); - if (!m_propertyTable) - return invalidOffset; + if (hasInlineStorage()) + return 0; + return firstOutOfLineOffset; + } + PropertyOffset lastValidOffset() const + { + return m_offset; + } + bool isValidOffset(PropertyOffset offset) const + { + return offset >= firstValidOffset() + && offset <= lastValidOffset(); + } + + bool masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject); - PropertyMapEntry* entry = m_propertyTable->findWithString(name.impl()).first; - return entry ? entry->offset : invalidOffset; + PropertyOffset get(VM&, PropertyName); + PropertyOffset get(VM&, const WTF::String& name); + JS_EXPORT_PRIVATE PropertyOffset get(VM&, PropertyName, unsigned& attributes, JSCell*& specificValue); + + bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; } + bool hasReadOnlyOrGetterSetterPropertiesExcludingProto() const { return m_hasReadOnlyOrGetterSetterPropertiesExcludingProto; } + void setHasGetterSetterProperties(bool is__proto__) + { + m_hasGetterSetterProperties = true; + if (!is__proto__) + m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true; } - - inline bool Structure::masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject) + void setContainsReadOnlyProperties() + { + m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true; + } + + bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; } + + bool isEmpty() const { - return typeInfo().masqueradesAsUndefined() && globalObject() == lexicalGlobalObject; + ASSERT(checkOffsetConsistency()); + return !JSC::isValidOffset(m_offset); } - inline JSValue JSValue::structureOrUndefined() const + JS_EXPORT_PRIVATE void despecifyDictionaryFunction(VM&, PropertyName); + void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; } + + void setEnumerationCache(VM&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h. + JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h. + void getPropertyNamesFromStructure(VM&, PropertyNameArray&, EnumerationMode); + + JSString* objectToStringValue() { - if (isCell()) - return JSValue(asCell()->structure()); - return jsUndefined(); + if (!typeInfo().structureHasRareData()) + return 0; + return rareData()->objectToStringValue(); } - inline bool JSCell::isObject() const + void setObjectToStringValue(VM& vm, const JSCell* owner, JSString* value) { - return m_structure->isObject(); + if (!typeInfo().structureHasRareData()) + allocateRareData(vm); + rareData()->setObjectToStringValue(vm, owner, value); } - inline bool JSCell::isString() const + bool staticFunctionsReified() { - return m_structure->typeInfo().type() == StringType; + return m_staticFunctionReified; } - inline bool JSCell::isGetterSetter() const + void setStaticFunctionsReified() { - return m_structure->typeInfo().type() == GetterSetterType; + m_staticFunctionReified = true; } - inline bool JSCell::isProxy() const + const ClassInfo* classInfo() const { return m_classInfo; } + + static ptrdiff_t prototypeOffset() { - return structure()->typeInfo().type() == ProxyType; + return OBJECT_OFFSETOF(Structure, m_prototype); } - inline bool JSCell::isAPIValueWrapper() const + static ptrdiff_t globalObjectOffset() { - return m_structure->typeInfo().type() == APIValueWrapperType; + return OBJECT_OFFSETOF(Structure, m_globalObject); } - inline void JSCell::setStructure(JSGlobalData& globalData, Structure* structure) + static ptrdiff_t typeInfoFlagsOffset() { - ASSERT(structure->typeInfo().overridesVisitChildren() == this->structure()->typeInfo().overridesVisitChildren()); - ASSERT(structure->classInfo() == m_structure->classInfo()); - ASSERT(!m_structure - || m_structure->transitionWatchpointSetHasBeenInvalidated() - || m_structure.get() == structure); - m_structure.set(globalData, this, structure); + return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::flagsOffset(); } - ALWAYS_INLINE void SlotVisitor::internalAppend(JSCell* cell) + static ptrdiff_t typeInfoTypeOffset() + { + return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::typeOffset(); + } + + static ptrdiff_t classInfoOffset() + { + return OBJECT_OFFSETOF(Structure, m_classInfo); + } + + static ptrdiff_t indexingTypeOffset() { - ASSERT(!m_isCheckingForDefaultMarkViolation); - if (!cell) - return; -#if ENABLE(GC_VALIDATION) - validate(cell); -#endif - if (Heap::testAndSetMarked(cell) || !cell->structure()) - return; + return OBJECT_OFFSETOF(Structure, m_indexingType); + } - m_visitCount++; + static Structure* createStructure(VM&); + + bool transitionWatchpointSetHasBeenInvalidated() const + { + return m_transitionWatchpointSet.hasBeenInvalidated(); + } + + bool transitionWatchpointSetIsStillValid() const + { + return m_transitionWatchpointSet.isStillValid(); + } + + void addTransitionWatchpoint(Watchpoint* watchpoint) const + { + ASSERT(transitionWatchpointSetIsStillValid()); + m_transitionWatchpointSet.add(watchpoint); + } + + void notifyTransitionFromThisStructure() const + { + m_transitionWatchpointSet.notifyWrite(); + } - MARK_LOG_CHILD(*this, cell); + static JS_EXPORTDATA const ClassInfo s_info; + +private: + friend class LLIntOffsetsExtractor; - // Should never attempt to mark something that is zapped. - ASSERT(!cell->isZapped()); + JS_EXPORT_PRIVATE Structure(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType, unsigned inlineCapacity); + Structure(VM&); + Structure(VM&, const Structure*); + + static Structure* create(VM&, const Structure*); - m_stack.append(cell); + typedef enum { + NoneDictionaryKind = 0, + CachedDictionaryKind = 1, + UncachedDictionaryKind = 2 + } DictionaryKind; + static Structure* toDictionaryTransition(VM&, Structure*, DictionaryKind); + + PropertyOffset putSpecificValue(VM&, PropertyName, unsigned attributes, JSCell* specificValue); + PropertyOffset remove(PropertyName); + + void createPropertyMap(VM&, unsigned keyCount = 0); + void checkConsistency(); + + bool despecifyFunction(VM&, PropertyName); + void despecifyAllFunctions(VM&); + + WriteBarrier<PropertyTable>& propertyTable(); + PropertyTable* takePropertyTableOrCloneIfPinned(VM&, Structure* owner); + PropertyTable* copyPropertyTable(VM&, Structure* owner); + PropertyTable* copyPropertyTableForPinning(VM&, Structure* owner); + JS_EXPORT_PRIVATE void materializePropertyMap(VM&); + void materializePropertyMapIfNecessary(VM& vm) + { + ASSERT(structure()->classInfo() == &s_info); + ASSERT(checkOffsetConsistency()); + if (!propertyTable() && previousID()) + materializePropertyMap(vm); + } + void materializePropertyMapIfNecessaryForPinning(VM& vm) + { + ASSERT(structure()->classInfo() == &s_info); + checkOffsetConsistency(); + if (!propertyTable()) + materializePropertyMap(vm); } - inline StructureTransitionTable::Hash::Key StructureTransitionTable::keyForWeakGCMapFinalizer(void*, Structure* structure) + void setPreviousID(VM& vm, Structure* transition, Structure* structure) { - // Newer versions of the STL have an std::make_pair function that takes rvalue references. - // When either of the parameters are bitfields, the C++ compiler will try to bind them as lvalues, which is invalid. To work around this, use unary "+" to make the parameter an rvalue. - // See https://bugs.webkit.org/show_bug.cgi?id=59261 for more details. - return Hash::Key(structure->m_nameInPrevious.get(), +structure->m_attributesInPrevious); + if (typeInfo().structureHasRareData()) + rareData()->setPreviousID(vm, transition, structure); + else + m_previousOrRareData.set(vm, transition, structure); } - inline bool Structure::transitivelyTransitionedFrom(Structure* structureToFind) + void clearPreviousID() { - for (Structure* current = this; current; current = current->previousID()) { - if (current == structureToFind) - return true; - } - return false; + if (typeInfo().structureHasRareData()) + rareData()->clearPreviousID(); + else + m_previousOrRareData.clear(); } - inline JSCell::JSCell(JSGlobalData& globalData, Structure* structure) - : m_structure(globalData, this, structure) + int transitionCount() const { + // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both. + return numberOfSlotsForLastOffset(m_offset, m_inlineCapacity); } - inline void JSCell::finishCreation(JSGlobalData& globalData, Structure* structure, CreatingEarlyCellTag) + bool isValid(JSGlobalObject*, StructureChain* cachedPrototypeChain) const; + bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const; + + void pin(); + + Structure* previous() const { -#if ENABLE(GC_VALIDATION) - ASSERT(globalData.isInitializingObject()); - globalData.setInitializingObjectClass(0); - if (structure) -#endif - m_structure.setEarlyValue(globalData, this, structure); - // Very first set of allocations won't have a real structure. - ASSERT(m_structure || !globalData.structureStructure); + ASSERT(!typeInfo().structureHasRareData()); + return static_cast<Structure*>(m_previousOrRareData.get()); } + StructureRareData* rareData() const + { + ASSERT(typeInfo().structureHasRareData()); + return static_cast<StructureRareData*>(m_previousOrRareData.get()); + } + + bool checkOffsetConsistency() const; + + void allocateRareData(VM&); + void cloneRareDataFrom(VM&, const Structure*); + + static const int s_maxTransitionLength = 64; + + static const unsigned maxSpecificFunctionThrashCount = 3; + + WriteBarrier<JSGlobalObject> m_globalObject; + WriteBarrier<Unknown> m_prototype; + mutable WriteBarrier<StructureChain> m_cachedPrototypeChain; + + WriteBarrier<JSCell> m_previousOrRareData; + + RefPtr<StringImpl> m_nameInPrevious; + WriteBarrier<JSCell> m_specificValueInPrevious; + + const ClassInfo* m_classInfo; + + StructureTransitionTable m_transitionTable; + + // Should be accessed through propertyTable(). During GC, it may be set to 0 by another thread. + WriteBarrier<PropertyTable> m_propertyTableUnsafe; + + mutable InlineWatchpointSet m_transitionWatchpointSet; + + COMPILE_ASSERT(firstOutOfLineOffset < 256, firstOutOfLineOffset_fits); + + // m_offset does not account for anonymous slots + PropertyOffset m_offset; + + TypeInfo m_typeInfo; + IndexingType m_indexingType; + + uint8_t m_inlineCapacity; + unsigned m_dictionaryKind : 2; + bool m_isPinnedPropertyTable : 1; + bool m_hasGetterSetterProperties : 1; + bool m_hasReadOnlyOrGetterSetterPropertiesExcludingProto : 1; + bool m_hasNonEnumerableProperties : 1; + unsigned m_attributesInPrevious : 14; + unsigned m_specificFunctionThrashCount : 2; + unsigned m_preventExtensions : 1; + unsigned m_didTransition : 1; + unsigned m_staticFunctionReified; +}; + } // namespace JSC #endif // Structure_h diff --git a/Source/JavaScriptCore/runtime/StructureChain.cpp b/Source/JavaScriptCore/runtime/StructureChain.cpp index a1c97340e..85abcd34f 100644 --- a/Source/JavaScriptCore/runtime/StructureChain.cpp +++ b/Source/JavaScriptCore/runtime/StructureChain.cpp @@ -27,6 +27,7 @@ #include "StructureChain.h" #include "JSObject.h" +#include "Operations.h" #include "Structure.h" #include <wtf/RefPtr.h> @@ -34,8 +35,8 @@ namespace JSC { ClassInfo StructureChain::s_info = { "StructureChain", 0, 0, 0, CREATE_METHOD_TABLE(StructureChain) }; -StructureChain::StructureChain(JSGlobalData& globalData, Structure* structure) - : JSCell(globalData, structure) +StructureChain::StructureChain(VM& vm, Structure* structure) + : JSCell(vm, structure) { } diff --git a/Source/JavaScriptCore/runtime/StructureChain.h b/Source/JavaScriptCore/runtime/StructureChain.h index 878f606b4..e652fecc2 100644 --- a/Source/JavaScriptCore/runtime/StructureChain.h +++ b/Source/JavaScriptCore/runtime/StructureChain.h @@ -46,16 +46,16 @@ namespace JSC { public: typedef JSCell Base; - static StructureChain* create(JSGlobalData& globalData, Structure* head) + static StructureChain* create(VM& vm, Structure* head) { - StructureChain* chain = new (NotNull, allocateCell<StructureChain>(globalData.heap)) StructureChain(globalData, globalData.structureChainStructure.get()); - chain->finishCreation(globalData, head); + StructureChain* chain = new (NotNull, allocateCell<StructureChain>(vm.heap)) StructureChain(vm, vm.structureChainStructure.get()); + chain->finishCreation(vm, head); return chain; } WriteBarrier<Structure>* head() { return m_vector.get(); } static void visitChildren(JSCell*, SlotVisitor&); - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) { return Structure::create(globalData, globalObject, prototype, TypeInfo(CompoundType, OverridesVisitChildren), &s_info); } + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, OverridesVisitChildren), &s_info); } static ClassInfo s_info; @@ -64,9 +64,9 @@ namespace JSC { static void destroy(JSCell*); protected: - void finishCreation(JSGlobalData& globalData, Structure* head) + void finishCreation(VM& vm, Structure* head) { - Base::finishCreation(globalData); + Base::finishCreation(vm); size_t size = 0; for (Structure* current = head; current; current = current->storedPrototype().isNull() ? 0 : asObject(current->storedPrototype())->structure()) ++size; @@ -75,13 +75,13 @@ namespace JSC { size_t i = 0; for (Structure* current = head; current; current = current->storedPrototype().isNull() ? 0 : asObject(current->storedPrototype())->structure()) - m_vector[i++].set(globalData, this, current); + m_vector[i++].set(vm, this, current); } private: friend class LLIntOffsetsExtractor; - StructureChain(JSGlobalData&, Structure*); + StructureChain(VM&, Structure*); OwnArrayPtr<WriteBarrier<Structure> > m_vector; }; diff --git a/Source/JavaScriptCore/runtime/StructureInlines.h b/Source/JavaScriptCore/runtime/StructureInlines.h new file mode 100644 index 000000000..75ca40dd7 --- /dev/null +++ b/Source/JavaScriptCore/runtime/StructureInlines.h @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2013 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 COMPUTER, 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 COMPUTER, 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 StructureInlines_h +#define StructureInlines_h + +#include "PropertyMapHashTable.h" +#include "Structure.h" + +namespace JSC { + +inline Structure* Structure::create(VM& vm, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, unsigned inlineCapacity) +{ + ASSERT(vm.structureStructure); + ASSERT(classInfo); + Structure* structure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm, globalObject, prototype, typeInfo, classInfo, indexingType, inlineCapacity); + structure->finishCreation(vm); + return structure; +} + +inline Structure* Structure::createStructure(VM& vm) +{ + ASSERT(!vm.structureStructure); + Structure* structure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm); + structure->finishCreation(vm, CreatingEarlyCell); + return structure; +} + +inline Structure* Structure::create(VM& vm, const Structure* structure) +{ + ASSERT(vm.structureStructure); + Structure* newStructure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm, structure); + newStructure->finishCreation(vm); + return newStructure; +} + +inline PropertyOffset Structure::get(VM& vm, PropertyName propertyName) +{ + ASSERT(structure()->classInfo() == &s_info); + materializePropertyMapIfNecessary(vm); + if (!propertyTable()) + return invalidOffset; + + PropertyMapEntry* entry = propertyTable()->find(propertyName.uid()).first; + return entry ? entry->offset : invalidOffset; +} + +inline PropertyOffset Structure::get(VM& vm, const WTF::String& name) +{ + ASSERT(structure()->classInfo() == &s_info); + materializePropertyMapIfNecessary(vm); + if (!propertyTable()) + return invalidOffset; + + PropertyMapEntry* entry = propertyTable()->findWithString(name.impl()).first; + return entry ? entry->offset : invalidOffset; +} + +inline bool Structure::masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject) +{ + return typeInfo().masqueradesAsUndefined() && globalObject() == lexicalGlobalObject; +} + +ALWAYS_INLINE void SlotVisitor::internalAppend(JSCell* cell) +{ + ASSERT(!m_isCheckingForDefaultMarkViolation); + if (!cell) + return; +#if ENABLE(GC_VALIDATION) + validate(cell); +#endif + if (Heap::testAndSetMarked(cell) || !cell->structure()) + return; + + m_visitCount++; + + MARK_LOG_CHILD(*this, cell); + + // Should never attempt to mark something that is zapped. + ASSERT(!cell->isZapped()); + + m_stack.append(cell); +} + +inline bool Structure::transitivelyTransitionedFrom(Structure* structureToFind) +{ + for (Structure* current = this; current; current = current->previousID()) { + if (current == structureToFind) + return true; + } + return false; +} + +inline void Structure::setEnumerationCache(VM& vm, JSPropertyNameIterator* enumerationCache) +{ + ASSERT(!isDictionary()); + if (!typeInfo().structureHasRareData()) + allocateRareData(vm); + rareData()->setEnumerationCache(vm, this, enumerationCache); +} + +inline JSPropertyNameIterator* Structure::enumerationCache() +{ + if (!typeInfo().structureHasRareData()) + return 0; + return rareData()->enumerationCache(); +} + +inline JSValue Structure::prototypeForLookup(JSGlobalObject* globalObject) const +{ + if (isObject()) + return m_prototype.get(); + + ASSERT(typeInfo().type() == StringType); + return globalObject->stringPrototype(); +} + +inline JSValue Structure::prototypeForLookup(ExecState* exec) const +{ + return prototypeForLookup(exec->lexicalGlobalObject()); +} + +inline StructureChain* Structure::prototypeChain(VM& vm, JSGlobalObject* globalObject) const +{ + // We cache our prototype chain so our clients can share it. + if (!isValid(globalObject, m_cachedPrototypeChain.get())) { + JSValue prototype = prototypeForLookup(globalObject); + m_cachedPrototypeChain.set(vm, this, StructureChain::create(vm, prototype.isNull() ? 0 : asObject(prototype)->structure())); + } + return m_cachedPrototypeChain.get(); +} + +inline StructureChain* Structure::prototypeChain(ExecState* exec) const +{ + return prototypeChain(exec->vm(), exec->lexicalGlobalObject()); +} + +inline bool Structure::isValid(JSGlobalObject* globalObject, StructureChain* cachedPrototypeChain) const +{ + if (!cachedPrototypeChain) + return false; + + JSValue prototype = prototypeForLookup(globalObject); + WriteBarrier<Structure>* cachedStructure = cachedPrototypeChain->head(); + while (*cachedStructure && !prototype.isNull()) { + if (asObject(prototype)->structure() != cachedStructure->get()) + return false; + ++cachedStructure; + prototype = asObject(prototype)->prototype(); + } + return prototype.isNull() && !*cachedStructure; +} + +inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const +{ + return isValid(exec->lexicalGlobalObject(), cachedPrototypeChain); +} + +inline bool Structure::putWillGrowOutOfLineStorage() +{ + checkOffsetConsistency(); + + ASSERT(outOfLineCapacity() >= outOfLineSize()); + + if (!propertyTable()) { + unsigned currentSize = numberOfOutOfLineSlotsForLastOffset(m_offset); + ASSERT(outOfLineCapacity() >= currentSize); + return currentSize == outOfLineCapacity(); + } + + ASSERT(totalStorageCapacity() >= propertyTable()->propertyStorageSize()); + if (propertyTable()->hasDeletedOffset()) + return false; + + ASSERT(totalStorageCapacity() >= propertyTable()->size()); + return propertyTable()->size() == totalStorageCapacity(); +} + +ALWAYS_INLINE WriteBarrier<PropertyTable>& Structure::propertyTable() +{ + ASSERT(!globalObject() || !globalObject()->vm().heap.isBusy()); + return m_propertyTableUnsafe; +} + +ALWAYS_INLINE bool Structure::checkOffsetConsistency() const +{ + PropertyTable* propertyTable = m_propertyTableUnsafe.get(); + + if (!propertyTable) { + ASSERT(!m_isPinnedPropertyTable); + return true; + } + + RELEASE_ASSERT(numberOfSlotsForLastOffset(m_offset, m_inlineCapacity) == propertyTable->propertyStorageSize()); + unsigned totalSize = propertyTable->propertyStorageSize(); + RELEASE_ASSERT((totalSize < inlineCapacity() ? 0 : totalSize - inlineCapacity()) == numberOfOutOfLineSlotsForLastOffset(m_offset)); + + return true; +} + +} // namespace JSC + +#endif // StructureInlines_h + diff --git a/Source/JavaScriptCore/runtime/StructureRareData.cpp b/Source/JavaScriptCore/runtime/StructureRareData.cpp new file mode 100644 index 000000000..00880d32c --- /dev/null +++ b/Source/JavaScriptCore/runtime/StructureRareData.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2013 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 "StructureRareData.h" + +#include "JSString.h" +#include "Operations.h" + +namespace JSC { + +const ClassInfo StructureRareData::s_info = { "StructureRareData", 0, 0, 0, CREATE_METHOD_TABLE(StructureRareData) }; + +Structure* StructureRareData::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) +{ + return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, StructureFlags), &s_info); +} + +StructureRareData* StructureRareData::create(VM& vm, Structure* previous) +{ + StructureRareData* rareData = new (NotNull, allocateCell<StructureRareData>(vm.heap)) StructureRareData(vm, previous); + rareData->finishCreation(vm); + return rareData; +} + +StructureRareData* StructureRareData::clone(VM& vm, const StructureRareData* other) +{ + StructureRareData* newRareData = new (NotNull, allocateCell<StructureRareData>(vm.heap)) StructureRareData(vm, other); + newRareData->finishCreation(vm); + return newRareData; +} + +StructureRareData::StructureRareData(VM& vm, Structure* previous) + : JSCell(vm, vm.structureRareDataStructure.get()) +{ + if (previous) + m_previous.set(vm, this, previous); +} + +StructureRareData::StructureRareData(VM& vm, const StructureRareData* other) + : JSCell(vm, other->structure()) +{ + if (other->previousID()) + m_previous.set(vm, this, other->previousID()); + if (other->objectToStringValue()) + m_objectToStringValue.set(vm, this, other->objectToStringValue()); +} + +void StructureRareData::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + StructureRareData* thisObject = jsCast<StructureRareData*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + + JSCell::visitChildren(thisObject, visitor); + visitor.append(&thisObject->m_previous); + visitor.append(&thisObject->m_objectToStringValue); + visitor.append(&thisObject->m_enumerationCache); +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/StructureRareData.h b/Source/JavaScriptCore/runtime/StructureRareData.h new file mode 100644 index 000000000..e5db9e5f4 --- /dev/null +++ b/Source/JavaScriptCore/runtime/StructureRareData.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2013 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 StructureRareData_h +#define StructureRareData_h + +#include "ClassInfo.h" +#include "JSCell.h" +#include "JSTypeInfo.h" + +namespace JSC { + +class JSPropertyNameIterator; +class Structure; + +class StructureRareData : public JSCell { + friend class Structure; +public: + static StructureRareData* create(VM&, Structure*); + static StructureRareData* clone(VM&, const StructureRareData* other); + + static void visitChildren(JSCell*, SlotVisitor&); + + static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype); + + // Returns true if this StructureRareData should also be cloned when cloning the owner Structure. + bool needsCloning() const { return false; } + + Structure* previousID() const; + void setPreviousID(VM&, Structure* transition, Structure*); + void clearPreviousID(); + + JSString* objectToStringValue() const; + void setObjectToStringValue(VM&, const JSCell* owner, JSString* value); + + JSPropertyNameIterator* enumerationCache(); + void setEnumerationCache(VM&, const Structure* owner, JSPropertyNameIterator* value); + + static JS_EXPORTDATA const ClassInfo s_info; + +private: + StructureRareData(VM&, Structure*); + StructureRareData(VM&, const StructureRareData*); + + static const unsigned StructureFlags = OverridesVisitChildren | JSCell::StructureFlags; + + WriteBarrier<Structure> m_previous; + WriteBarrier<JSString> m_objectToStringValue; + WriteBarrier<JSPropertyNameIterator> m_enumerationCache; +}; + +} // namespace JSC + +#endif // StructureRareData_h diff --git a/Source/JavaScriptCore/runtime/StructureRareDataInlines.h b/Source/JavaScriptCore/runtime/StructureRareDataInlines.h new file mode 100644 index 000000000..20b7f8b12 --- /dev/null +++ b/Source/JavaScriptCore/runtime/StructureRareDataInlines.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 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 StructureRareDataInlines_h +#define StructureRareDataInlines_h + +#include "StructureRareData.h" + +namespace JSC { + +inline Structure* StructureRareData::previousID() const +{ + return m_previous.get(); +} + +inline void StructureRareData::setPreviousID(VM& vm, Structure* transition, Structure* structure) +{ + m_previous.set(vm, transition, structure); +} + +inline void StructureRareData::clearPreviousID() +{ + m_previous.clear(); +} + +inline JSString* StructureRareData::objectToStringValue() const +{ + return m_objectToStringValue.get(); +} + +inline void StructureRareData::setObjectToStringValue(VM& vm, const JSCell* owner, JSString* value) +{ + m_objectToStringValue.set(vm, owner, value); +} + +} // namespace JSC + +#endif // StructureRareDataInlines_h diff --git a/Source/JavaScriptCore/runtime/StructureTransitionTable.h b/Source/JavaScriptCore/runtime/StructureTransitionTable.h index 5291ed540..601202017 100644 --- a/Source/JavaScriptCore/runtime/StructureTransitionTable.h +++ b/Source/JavaScriptCore/runtime/StructureTransitionTable.h @@ -85,7 +85,7 @@ inline IndexingType newIndexingType(IndexingType oldType, NonPropertyTransition case AddIndexedAccessors: return oldType | MayHaveIndexedAccessors; default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return oldType; } } @@ -111,21 +111,7 @@ class StructureTransitionTable { static const bool safeToCompareToEmptyOrDeleted = true; }; - 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> TransitionMap; - - static Hash::Key keyForWeakGCMapFinalizer(void* context, Structure*); + typedef WeakGCMap<Hash::Key, Structure, Hash> TransitionMap; public: StructureTransitionTable() @@ -146,7 +132,7 @@ public: WeakSet::deallocate(impl); } - inline void add(JSGlobalData&, Structure*); + inline void add(VM&, Structure*); inline bool contains(StringImpl* rep, unsigned attributes) const; inline Structure* get(StringImpl* rep, unsigned attributes) const; @@ -191,7 +177,7 @@ private: return 0; } - void setSingleTransition(JSGlobalData&, Structure* structure) + void setSingleTransition(VM&, Structure* structure) { ASSERT(isUsingSingleSlot()); if (WeakImpl* impl = this->weakImpl()) diff --git a/Source/JavaScriptCore/runtime/SymbolTable.cpp b/Source/JavaScriptCore/runtime/SymbolTable.cpp index 1b7fd89c5..8c5a00b03 100644 --- a/Source/JavaScriptCore/runtime/SymbolTable.cpp +++ b/Source/JavaScriptCore/runtime/SymbolTable.cpp @@ -38,7 +38,7 @@ SymbolTableEntry& SymbolTableEntry::copySlow(const SymbolTableEntry& other) ASSERT(other.isFat()); FatEntry* newFatEntry = new FatEntry(*other.fatEntry()); freeFatEntry(); - m_bits = bitwise_cast<intptr_t>(newFatEntry) | FatFlag; + m_bits = bitwise_cast<intptr_t>(newFatEntry); return *this; } @@ -94,7 +94,7 @@ void SymbolTableEntry::notifyWriteSlow() SymbolTableEntry::FatEntry* SymbolTableEntry::inflateSlow() { FatEntry* entry = new FatEntry(m_bits); - m_bits = bitwise_cast<intptr_t>(entry) | FatFlag; + m_bits = bitwise_cast<intptr_t>(entry); return entry; } diff --git a/Source/JavaScriptCore/runtime/SymbolTable.h b/Source/JavaScriptCore/runtime/SymbolTable.h index 87d1c8be5..49a00dd39 100644 --- a/Source/JavaScriptCore/runtime/SymbolTable.h +++ b/Source/JavaScriptCore/runtime/SymbolTable.h @@ -31,375 +31,374 @@ #include "JSObject.h" #include "Watchpoint.h" -#include <wtf/AlwaysInline.h> #include <wtf/HashTraits.h> #include <wtf/text/StringImpl.h> namespace JSC { - class Watchpoint; - class WatchpointSet; +class Watchpoint; +class WatchpointSet; - struct SlowArgument { - enum Status { - Normal = 0, - Captured = 1, - Deleted = 2 - }; - - SlowArgument() - : status(Normal) - , index(0) - { - } - - Status status; - int index; // If status is 'Deleted', index is bogus. +struct SlowArgument { + enum Status { + Normal = 0, + Captured = 1, + Deleted = 2 }; - static ALWAYS_INLINE int missingSymbolMarker() { return std::numeric_limits<int>::max(); } - - // The bit twiddling in this class assumes that every register index is a - // reasonably small positive or negative number, and therefore has its high - // four bits all set or all unset. - - // In addition to implementing semantics-mandated variable attributes and - // implementation-mandated variable indexing, this class also implements - // watchpoints to be used for JIT optimizations. Because watchpoints are - // meant to be relatively rare, this class optimizes heavily for the case - // that they are not being used. To that end, this class uses the thin-fat - // idiom: either it is thin, in which case it contains an in-place encoded - // word that consists of attributes, the index, and a bit saying that it is - // thin; or it is fat, in which case it contains a pointer to a malloc'd - // data structure and a bit saying that it is fat. The malloc'd data - // structure will be malloced a second time upon copy, to preserve the - // property that in-place edits to SymbolTableEntry do not manifest in any - // copies. However, the malloc'd FatEntry data structure contains a ref- - // counted pointer to a shared WatchpointSet. Thus, in-place edits of the - // WatchpointSet will manifest in all copies. Here's a picture: - // - // SymbolTableEntry --> FatEntry --> WatchpointSet - // - // If you make a copy of a SymbolTableEntry, you will have: - // - // original: SymbolTableEntry --> FatEntry --> WatchpointSet - // copy: SymbolTableEntry --> FatEntry -----^ - - struct SymbolTableEntry { - // Use the SymbolTableEntry::Fast class, either via implicit cast or by calling - // getFast(), when you (1) only care about isNull(), getIndex(), and isReadOnly(), - // and (2) you are in a hot path where you need to minimize the number of times - // that you branch on isFat() when getting the bits(). - class Fast { - public: - Fast() - : m_bits(0) - { - } - - ALWAYS_INLINE Fast(const SymbolTableEntry& entry) - : m_bits(entry.bits()) - { - } - - bool isNull() const - { - return !m_bits; - } - - int getIndex() const - { - return static_cast<int>(m_bits >> FlagBits); - } - - bool isReadOnly() const - { - return m_bits & ReadOnlyFlag; - } - - unsigned getAttributes() const - { - unsigned attributes = 0; - if (m_bits & ReadOnlyFlag) - attributes |= ReadOnly; - if (m_bits & DontEnumFlag) - attributes |= DontEnum; - return attributes; - } - - bool isFat() const - { - return m_bits & FatFlag; - } - - private: - friend struct SymbolTableEntry; - intptr_t m_bits; - }; - - SymbolTableEntry() - : m_bits(0) - { - } - - SymbolTableEntry(int index) - : m_bits(0) - { - ASSERT(isValidIndex(index)); - pack(index, false, false); - } - - SymbolTableEntry(int index, unsigned attributes) - : m_bits(0) - { - ASSERT(isValidIndex(index)); - pack(index, attributes & ReadOnly, attributes & DontEnum); - } - - ~SymbolTableEntry() - { - freeFatEntry(); - } - - SymbolTableEntry(const SymbolTableEntry& other) - : m_bits(0) + SlowArgument() + : status(Normal) + , index(0) + { + } + + Status status; + int index; // If status is 'Deleted', index is bogus. +}; + +static ALWAYS_INLINE int missingSymbolMarker() { return std::numeric_limits<int>::max(); } + +// The bit twiddling in this class assumes that every register index is a +// reasonably small positive or negative number, and therefore has its high +// four bits all set or all unset. + +// In addition to implementing semantics-mandated variable attributes and +// implementation-mandated variable indexing, this class also implements +// watchpoints to be used for JIT optimizations. Because watchpoints are +// meant to be relatively rare, this class optimizes heavily for the case +// that they are not being used. To that end, this class uses the thin-fat +// idiom: either it is thin, in which case it contains an in-place encoded +// word that consists of attributes, the index, and a bit saying that it is +// thin; or it is fat, in which case it contains a pointer to a malloc'd +// data structure and a bit saying that it is fat. The malloc'd data +// structure will be malloced a second time upon copy, to preserve the +// property that in-place edits to SymbolTableEntry do not manifest in any +// copies. However, the malloc'd FatEntry data structure contains a ref- +// counted pointer to a shared WatchpointSet. Thus, in-place edits of the +// WatchpointSet will manifest in all copies. Here's a picture: +// +// SymbolTableEntry --> FatEntry --> WatchpointSet +// +// If you make a copy of a SymbolTableEntry, you will have: +// +// original: SymbolTableEntry --> FatEntry --> WatchpointSet +// copy: SymbolTableEntry --> FatEntry -----^ + +struct SymbolTableEntry { + // Use the SymbolTableEntry::Fast class, either via implicit cast or by calling + // getFast(), when you (1) only care about isNull(), getIndex(), and isReadOnly(), + // and (2) you are in a hot path where you need to minimize the number of times + // that you branch on isFat() when getting the bits(). + class Fast { + public: + Fast() + : m_bits(SlimFlag) { - *this = other; } - SymbolTableEntry& operator=(const SymbolTableEntry& other) + ALWAYS_INLINE Fast(const SymbolTableEntry& entry) + : m_bits(entry.bits()) { - if (UNLIKELY(other.isFat())) - return copySlow(other); - freeFatEntry(); - m_bits = other.m_bits; - return *this; } - + bool isNull() const { - return !bits(); + return !(m_bits & ~SlimFlag); } int getIndex() const { - return static_cast<int>(bits() >> FlagBits); - } - - ALWAYS_INLINE Fast getFast() const - { - return Fast(*this); + return static_cast<int>(m_bits >> FlagBits); } - - ALWAYS_INLINE Fast getFast(bool& wasFat) const + + bool isReadOnly() const { - Fast result; - wasFat = isFat(); - if (wasFat) - result.m_bits = fatEntry()->m_bits; - else - result.m_bits = m_bits; - return result; + return m_bits & ReadOnlyFlag; } unsigned getAttributes() const { - return getFast().getAttributes(); - } - - void setAttributes(unsigned attributes) - { - pack(getIndex(), attributes & ReadOnly, attributes & DontEnum); + unsigned attributes = 0; + if (m_bits & ReadOnlyFlag) + attributes |= ReadOnly; + if (m_bits & DontEnumFlag) + attributes |= DontEnum; + return attributes; } - bool isReadOnly() const - { - return bits() & ReadOnlyFlag; - } - - bool couldBeWatched(); - - // Notify an opportunity to create a watchpoint for a variable. This is - // idempotent and fail-silent. It is idempotent in the sense that if - // a watchpoint set had already been created, then another one will not - // be created. Hence two calls to this method have the same effect as - // one call. It is also fail-silent, in the sense that if a watchpoint - // set had been created and had already been invalidated, then this will - // just return. This means that couldBeWatched() may return false even - // immediately after a call to attemptToWatch(). - void attemptToWatch(); - - bool* addressOfIsWatched(); - - void addWatchpoint(Watchpoint*); - - WatchpointSet* watchpointSet() - { - return fatEntry()->m_watchpoints.get(); - } - - ALWAYS_INLINE void notifyWrite() - { - if (LIKELY(!isFat())) - return; - notifyWriteSlow(); - } - - private: - static const intptr_t FatFlag = 0x1; - static const intptr_t ReadOnlyFlag = 0x2; - static const intptr_t DontEnumFlag = 0x4; - static const intptr_t NotNullFlag = 0x8; - static const intptr_t FlagBits = 4; - - class FatEntry { - WTF_MAKE_FAST_ALLOCATED; - public: - FatEntry(intptr_t bits) - : m_bits(bits | FatFlag) - { - } - - intptr_t m_bits; // always has FatFlag set and exactly matches what the bits would have been if this wasn't fat. - - RefPtr<WatchpointSet> m_watchpoints; - }; - - SymbolTableEntry& copySlow(const SymbolTableEntry&); - JS_EXPORT_PRIVATE void notifyWriteSlow(); - bool isFat() const { - return m_bits & FatFlag; - } - - const FatEntry* fatEntry() const - { - ASSERT(isFat()); - return bitwise_cast<const FatEntry*>(m_bits & ~FatFlag); - } - - FatEntry* fatEntry() - { - ASSERT(isFat()); - return bitwise_cast<FatEntry*>(m_bits & ~FatFlag); - } - - FatEntry* inflate() - { - if (LIKELY(isFat())) - return fatEntry(); - return inflateSlow(); - } - - FatEntry* inflateSlow(); - - ALWAYS_INLINE intptr_t bits() const - { - if (isFat()) - return fatEntry()->m_bits; - return m_bits; - } - - ALWAYS_INLINE intptr_t& bits() - { - if (isFat()) - return fatEntry()->m_bits; - return m_bits; - } - - void freeFatEntry() - { - if (LIKELY(!isFat())) - return; - freeFatEntrySlow(); - } - - void freeFatEntrySlow(); - - void pack(int index, bool readOnly, bool dontEnum) - { - intptr_t& bitsRef = bits(); - bitsRef = (static_cast<intptr_t>(index) << FlagBits) | NotNullFlag; - if (readOnly) - bitsRef |= ReadOnlyFlag; - if (dontEnum) - bitsRef |= DontEnumFlag; + return !(m_bits & SlimFlag); } - bool isValidIndex(int index) - { - return ((static_cast<intptr_t>(index) << FlagBits) >> FlagBits) == static_cast<intptr_t>(index); - } - + private: + friend struct SymbolTableEntry; intptr_t m_bits; }; - struct SymbolTableIndexHashTraits : HashTraits<SymbolTableEntry> { - static const bool emptyValueIsZero = true; - static const bool needsDestruction = true; - }; - - typedef HashMap<RefPtr<StringImpl>, SymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<StringImpl> >, SymbolTableIndexHashTraits> SymbolTable; - - class SharedSymbolTable : public JSCell, public SymbolTable { + SymbolTableEntry() + : m_bits(SlimFlag) + { + } + + SymbolTableEntry(int index) + : m_bits(SlimFlag) + { + ASSERT(isValidIndex(index)); + pack(index, false, false); + } + + SymbolTableEntry(int index, unsigned attributes) + : m_bits(SlimFlag) + { + ASSERT(isValidIndex(index)); + pack(index, attributes & ReadOnly, attributes & DontEnum); + } + + ~SymbolTableEntry() + { + freeFatEntry(); + } + + SymbolTableEntry(const SymbolTableEntry& other) + : m_bits(SlimFlag) + { + *this = other; + } + + SymbolTableEntry& operator=(const SymbolTableEntry& other) + { + if (UNLIKELY(other.isFat())) + return copySlow(other); + freeFatEntry(); + m_bits = other.m_bits; + return *this; + } + + bool isNull() const + { + return !(bits() & ~SlimFlag); + } + + int getIndex() const + { + return static_cast<int>(bits() >> FlagBits); + } + + ALWAYS_INLINE Fast getFast() const + { + return Fast(*this); + } + + ALWAYS_INLINE Fast getFast(bool& wasFat) const + { + Fast result; + wasFat = isFat(); + if (wasFat) + result.m_bits = fatEntry()->m_bits | SlimFlag; + else + result.m_bits = m_bits; + return result; + } + + unsigned getAttributes() const + { + return getFast().getAttributes(); + } + + void setAttributes(unsigned attributes) + { + pack(getIndex(), attributes & ReadOnly, attributes & DontEnum); + } + + bool isReadOnly() const + { + return bits() & ReadOnlyFlag; + } + + bool couldBeWatched(); + + // Notify an opportunity to create a watchpoint for a variable. This is + // idempotent and fail-silent. It is idempotent in the sense that if + // a watchpoint set had already been created, then another one will not + // be created. Hence two calls to this method have the same effect as + // one call. It is also fail-silent, in the sense that if a watchpoint + // set had been created and had already been invalidated, then this will + // just return. This means that couldBeWatched() may return false even + // immediately after a call to attemptToWatch(). + void attemptToWatch(); + + bool* addressOfIsWatched(); + + void addWatchpoint(Watchpoint*); + + WatchpointSet* watchpointSet() + { + return fatEntry()->m_watchpoints.get(); + } + + ALWAYS_INLINE void notifyWrite() + { + if (LIKELY(!isFat())) + return; + notifyWriteSlow(); + } + +private: + static const intptr_t SlimFlag = 0x1; + static const intptr_t ReadOnlyFlag = 0x2; + static const intptr_t DontEnumFlag = 0x4; + static const intptr_t NotNullFlag = 0x8; + static const intptr_t FlagBits = 4; + + class FatEntry { + WTF_MAKE_FAST_ALLOCATED; public: - typedef JSCell Base; - - static SharedSymbolTable* create(JSGlobalData& globalData) - { - SharedSymbolTable* sharedSymbolTable = new (NotNull, allocateCell<SharedSymbolTable>(globalData.heap)) SharedSymbolTable(globalData); - sharedSymbolTable->finishCreation(globalData); - return sharedSymbolTable; - } - static const bool needsDestruction = true; - static const bool hasImmortalStructure = true; - static void destroy(JSCell*); - - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(globalData, globalObject, prototype, TypeInfo(LeafType, StructureFlags), &s_info); - } - - bool usesNonStrictEval() { return m_usesNonStrictEval; } - void setUsesNonStrictEval(bool usesNonStrictEval) { m_usesNonStrictEval = usesNonStrictEval; } - - int captureStart() { return m_captureStart; } - void setCaptureStart(int captureStart) { m_captureStart = captureStart; } - - int captureEnd() { return m_captureEnd; } - void setCaptureEnd(int captureEnd) { m_captureEnd = captureEnd; } - - int captureCount() { return m_captureEnd - m_captureStart; } - - int parameterCount() { return m_parameterCountIncludingThis - 1; } - int parameterCountIncludingThis() { return m_parameterCountIncludingThis; } - void setParameterCountIncludingThis(int parameterCountIncludingThis) { m_parameterCountIncludingThis = parameterCountIncludingThis; } - - // 0 if we don't capture any arguments; parameterCount() in length if we do. - const SlowArgument* slowArguments() { return m_slowArguments.get(); } - void setSlowArguments(PassOwnArrayPtr<SlowArgument> slowArguments) { m_slowArguments = slowArguments; } - - static JS_EXPORTDATA const ClassInfo s_info; - - private: - SharedSymbolTable(JSGlobalData& globalData) - : JSCell(globalData, globalData.sharedSymbolTableStructure.get()) - , m_parameterCountIncludingThis(0) - , m_usesNonStrictEval(false) - , m_captureStart(0) - , m_captureEnd(0) + FatEntry(intptr_t bits) + : m_bits(bits & ~SlimFlag) { } - - int m_parameterCountIncludingThis; - bool m_usesNonStrictEval; - - int m_captureStart; - int m_captureEnd; - - OwnArrayPtr<SlowArgument> m_slowArguments; + + intptr_t m_bits; // always has FatFlag set and exactly matches what the bits would have been if this wasn't fat. + + RefPtr<WatchpointSet> m_watchpoints; }; + + SymbolTableEntry& copySlow(const SymbolTableEntry&); + JS_EXPORT_PRIVATE void notifyWriteSlow(); + + bool isFat() const + { + return !(m_bits & SlimFlag); + } + + const FatEntry* fatEntry() const + { + ASSERT(isFat()); + return bitwise_cast<const FatEntry*>(m_bits); + } + + FatEntry* fatEntry() + { + ASSERT(isFat()); + return bitwise_cast<FatEntry*>(m_bits); + } + + FatEntry* inflate() + { + if (LIKELY(isFat())) + return fatEntry(); + return inflateSlow(); + } + + FatEntry* inflateSlow(); + + ALWAYS_INLINE intptr_t bits() const + { + if (isFat()) + return fatEntry()->m_bits; + return m_bits; + } + + ALWAYS_INLINE intptr_t& bits() + { + if (isFat()) + return fatEntry()->m_bits; + return m_bits; + } + + void freeFatEntry() + { + if (LIKELY(!isFat())) + return; + freeFatEntrySlow(); + } + + JS_EXPORT_PRIVATE void freeFatEntrySlow(); + + void pack(int index, bool readOnly, bool dontEnum) + { + ASSERT(!isFat()); + intptr_t& bitsRef = bits(); + bitsRef = (static_cast<intptr_t>(index) << FlagBits) | NotNullFlag | SlimFlag; + if (readOnly) + bitsRef |= ReadOnlyFlag; + if (dontEnum) + bitsRef |= DontEnumFlag; + } + + bool isValidIndex(int index) + { + return ((static_cast<intptr_t>(index) << FlagBits) >> FlagBits) == static_cast<intptr_t>(index); + } + + intptr_t m_bits; +}; + +struct SymbolTableIndexHashTraits : HashTraits<SymbolTableEntry> { + static const bool needsDestruction = true; +}; + +typedef HashMap<RefPtr<StringImpl>, SymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<StringImpl> >, SymbolTableIndexHashTraits> SymbolTable; + +class SharedSymbolTable : public JSCell, public SymbolTable { +public: + typedef JSCell Base; + + static SharedSymbolTable* create(VM& vm) + { + SharedSymbolTable* sharedSymbolTable = new (NotNull, allocateCell<SharedSymbolTable>(vm.heap)) SharedSymbolTable(vm); + sharedSymbolTable->finishCreation(vm); + return sharedSymbolTable; + } + static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; + static void destroy(JSCell*); + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(LeafType, StructureFlags), &s_info); + } + + bool usesNonStrictEval() { return m_usesNonStrictEval; } + void setUsesNonStrictEval(bool usesNonStrictEval) { m_usesNonStrictEval = usesNonStrictEval; } + + int captureStart() { return m_captureStart; } + void setCaptureStart(int captureStart) { m_captureStart = captureStart; } + + int captureEnd() { return m_captureEnd; } + void setCaptureEnd(int captureEnd) { m_captureEnd = captureEnd; } + + int captureCount() { return m_captureEnd - m_captureStart; } + + int parameterCount() { return m_parameterCountIncludingThis - 1; } + int parameterCountIncludingThis() { return m_parameterCountIncludingThis; } + void setParameterCountIncludingThis(int parameterCountIncludingThis) { m_parameterCountIncludingThis = parameterCountIncludingThis; } + + // 0 if we don't capture any arguments; parameterCount() in length if we do. + const SlowArgument* slowArguments() { return m_slowArguments.get(); } + void setSlowArguments(PassOwnArrayPtr<SlowArgument> slowArguments) { m_slowArguments = slowArguments; } + + static JS_EXPORTDATA const ClassInfo s_info; + +private: + SharedSymbolTable(VM& vm) + : JSCell(vm, vm.sharedSymbolTableStructure.get()) + , m_parameterCountIncludingThis(0) + , m_usesNonStrictEval(false) + , m_captureStart(0) + , m_captureEnd(0) + { + } + + int m_parameterCountIncludingThis; + bool m_usesNonStrictEval; + + int m_captureStart; + int m_captureEnd; + + OwnArrayPtr<SlowArgument> m_slowArguments; +}; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Terminator.h b/Source/JavaScriptCore/runtime/Terminator.h deleted file mode 100644 index 6b0f2366f..000000000 --- a/Source/JavaScriptCore/runtime/Terminator.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2010 Google 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. - * 3. Neither the name of Google Inc. ("Google") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 Terminator_h -#define Terminator_h - -namespace JSC { - -class Terminator { -public: - Terminator() : m_shouldTerminate(false) { } - - void terminateSoon() { m_shouldTerminate = true; } - bool shouldTerminate() const { return m_shouldTerminate; } - -private: - bool m_shouldTerminate; -}; - -} // namespace JSC - -#endif // Terminator_h diff --git a/Source/JavaScriptCore/runtime/TimeoutChecker.cpp b/Source/JavaScriptCore/runtime/TimeoutChecker.cpp deleted file mode 100644 index 56d6d4b71..000000000 --- a/Source/JavaScriptCore/runtime/TimeoutChecker.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. - * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> - * - * 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "TimeoutChecker.h" - -#include "CallFrame.h" -#include "JSGlobalObject.h" - -#if OS(DARWIN) -#include <mach/mach.h> -#elif OS(WINDOWS) -#include <windows.h> -#else -#include <wtf/CurrentTime.h> -#endif - -using namespace std; - -namespace JSC { - -// Number of ticks before the first timeout check is done. -static const int ticksUntilFirstCheck = 1024; - -// Number of milliseconds between each timeout check. -static const int intervalBetweenChecks = 1000; - -// Returns the time the current thread has spent executing, in milliseconds. -static inline unsigned getCPUTime() -{ -#if OS(DARWIN) - mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT; - thread_basic_info_data_t info; - - // Get thread information - mach_port_t threadPort = mach_thread_self(); - thread_info(threadPort, THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount); - mach_port_deallocate(mach_task_self(), threadPort); - - unsigned time = info.user_time.seconds * 1000 + info.user_time.microseconds / 1000; - time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000; - - return time; -#elif OS(WINDOWS) - union { - FILETIME fileTime; - unsigned long long fileTimeAsLong; - } userTime, kernelTime; - - // GetThreadTimes won't accept NULL arguments so we pass these even though - // they're not used. - FILETIME creationTime, exitTime; - - GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime); - - return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000; -#elif OS(QNX) - struct timespec time; - if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &time)) - CRASH(); - return time.tv_sec * 1000.0 + time.tv_nsec / 1.0e6; -#else - // FIXME: We should return the time the current thread has spent executing. - - // use a relative time from first call in order to avoid an overflow - static double firstTime = currentTime(); - return static_cast<unsigned> ((currentTime() - firstTime) * 1000); -#endif -} - -TimeoutChecker::TimeoutChecker() - : m_timeoutInterval(0) - , m_startCount(0) -{ - reset(); -} - -void TimeoutChecker::reset() -{ - m_ticksUntilNextCheck = ticksUntilFirstCheck; - m_timeAtLastCheck = 0; - m_timeExecuting = 0; -} - -bool TimeoutChecker::didTimeOut(ExecState* exec) -{ - unsigned currentTime = getCPUTime(); - - if (!m_timeAtLastCheck) { - // Suspicious amount of looping in a script -- start timing it - m_timeAtLastCheck = currentTime; - return false; - } - - unsigned timeDiff = currentTime - m_timeAtLastCheck; - - if (timeDiff == 0) - timeDiff = 1; - - m_timeExecuting += timeDiff; - m_timeAtLastCheck = currentTime; - - // Adjust the tick threshold so we get the next checkTimeout call in the - // interval specified in intervalBetweenChecks. - m_ticksUntilNextCheck = static_cast<unsigned>((static_cast<float>(intervalBetweenChecks) / timeDiff) * m_ticksUntilNextCheck); - // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the - // preferred script check time interval. - if (m_ticksUntilNextCheck == 0) - m_ticksUntilNextCheck = ticksUntilFirstCheck; - - if (m_timeoutInterval && m_timeExecuting > m_timeoutInterval) { - if (exec->dynamicGlobalObject()->globalObjectMethodTable()->shouldInterruptScript(exec->dynamicGlobalObject())) - return true; - - reset(); - } - - return false; -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/TimeoutChecker.h b/Source/JavaScriptCore/runtime/TimeoutChecker.h deleted file mode 100644 index 89d6158cc..000000000 --- a/Source/JavaScriptCore/runtime/TimeoutChecker.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2008 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 TimeoutChecker_h -#define TimeoutChecker_h - -#include <wtf/Assertions.h> - -namespace JSC { - - class ExecState; - - class TimeoutChecker { - public: - TimeoutChecker(); - - void setTimeoutInterval(unsigned timeoutInterval) { m_timeoutInterval = timeoutInterval; } - unsigned timeoutInterval() const { return m_timeoutInterval; } - - unsigned ticksUntilNextCheck() { return m_ticksUntilNextCheck; } - - void start() - { - if (!m_startCount) - reset(); - ++m_startCount; - } - - void stop() - { - ASSERT(m_startCount); - --m_startCount; - } - - JS_EXPORT_PRIVATE void reset(); - - JS_EXPORT_PRIVATE bool didTimeOut(ExecState*); - - private: - unsigned m_timeoutInterval; - unsigned m_timeAtLastCheck; - unsigned m_timeExecuting; - unsigned m_startCount; - unsigned m_ticksUntilNextCheck; - }; - -} // namespace JSC - -#endif // TimeoutChecker_h diff --git a/Source/JavaScriptCore/runtime/Uint16WithFraction.h b/Source/JavaScriptCore/runtime/Uint16WithFraction.h index 0e5c5f91c..9a30100eb 100644 --- a/Source/JavaScriptCore/runtime/Uint16WithFraction.h +++ b/Source/JavaScriptCore/runtime/Uint16WithFraction.h @@ -41,7 +41,7 @@ class Uint16WithFraction { public: explicit Uint16WithFraction(double number, uint16_t divideByExponent = 0) { - ASSERT(number && isfinite(number) && !signbit(number)); + ASSERT(number && std::isfinite(number) && !std::signbit(number)); // Check for values out of uint16_t range. if (number >= oneGreaterThanMaxUInt16) { diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/Source/JavaScriptCore/runtime/VM.cpp index 74429c7a7..3ca134ba2 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/Source/JavaScriptCore/runtime/VM.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2011, 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,11 +27,12 @@ */ #include "config.h" -#include "JSGlobalData.h" +#include "VM.h" #include "ArgList.h" #include "CodeCache.h" #include "CommonIdentifiers.h" +#include "DFGLongLivedState.h" #include "DebuggerActivation.h" #include "FunctionConstructor.h" #include "GCActivityCallback.h" @@ -43,7 +44,6 @@ #include "JSActivation.h" #include "JSAPIValueWrapper.h" #include "JSArray.h" -#include "JSClassRef.h" #include "JSFunction.h" #include "JSLock.h" #include "JSNameScope.h" @@ -56,10 +56,13 @@ #include "ParserArena.h" #include "RegExpCache.h" #include "RegExpObject.h" +#include "SourceProviderCache.h" #include "StrictEvalActivation.h" #include "StrongInlines.h" #include "UnlinkedCodeBlock.h" +#include <wtf/ProcessID.h> #include <wtf/RetainPtr.h> +#include <wtf/StringPrintStream.h> #include <wtf/Threading.h> #include <wtf/WTFThreadData.h> @@ -91,12 +94,10 @@ extern const HashTable mathTable; extern const HashTable numberConstructorTable; extern const HashTable numberPrototypeTable; JS_EXPORTDATA extern const HashTable objectConstructorTable; -extern const HashTable objectPrototypeTable; extern const HashTable privateNamePrototypeTable; extern const HashTable regExpTable; extern const HashTable regExpConstructorTable; extern const HashTable regExpPrototypeTable; -extern const HashTable stringTable; extern const HashTable stringConstructorTable; // Note: Platform.h will enforce that ENABLE(ASSEMBLER) is true if either @@ -113,12 +114,12 @@ static bool enableAssembler(ExecutableAllocator& executableAllocator) #if COMPILER(GCC) && !COMPILER(CLANG) // FIXME: remove this once the EWS have been upgraded to LLVM. // Work around a bug of GCC with strict-aliasing. - RetainPtr<CFStringRef> canUseJITKeyRetain(AdoptCF, CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman)); + RetainPtr<CFStringRef> canUseJITKeyRetain = adoptCF(CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman)); CFStringRef canUseJITKey = canUseJITKeyRetain.get(); #else CFStringRef canUseJITKey = CFSTR("JavaScriptCoreUseJIT"); #endif // COMPILER(GCC) && !COMPILER(CLANG) - RetainPtr<CFBooleanRef> canUseJIT(AdoptCF, (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication)); + RetainPtr<CFTypeRef> canUseJIT = adoptCF(CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication)); if (canUseJIT) return kCFBooleanTrue == canUseJIT.get(); #endif @@ -132,13 +133,13 @@ static bool enableAssembler(ExecutableAllocator& executableAllocator) } #endif // ENABLE(!ASSEMBLER) -JSGlobalData::JSGlobalData(GlobalDataType globalDataType, HeapType heapType) - : +VM::VM(VMType vmType, HeapType heapType) + : m_apiLock(adoptRef(new JSLock(this))) #if ENABLE(ASSEMBLER) - executableAllocator(*this), + , executableAllocator(*this) #endif - heap(this, heapType) - , globalDataType(globalDataType) + , heap(this, heapType) + , vmType(vmType) , clientData(0) , topCallFrame(CallFrame::noCaller()) , arrayConstructorTable(fastNew<HashTable>(JSC::arrayConstructorTable)) @@ -153,14 +154,12 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, HeapType heapType) , numberConstructorTable(fastNew<HashTable>(JSC::numberConstructorTable)) , numberPrototypeTable(fastNew<HashTable>(JSC::numberPrototypeTable)) , objectConstructorTable(fastNew<HashTable>(JSC::objectConstructorTable)) - , objectPrototypeTable(fastNew<HashTable>(JSC::objectPrototypeTable)) , privateNamePrototypeTable(fastNew<HashTable>(JSC::privateNamePrototypeTable)) , regExpTable(fastNew<HashTable>(JSC::regExpTable)) , regExpConstructorTable(fastNew<HashTable>(JSC::regExpConstructorTable)) , regExpPrototypeTable(fastNew<HashTable>(JSC::regExpPrototypeTable)) - , stringTable(fastNew<HashTable>(JSC::stringTable)) , stringConstructorTable(fastNew<HashTable>(JSC::stringConstructorTable)) - , identifierTable(globalDataType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable()) + , identifierTable(vmType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable()) , propertyNames(new CommonIdentifiers(this)) , emptyList(new MarkedArgumentBuffer) , parserArena(adoptPtr(new ParserArena)) @@ -172,7 +171,6 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, HeapType heapType) , sizeOfLastScratchBuffer(0) #endif , dynamicGlobalObject(0) - , cachedUTCOffset(QNaN) , m_enabledProfiler(0) , m_regExpCache(new RegExpCache(this)) #if ENABLE(REGEXP_TRACING) @@ -181,10 +179,7 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, HeapType heapType) #ifndef NDEBUG , exclusiveThread(0) #endif -#if CPU(X86) && ENABLE(JIT) - , m_timeoutCount(512) -#endif - , m_newStringsSinceLastHashConst(0) + , m_newStringsSinceLastHashCons(0) #if ENABLE(ASSEMBLER) , m_canUseAssembler(enableAssembler(executableAllocator)) #endif @@ -198,7 +193,7 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, HeapType heapType) , m_initializingObjectClass(0) #endif , m_inDefineOwnProperty(false) - , m_codeCache(CodeCache::create()) + , m_codeCache(CodeCache::create(CodeCache::GlobalCodeCache)) { interpreter = new Interpreter(*this); @@ -206,8 +201,8 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, HeapType heapType) JSLockHolder lock(this); IdentifierTable* existingEntryIdentifierTable = wtfThreadData().setCurrentIdentifierTable(identifierTable); structureStructure.set(*this, Structure::createStructure(*this)); + structureRareDataStructure.set(*this, StructureRareData::createStructure(*this, 0, jsNull())); debuggerActivationStructure.set(*this, DebuggerActivation::createStructure(*this, 0, jsNull())); - interruptedExecutionErrorStructure.set(*this, InterruptedExecutionError::createStructure(*this, 0, jsNull())); terminatedExecutionErrorStructure.set(*this, TerminatedExecutionError::createStructure(*this, 0, jsNull())); stringStructure.set(*this, JSString::createStructure(*this, 0, jsNull())); notAnObjectStructure.set(*this, JSNotAnObject::createStructure(*this, 0, jsNull())); @@ -229,11 +224,14 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, HeapType heapType) unlinkedProgramCodeBlockStructure.set(*this, UnlinkedProgramCodeBlock::createStructure(*this, 0, jsNull())); unlinkedEvalCodeBlockStructure.set(*this, UnlinkedEvalCodeBlock::createStructure(*this, 0, jsNull())); unlinkedFunctionCodeBlockStructure.set(*this, UnlinkedFunctionCodeBlock::createStructure(*this, 0, jsNull())); + propertyTableStructure.set(*this, PropertyTable::createStructure(*this, 0, jsNull())); + smallStrings.initializeCommonStrings(*this); wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable); #if ENABLE(JIT) - jitStubs = adoptPtr(new JITThunks(this)); + jitStubs = adoptPtr(new JITThunks()); + performPlatformSpecificJITAssertions(this); #endif interpreter->initialize(this->canUseJIT()); @@ -243,14 +241,36 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, HeapType heapType) #endif heap.notifyIsSafeToCollect(); - + LLInt::Data::performAssertions(*this); + + if (Options::enableProfiler()) { + m_perBytecodeProfiler = adoptPtr(new Profiler::Database(*this)); + + StringPrintStream pathOut; +#if !OS(WINCE) + const char* profilerPath = getenv("JSC_PROFILER_PATH"); + if (profilerPath) + pathOut.print(profilerPath, "/"); +#endif + pathOut.print("JSCProfile-", getCurrentProcessID(), "-", m_perBytecodeProfiler->databaseID(), ".json"); + m_perBytecodeProfiler->registerToSaveAtExit(pathOut.toCString().data()); + } + +#if ENABLE(DFG_JIT) + if (canUseJIT()) + m_dfgState = adoptPtr(new DFG::LongLivedState()); +#endif } -JSGlobalData::~JSGlobalData() +VM::~VM() { - ASSERT(!m_apiLock.currentThreadIsHoldingLock()); - heap.didStartVMShutdown(); + // Clear this first to ensure that nobody tries to remove themselves from it. + m_perBytecodeProfiler.clear(); + + ASSERT(m_apiLock->currentThreadIsHoldingLock()); + m_apiLock->willDestroyVM(this); + heap.lastChanceToFinalize(); delete interpreter; #ifndef NDEBUG @@ -269,12 +289,10 @@ JSGlobalData::~JSGlobalData() numberConstructorTable->deleteTable(); numberPrototypeTable->deleteTable(); objectConstructorTable->deleteTable(); - objectPrototypeTable->deleteTable(); privateNamePrototypeTable->deleteTable(); regExpTable->deleteTable(); regExpConstructorTable->deleteTable(); regExpPrototypeTable->deleteTable(); - stringTable->deleteTable(); stringConstructorTable->deleteTable(); fastDelete(const_cast<HashTable*>(arrayConstructorTable)); @@ -289,20 +307,16 @@ JSGlobalData::~JSGlobalData() fastDelete(const_cast<HashTable*>(numberConstructorTable)); fastDelete(const_cast<HashTable*>(numberPrototypeTable)); fastDelete(const_cast<HashTable*>(objectConstructorTable)); - fastDelete(const_cast<HashTable*>(objectPrototypeTable)); fastDelete(const_cast<HashTable*>(privateNamePrototypeTable)); fastDelete(const_cast<HashTable*>(regExpTable)); fastDelete(const_cast<HashTable*>(regExpConstructorTable)); fastDelete(const_cast<HashTable*>(regExpPrototypeTable)); - fastDelete(const_cast<HashTable*>(stringTable)); fastDelete(const_cast<HashTable*>(stringConstructorTable)); - opaqueJSClassData.clear(); - delete emptyList; delete propertyNames; - if (globalDataType != Default) + if (vmType != Default) deleteIdentifierTable(identifierTable); delete clientData; @@ -317,40 +331,40 @@ JSGlobalData::~JSGlobalData() #endif } -PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(HeapType heapType) +PassRefPtr<VM> VM::createContextGroup(HeapType heapType) { - return adoptRef(new JSGlobalData(APIContextGroup, heapType)); + return adoptRef(new VM(APIContextGroup, heapType)); } -PassRefPtr<JSGlobalData> JSGlobalData::create(HeapType heapType) +PassRefPtr<VM> VM::create(HeapType heapType) { - return adoptRef(new JSGlobalData(Default, heapType)); + return adoptRef(new VM(Default, heapType)); } -PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(HeapType heapType) +PassRefPtr<VM> VM::createLeaked(HeapType heapType) { return create(heapType); } -bool JSGlobalData::sharedInstanceExists() +bool VM::sharedInstanceExists() { return sharedInstanceInternal(); } -JSGlobalData& JSGlobalData::sharedInstance() +VM& VM::sharedInstance() { GlobalJSLock globalLock; - JSGlobalData*& instance = sharedInstanceInternal(); + VM*& instance = sharedInstanceInternal(); if (!instance) { - instance = adoptRef(new JSGlobalData(APIShared, SmallHeap)).leakRef(); + instance = adoptRef(new VM(APIShared, SmallHeap)).leakRef(); instance->makeUsableFromMultipleThreads(); } return *instance; } -JSGlobalData*& JSGlobalData::sharedInstanceInternal() +VM*& VM::sharedInstanceInternal() { - static JSGlobalData* sharedInstance; + static VM* sharedInstance; return sharedInstance; } @@ -380,52 +394,60 @@ static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic) return expThunkGenerator; case LogIntrinsic: return logThunkGenerator; + case IMulIntrinsic: + return imulThunkGenerator; default: return 0; } } -NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, NativeFunction constructor) +NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor) { return jitStubs->hostFunctionStub(this, function, constructor); } -NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, Intrinsic intrinsic) +NativeExecutable* VM::getHostFunction(NativeFunction function, Intrinsic intrinsic) { ASSERT(canUseJIT()); return jitStubs->hostFunctionStub(this, function, intrinsic != NoIntrinsic ? thunkGeneratorForIntrinsic(intrinsic) : 0, intrinsic); } #else // !ENABLE(JIT) -NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, NativeFunction constructor) +NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor) { return NativeExecutable::create(*this, function, constructor); } #endif // !ENABLE(JIT) -JSGlobalData::ClientData::~ClientData() +VM::ClientData::~ClientData() { } -void JSGlobalData::resetDateCache() +void VM::resetDateCache() { - cachedUTCOffset = QNaN; - dstOffsetCache.reset(); + localTimeOffsetCache.reset(); cachedDateString = String(); cachedDateStringValue = QNaN; dateInstanceCache.reset(); } -void JSGlobalData::startSampling() +void VM::startSampling() { interpreter->startSampling(); } -void JSGlobalData::stopSampling() +void VM::stopSampling() { interpreter->stopSampling(); } -void JSGlobalData::dumpSampleData(ExecState* exec) +void VM::discardAllCode() +{ + m_codeCache->clear(); + heap.deleteAllCompiledCode(); + heap.reportAbandonedObjectGraph(); +} + +void VM::dumpSampleData(ExecState* exec) { interpreter->dumpSampleData(exec); #if ENABLE(ASSEMBLER) @@ -433,6 +455,19 @@ void JSGlobalData::dumpSampleData(ExecState* exec) #endif } +SourceProviderCache* VM::addSourceProviderCache(SourceProvider* sourceProvider) +{ + SourceProviderCacheMap::AddResult addResult = sourceProviderCacheMap.add(sourceProvider, 0); + if (addResult.isNewEntry) + addResult.iterator->value = adoptRef(new SourceProviderCache); + return addResult.iterator->value.get(); +} + +void VM::clearSourceProviderCaches() +{ + sourceProviderCacheMap.clear(); +} + struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor { HashSet<FunctionExecutable*> currentlyExecutingFunctions; void operator()(JSCell* cell) @@ -446,11 +481,12 @@ struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor { } }; -void JSGlobalData::releaseExecutableMemory() +void VM::releaseExecutableMemory() { if (dynamicGlobalObject) { StackPreservingRecompiler recompiler; HashSet<JSCell*> roots; + heap.canonicalizeCellLivenessData(); heap.getConservativeRegisterRoots(roots); HashSet<JSCell*>::iterator end = roots.end(); for (HashSet<JSCell*>::iterator ptr = roots.begin(); ptr != end; ++ptr) { @@ -476,14 +512,19 @@ void JSGlobalData::releaseExecutableMemory() m_regExpCache->invalidateCode(); heap.collectAllGarbage(); } + +void VM::clearExceptionStack() +{ + m_exceptionStack = RefCountedArray<StackFrame>(); +} -void releaseExecutableMemory(JSGlobalData& globalData) +void releaseExecutableMemory(VM& vm) { - globalData.releaseExecutableMemory(); + vm.releaseExecutableMemory(); } #if ENABLE(DFG_JIT) -void JSGlobalData::gatherConservativeRoots(ConservativeRoots& conservativeRoots) +void VM::gatherConservativeRoots(ConservativeRoots& conservativeRoots) { for (size_t i = 0; i < scratchBuffers.size(); i++) { ScratchBuffer* scratchBuffer = scratchBuffers[i]; @@ -496,12 +537,12 @@ void JSGlobalData::gatherConservativeRoots(ConservativeRoots& conservativeRoots) #endif #if ENABLE(REGEXP_TRACING) -void JSGlobalData::addRegExpToTrace(RegExp* regExp) +void VM::addRegExpToTrace(RegExp* regExp) { m_rtTraceList->add(regExp); } -void JSGlobalData::dumpRegExpTrace() +void VM::dumpRegExpTrace() { // The first RegExp object is ignored. It is create by the RegExpPrototype ctor and not used. RTTraceList::iterator iter = ++m_rtTraceList->begin(); @@ -523,7 +564,7 @@ void JSGlobalData::dumpRegExpTrace() m_rtTraceList->clear(); } #else -void JSGlobalData::dumpRegExpTrace() +void VM::dumpRegExpTrace() { } #endif diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.h b/Source/JavaScriptCore/runtime/VM.h index 01e6059da..dcd525107 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.h +++ b/Source/JavaScriptCore/runtime/VM.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009, 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,29 +26,35 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSGlobalData_h -#define JSGlobalData_h +#ifndef VM_h +#define VM_h #include "CachedTranscendentalFunction.h" #include "DateInstanceCache.h" #include "ExecutableAllocator.h" #include "Heap.h" #include "Intrinsic.h" -#include "JITStubs.h" +#include "JITThunks.h" +#include "JITThunks.h" +#include "JSCJSValue.h" #include "JSLock.h" -#include "JSValue.h" #include "LLIntData.h" +#include "MacroAssemblerCodeRef.h" #include "NumericStrings.h" +#include "ProfilerDatabase.h" #include "PrivateName.h" +#include "PrototypeMap.h" #include "SmallStrings.h" #include "Strong.h" -#include "Terminator.h" -#include "TimeoutChecker.h" +#include "ThunkGenerators.h" #include "TypedArrayDescriptor.h" +#include "Watchdog.h" #include "WeakRandom.h" #include <wtf/BumpPointerAllocator.h> +#include <wtf/DateMath.h> #include <wtf/Forward.h> #include <wtf/HashMap.h> +#include <wtf/RefCountedArray.h> #include <wtf/SimpleStats.h> #include <wtf/ThreadSafeRefCounted.h> #include <wtf/ThreadSpecific.h> @@ -57,14 +63,12 @@ #include <wtf/ListHashSet.h> #endif -struct OpaqueJSClass; -struct OpaqueJSClassContextData; - namespace JSC { class CodeBlock; class CodeCache; class CommonIdentifiers; + class ExecState; class HandleStack; class IdentifierTable; class Interpreter; @@ -72,10 +76,13 @@ namespace JSC { class JSObject; class Keywords; class LLIntOffsetsExtractor; + class LegacyProfiler; class NativeExecutable; class ParserArena; - class Profiler; class RegExpCache; + class SourceProvider; + class SourceProviderCache; + struct StackFrame; class Stringifier; class Structure; #if ENABLE(REGEXP_TRACING) @@ -86,24 +93,32 @@ namespace JSC { class UnlinkedFunctionExecutable; class UnlinkedProgramCodeBlock; +#if ENABLE(DFG_JIT) + namespace DFG { + class LongLivedState; + } +#endif // ENABLE(DFG_JIT) + struct HashTable; struct Instruction; - struct DSTOffsetCache { - DSTOffsetCache() + struct LocalTimeOffsetCache { + LocalTimeOffsetCache() + : start(0.0) + , end(-1.0) + , increment(0.0) { - reset(); } void reset() { - offset = 0.0; + offset = LocalTimeOffset(); start = 0.0; end = -1.0; increment = 0.0; } - double offset; + LocalTimeOffset offset; double start; double end; double increment; @@ -118,8 +133,8 @@ namespace JSC { #endif struct ScratchBuffer { ScratchBuffer() - : m_activeLength(0) { + u.m_activeLength = 0; } static ScratchBuffer* create(size_t size) @@ -130,12 +145,15 @@ namespace JSC { } static size_t allocationSize(size_t bufferSize) { return sizeof(ScratchBuffer) + bufferSize; } - void setActiveLength(size_t activeLength) { m_activeLength = activeLength; } - size_t activeLength() const { return m_activeLength; }; - size_t* activeLengthPtr() { return &m_activeLength; }; + void setActiveLength(size_t activeLength) { u.m_activeLength = activeLength; } + size_t activeLength() const { return u.m_activeLength; }; + size_t* activeLengthPtr() { return &u.m_activeLength; }; void* dataBuffer() { return m_buffer; } - size_t m_activeLength; + union { + size_t m_activeLength; + double pad; // Make sure m_buffer is double aligned. + } u; #if CPU(MIPS) && (defined WTF_MIPS_ARCH_REV && WTF_MIPS_ARCH_REV == 2) void* m_buffer[0] __attribute__((aligned(8))); #else @@ -147,36 +165,36 @@ namespace JSC { #endif #endif - class JSGlobalData : public ThreadSafeRefCounted<JSGlobalData> { + class VM : public ThreadSafeRefCounted<VM> { public: - // WebCore has a one-to-one mapping of threads to JSGlobalDatas; + // WebCore has a one-to-one mapping of threads to VMs; // either create() or createLeaked() should only be called once - // on a thread, this is the 'default' JSGlobalData (it uses the + // on a thread, this is the 'default' VM (it uses the // thread's default string uniquing table from wtfThreadData). // API contexts created using the new context group aware interface // create APIContextGroup objects which require less locking of JSC - // than the old singleton APIShared JSGlobalData created for use by + // than the old singleton APIShared VM created for use by // the original API. - enum GlobalDataType { Default, APIContextGroup, APIShared }; + enum VMType { Default, APIContextGroup, APIShared }; struct ClientData { JS_EXPORT_PRIVATE virtual ~ClientData() = 0; }; - bool isSharedInstance() { return globalDataType == APIShared; } - bool usingAPI() { return globalDataType != Default; } + bool isSharedInstance() { return vmType == APIShared; } + bool usingAPI() { return vmType != Default; } static bool sharedInstanceExists(); - JS_EXPORT_PRIVATE static JSGlobalData& sharedInstance(); + JS_EXPORT_PRIVATE static VM& sharedInstance(); - JS_EXPORT_PRIVATE static PassRefPtr<JSGlobalData> create(HeapType = SmallHeap); - JS_EXPORT_PRIVATE static PassRefPtr<JSGlobalData> createLeaked(HeapType = SmallHeap); - static PassRefPtr<JSGlobalData> createContextGroup(HeapType = SmallHeap); - JS_EXPORT_PRIVATE ~JSGlobalData(); + JS_EXPORT_PRIVATE static PassRefPtr<VM> create(HeapType = SmallHeap); + JS_EXPORT_PRIVATE static PassRefPtr<VM> createLeaked(HeapType = SmallHeap); + static PassRefPtr<VM> createContextGroup(HeapType = SmallHeap); + JS_EXPORT_PRIVATE ~VM(); void makeUsableFromMultipleThreads() { heap.machineThreads().makeUsableFromMultipleThreads(); } private: - JSLock m_apiLock; + RefPtr<JSLock> m_apiLock; public: #if ENABLE(ASSEMBLER) @@ -188,10 +206,15 @@ namespace JSC { // The heap should be just after executableAllocator and before other members to ensure that it's // destructed after all the objects that reference it. Heap heap; + +#if ENABLE(DFG_JIT) + OwnPtr<DFG::LongLivedState> m_dfgState; +#endif // ENABLE(DFG_JIT) - GlobalDataType globalDataType; + VMType vmType; ClientData* clientData; - CallFrame* topCallFrame; + ExecState* topCallFrame; + Watchdog watchdog; const HashTable* arrayConstructorTable; const HashTable* arrayPrototypeTable; @@ -205,17 +228,15 @@ namespace JSC { const HashTable* numberConstructorTable; const HashTable* numberPrototypeTable; const HashTable* objectConstructorTable; - const HashTable* objectPrototypeTable; const HashTable* privateNamePrototypeTable; const HashTable* regExpTable; const HashTable* regExpConstructorTable; const HashTable* regExpPrototypeTable; - const HashTable* stringTable; const HashTable* stringConstructorTable; Strong<Structure> structureStructure; + Strong<Structure> structureRareDataStructure; Strong<Structure> debuggerActivationStructure; - Strong<Structure> interruptedExecutionErrorStructure; Strong<Structure> terminatedExecutionErrorStructure; Strong<Structure> stringStructure; Strong<Structure> notAnObjectStructure; @@ -237,6 +258,7 @@ namespace JSC { Strong<Structure> unlinkedProgramCodeBlockStructure; Strong<Structure> unlinkedEvalCodeBlockStructure; Strong<Structure> unlinkedFunctionCodeBlockStructure; + Strong<Structure> propertyTableStructure; IdentifierTable* identifierTable; CommonIdentifiers* propertyNames; @@ -267,7 +289,7 @@ namespace JSC { return m_inDefineOwnProperty; } - Profiler* enabledProfiler() + LegacyProfiler* enabledProfiler() { return m_enabledProfiler; } @@ -286,9 +308,14 @@ namespace JSC { bool canUseRegExpJIT() { return false; } // interpreter only #endif - PrivateName m_inheritorIDKey; + SourceProviderCache* addSourceProviderCache(SourceProvider*); + void clearSourceProviderCaches(); + + PrototypeMap prototypeMap; OwnPtr<ParserArena> parserArena; + typedef HashMap<RefPtr<SourceProvider>, RefPtr<SourceProviderCache> > SourceProviderCacheMap; + SourceProviderCacheMap sourceProviderCacheMap; OwnPtr<Keywords> keywords; Interpreter* interpreter; #if ENABLE(JIT) @@ -301,17 +328,16 @@ namespace JSC { #endif NativeExecutable* getHostFunction(NativeFunction, NativeFunction constructor); - TimeoutChecker timeoutChecker; - Terminator terminator; - JSValue exception; + JS_EXPORT_PRIVATE void clearExceptionStack(); + RefCountedArray<StackFrame>& exceptionStack() { return m_exceptionStack; } const ClassInfo* const jsArrayClassInfo; const ClassInfo* const jsFinalObjectClassInfo; ReturnAddressPtr exceptionLocation; JSValue hostCallReturnValue; - CallFrame* callFrameForThrow; + ExecState* callFrameForThrow; void* targetMachinePCForThrow; Instruction* targetInterpreterPCForThrow; #if ENABLE(DFG_JIT) @@ -343,19 +369,17 @@ namespace JSC { void gatherConservativeRoots(ConservativeRoots&); #endif - HashMap<OpaqueJSClass*, OwnPtr<OpaqueJSClassContextData> > opaqueJSClassData; - JSGlobalObject* dynamicGlobalObject; HashSet<JSObject*> stringRecursionCheckVisitedObjects; - double cachedUTCOffset; - DSTOffsetCache dstOffsetCache; + LocalTimeOffsetCache localTimeOffsetCache; String cachedDateString; double cachedDateStringValue; - Profiler* m_enabledProfiler; + LegacyProfiler* m_enabledProfiler; + OwnPtr<Profiler::Database> m_perBytecodeProfiler; RegExpCache* m_regExpCache; BumpPointerAllocator m_regExpAllocator; @@ -368,7 +392,7 @@ namespace JSC { ThreadIdentifier exclusiveThread; #endif - CachedTranscendentalFunction<sin> cachedSin; + CachedTranscendentalFunction<std::sin> cachedSin; JS_EXPORT_PRIVATE void resetDateCache(); @@ -389,16 +413,12 @@ namespace JSC { void setInitializingObjectClass(const ClassInfo*); #endif -#if CPU(X86) && ENABLE(JIT) - unsigned m_timeoutCount; -#endif - - unsigned m_newStringsSinceLastHashConst; + unsigned m_newStringsSinceLastHashCons; - static const unsigned s_minNumberOfNewStringsToHashConst = 100; + static const unsigned s_minNumberOfNewStringsToHashCons = 100; - bool haveEnoughNewStringsToHashConst() { return m_newStringsSinceLastHashConst > s_minNumberOfNewStringsToHashConst; } - void resetNewStringsSinceLastHashConst() { m_newStringsSinceLastHashConst = 0; } + bool haveEnoughNewStringsToHashCons() { return m_newStringsSinceLastHashCons > s_minNumberOfNewStringsToHashCons; } + void resetNewStringsSinceLastHashCons() { m_newStringsSinceLastHashCons = 0; } #define registerTypedArrayFunction(type, capitalizedType) \ void registerTypedArrayDescriptor(const capitalizedType##Array*, const TypedArrayDescriptor& descriptor) \ @@ -449,14 +469,16 @@ namespace JSC { } } - JSLock& apiLock() { return m_apiLock; } + JSLock& apiLock() { return *m_apiLock; } CodeCache* codeCache() { return m_codeCache.get(); } + JS_EXPORT_PRIVATE void discardAllCode(); + private: friend class LLIntOffsetsExtractor; - JSGlobalData(GlobalDataType, HeapType); - static JSGlobalData*& sharedInstanceInternal(); + VM(VMType, HeapType); + static VM*& sharedInstanceInternal(); void createNativeThunk(); #if ENABLE(ASSEMBLER) bool m_canUseAssembler; @@ -471,7 +493,8 @@ namespace JSC { const ClassInfo* m_initializingObjectClass; #endif bool m_inDefineOwnProperty; - OwnPtr<CodeCache> m_codeCache; + RefPtr<CodeCache> m_codeCache; + RefCountedArray<StackFrame> m_exceptionStack; TypedArrayDescriptor m_int8ArrayDescriptor; TypedArrayDescriptor m_int16ArrayDescriptor; @@ -485,12 +508,12 @@ namespace JSC { }; #if ENABLE(GC_VALIDATION) - inline bool JSGlobalData::isInitializingObject() const + inline bool VM::isInitializingObject() const { return !!m_initializingObjectClass; } - inline void JSGlobalData::setInitializingObjectClass(const ClassInfo* initializingObjectClass) + inline void VM::setInitializingObjectClass(const ClassInfo* initializingObjectClass) { m_initializingObjectClass = initializingObjectClass; } @@ -498,9 +521,9 @@ namespace JSC { inline Heap* WeakSet::heap() const { - return &m_globalData->heap; + return &m_vm->heap; } } // namespace JSC -#endif // JSGlobalData_h +#endif // VM_h diff --git a/Source/JavaScriptCore/runtime/VMStackBounds.h b/Source/JavaScriptCore/runtime/VMStackBounds.h new file mode 100644 index 000000000..76a3ebd30 --- /dev/null +++ b/Source/JavaScriptCore/runtime/VMStackBounds.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2013 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 VMStackBounds_h +#define VMStackBounds_h + +#include "VM.h" +#include <wtf/StackBounds.h> + +namespace JSC { + +class VMStackBounds { +public: + VMStackBounds(VM& vm, const StackBounds& bounds) + : m_vm(vm) + , m_bounds(bounds) + { + } + + bool isSafeToRecurse() const { return m_bounds.isSafeToRecurse(requiredCapacity()); } + +private: + inline size_t requiredCapacity() const + { + Interpreter* interpreter = m_vm.interpreter; + + // We have two separate stack limits, one for regular JS execution, and one + // for when we're handling errors. We need the error stack to be smaller + // otherwise there would obviously not be any stack left to execute JS in when + // there's a stack overflow. + // + // These sizes were derived from the stack usage of a number of sites when + // layout occurs when we've already consumed most of the C stack. + const size_t requiredStack = 128 * KB; + const size_t errorModeRequiredStack = 64 * KB; + + size_t requiredCapacity = interpreter->isInErrorHandlingMode() ? errorModeRequiredStack : requiredStack; + RELEASE_ASSERT(m_bounds.size() >= requiredCapacity); + return requiredCapacity; + } + + VM& m_vm; + const StackBounds& m_bounds; +}; + +} // namespace JSC + +#endif // VMStackBounds_h + diff --git a/Source/JavaScriptCore/runtime/Watchdog.cpp b/Source/JavaScriptCore/runtime/Watchdog.cpp new file mode 100644 index 000000000..573260b16 --- /dev/null +++ b/Source/JavaScriptCore/runtime/Watchdog.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2013 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 "Watchdog.h" + +#include "CallFrame.h" +#include <wtf/CurrentTime.h> +#include <wtf/MathExtras.h> + +namespace JSC { + +#define NO_LIMIT std::numeric_limits<double>::infinity() + +Watchdog::Watchdog() + : m_timerDidFire(false) + , m_didFire(false) + , m_limit(NO_LIMIT) + , m_startTime(0) + , m_elapsedTime(0) + , m_reentryCount(0) + , m_isStopped(true) + , m_callback(0) + , m_callbackData1(0) + , m_callbackData2(0) +{ + initTimer(); +} + +Watchdog::~Watchdog() +{ + ASSERT(!isArmed()); + stopCountdown(); + destroyTimer(); +} + +void Watchdog::setTimeLimit(VM& vm, double limit, + ShouldTerminateCallback callback, void* data1, void* data2) +{ + bool wasEnabled = isEnabled(); + + if (!m_isStopped) + stopCountdown(); + + m_didFire = false; // Reset the watchdog. + + m_limit = limit; + m_callback = callback; + m_callbackData1 = data1; + m_callbackData2 = data2; + + // If this is the first time that timeout is being enabled, then any + // previously JIT compiled code will not have the needed polling checks. + // Hence, we need to flush all the pre-existing compiled code. + // + // However, if the timeout is already enabled, and we're just changing the + // timeout value, then any existing JITted code will have the appropriate + // polling checks. Hence, there is no need to re-do this flushing. + if (!wasEnabled) { + // And if we've previously compiled any functions, we need to revert + // them because they don't have the needed polling checks yet. + vm.releaseExecutableMemory(); + } + + startCountdownIfNeeded(); +} + +bool Watchdog::didFire(ExecState* exec) +{ + if (m_didFire) + return true; + + if (!m_timerDidFire) + return false; + m_timerDidFire = false; + stopCountdown(); + + double currentTime = currentCPUTime(); + double deltaTime = currentTime - m_startTime; + double totalElapsedTime = m_elapsedTime + deltaTime; + if (totalElapsedTime > m_limit) { + // Case 1: the allowed CPU time has elapsed. + + // If m_callback is not set, then we terminate by default. + // Else, we let m_callback decide if we should terminate or not. + bool needsTermination = !m_callback + || m_callback(exec, m_callbackData1, m_callbackData2); + if (needsTermination) { + m_didFire = true; + return true; + } + + // The m_callback may have set a new limit. So, we may need to restart + // the countdown. + startCountdownIfNeeded(); + + } else { + // Case 2: the allowed CPU time has NOT elapsed. + + // Tell the timer to alarm us again when it thinks we've reached the + // end of the allowed time. + double remainingTime = m_limit - totalElapsedTime; + m_elapsedTime = totalElapsedTime; + m_startTime = currentTime; + startCountdown(remainingTime); + } + + return false; +} + +bool Watchdog::isEnabled() +{ + return (m_limit != NO_LIMIT); +} + +void Watchdog::fire() +{ + m_didFire = true; +} + +void Watchdog::arm() +{ + m_reentryCount++; + if (m_reentryCount == 1) + startCountdownIfNeeded(); +} + +void Watchdog::disarm() +{ + ASSERT(m_reentryCount > 0); + if (m_reentryCount == 1) + stopCountdown(); + m_reentryCount--; +} + +void Watchdog::startCountdownIfNeeded() +{ + if (!m_isStopped) + return; // Already started. + + if (!isArmed()) + return; // Not executing JS script. No need to start. + + if (isEnabled()) { + m_elapsedTime = 0; + m_startTime = currentCPUTime(); + startCountdown(m_limit); + } +} + +void Watchdog::startCountdown(double limit) +{ + ASSERT(m_isStopped); + m_isStopped = false; + startTimer(limit); +} + +void Watchdog::stopCountdown() +{ + if (m_isStopped) + return; + stopTimer(); + m_isStopped = true; +} + +Watchdog::Scope::Scope(Watchdog& watchdog) + : m_watchdog(watchdog) +{ + m_watchdog.arm(); +} + +Watchdog::Scope::~Scope() +{ + m_watchdog.disarm(); +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Watchdog.h b/Source/JavaScriptCore/runtime/Watchdog.h new file mode 100644 index 000000000..08c0ccb95 --- /dev/null +++ b/Source/JavaScriptCore/runtime/Watchdog.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2013 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 Watchdog_h +#define Watchdog_h + +#if PLATFORM(MAC) || PLATFORM(IOS) +#include <dispatch/dispatch.h> +#endif + +namespace JSC { + +class ExecState; +class VM; + +class Watchdog { +public: + class Scope; + + Watchdog(); + ~Watchdog(); + + typedef bool (*ShouldTerminateCallback)(ExecState*, void* data1, void* data2); + void setTimeLimit(VM&, double seconds, ShouldTerminateCallback = 0, void* data1 = 0, void* data2 = 0); + + // This version of didFire() will check the elapsed CPU time and call the + // callback (if needed) to determine if the watchdog should fire. + bool didFire(ExecState*); + + bool isEnabled(); + + // This version of didFire() is a more efficient version for when we want + // to know if the watchdog has fired in the past, and not whether it should + // fire right now. + JS_EXPORT_PRIVATE bool didFire() { return m_didFire; } + JS_EXPORT_PRIVATE void fire(); + + void* timerDidFireAddress() { return &m_timerDidFire; } + +private: + void arm(); + void disarm(); + void startCountdownIfNeeded(); + void startCountdown(double limit); + void stopCountdown(); + bool isArmed() { return !!m_reentryCount; } + + // Platform specific timer implementation: + void initTimer(); + void destroyTimer(); + void startTimer(double limit); + void stopTimer(); + + // m_timerDidFire (above) indicates whether the timer fired. The Watchdog + // still needs to check if the allowed CPU time has elapsed. If so, then + // the Watchdog fires and m_didFire will be set. + // NOTE: m_timerDidFire is only set by the platform specific timer + // (probably from another thread) but is only cleared in the script thread. + bool m_timerDidFire; + bool m_didFire; + + // All time units are in seconds. + double m_limit; + double m_startTime; + double m_elapsedTime; + + int m_reentryCount; + bool m_isStopped; + + ShouldTerminateCallback m_callback; + void* m_callbackData1; + void* m_callbackData2; + +#if PLATFORM(MAC) || PLATFORM(IOS) + dispatch_queue_t m_queue; + dispatch_source_t m_timer; +#endif + + friend class Watchdog::Scope; + friend class LLIntOffsetsExtractor; +}; + +class Watchdog::Scope { +public: + Scope(Watchdog&); + ~Scope(); + +private: + Watchdog& m_watchdog; +}; + +} // namespace JSC + +#endif // Watchdog_h diff --git a/Source/JavaScriptCore/runtime/WatchdogMac.cpp b/Source/JavaScriptCore/runtime/WatchdogMac.cpp new file mode 100644 index 000000000..ca474df2f --- /dev/null +++ b/Source/JavaScriptCore/runtime/WatchdogMac.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2013 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 "Watchdog.h" + +namespace JSC { + +void Watchdog::initTimer() +{ + m_queue = 0; + m_timer = 0; +} + +void Watchdog::destroyTimer() +{ + ASSERT(!m_timer); + if (m_queue) + dispatch_release(m_queue); +} + +void Watchdog::startTimer(double limit) +{ + ASSERT(!m_timer); + if (!m_queue) + m_queue = dispatch_queue_create("jsc.watchdog.queue", 0); + m_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, m_queue); + + dispatch_source_set_timer(m_timer, + dispatch_time(DISPATCH_TIME_NOW, limit * NSEC_PER_SEC), + DISPATCH_TIME_FOREVER, 0); + + dispatch_source_set_event_handler(m_timer, ^{ + m_timerDidFire = true; + }); + + dispatch_resume(m_timer); +} + +void Watchdog::stopTimer() +{ + ASSERT(m_queue); + dispatch_sync(m_queue, ^{ + dispatch_source_cancel(m_timer); + }); + dispatch_release(m_timer); + m_timer = 0; +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/WatchdogNone.cpp b/Source/JavaScriptCore/runtime/WatchdogNone.cpp new file mode 100644 index 000000000..615314bb3 --- /dev/null +++ b/Source/JavaScriptCore/runtime/WatchdogNone.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2013 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 "Watchdog.h" + +namespace JSC { + +// This is a stub for platforms that have not implemented this functionality. +// In this case, the platform timer here never fires. + +void Watchdog::initTimer() +{ +} + +void Watchdog::destroyTimer() +{ +} + +void Watchdog::startTimer(double) +{ +} + +void Watchdog::stopTimer() +{ +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/WeakGCMap.h b/Source/JavaScriptCore/runtime/WeakGCMap.h index 52e5e2946..f741fa4c4 100644 --- a/Source/JavaScriptCore/runtime/WeakGCMap.h +++ b/Source/JavaScriptCore/runtime/WeakGCMap.h @@ -26,88 +26,104 @@ #ifndef WeakGCMap_h #define WeakGCMap_h -#include "Handle.h" -#include "JSGlobalData.h" +#include <heap/Weak.h> +#include <heap/WeakInlines.h> #include <wtf/HashMap.h> namespace JSC { -// 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); - } +// A HashMap with Weak<JSCell> values, which automatically removes values once they're garbage collected. - static KeyType keyForFinalizer(void* context, typename HandleTypes<MappedType>::ExternalType) - { - return reinterpret_cast<KeyType>(context); - } -}; - -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; - WTF_MAKE_NONCOPYABLE(WeakGCMap); - - typedef HashMap<KeyType, WeakImpl*, HashArg, KeyTraitsArg> MapType; - typedef typename HandleTypes<MappedType>::ExternalType ExternalType; +template<typename KeyArg, typename RawMappedArg, typename HashArg = typename DefaultHash<KeyArg>::Hash, + typename KeyTraitsArg = HashTraits<KeyArg> > +class WeakGCMap : public HashMap<KeyArg, Weak<RawMappedArg>, HashArg, KeyTraitsArg> { + typedef Weak<RawMappedArg> MappedType; + typedef HashMap<KeyArg, MappedType, HashArg, KeyTraitsArg> Base; + typedef WeakGCMap<KeyArg, RawMappedArg, HashArg, KeyTraitsArg> Self; + typedef HashTraits<MappedType> MappedTraits; + typedef typename MappedTraits::PassInType MappedPassInType; public: + typedef typename Base::KeyType KeyType; + typedef typename Base::AddResult AddResult; + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + using Base::begin; + using Base::end; + using Base::size; + using Base::remove; + WeakGCMap() + : m_gcThreshold(minGCThreshold) { } - void clear() + AddResult set(const KeyType& key, MappedPassInType value) { - typename MapType::iterator end = m_map.end(); - for (typename MapType::iterator ptr = m_map.begin(); ptr != end; ++ptr) - WeakSet::deallocate(ptr->value); - m_map.clear(); + gcMapIfNeeded(); + return Base::set(key, value); } - ExternalType get(const KeyType& key) const + AddResult add(const KeyType& key, MappedPassInType value) { - WeakImpl* impl = m_map.get(key); - if (!impl || impl->state() != WeakImpl::Live) - return ExternalType(); - return HandleTypes<MappedType>::getFromSlot(const_cast<JSValue*>(&impl->jsValue())); + gcMapIfNeeded(); + AddResult addResult = Base::add(key, nullptr); + if (!addResult.iterator->value) { // New value or found a zombie value. + addResult.isNewEntry = true; + addResult.iterator->value = value; + } + return addResult; } - void set(JSGlobalData& globalData, const KeyType& key, ExternalType value) + iterator find(const KeyType& key) { - ASSERT_UNUSED(globalData, globalData.apiLock().currentThreadIsHoldingLock()); - typename MapType::AddResult result = m_map.add(key, 0); - if (!result.isNewEntry) - WeakSet::deallocate(result.iterator->value); - result.iterator->value = WeakSet::allocate(value, this, FinalizerCallback::finalizerContextFor(key)); + iterator it = Base::find(key); + iterator end = Base::end(); + if (it != end && !it->value) // Found a zombie value. + return end; + return it; } - void remove(const KeyType& key) + const_iterator find(const KeyType& key) const { - WeakImpl* impl = m_map.take(key); - if (!impl) - return; - WeakSet::deallocate(impl); + return const_cast<Self*>(this)->find(key); } - ~WeakGCMap() + bool contains(const KeyType& key) const { - clear(); + return find(key) != end(); } - + private: - virtual void finalize(Handle<Unknown> handle, void* context) + static const int minGCThreshold = 3; + + void gcMap() + { + Vector<KeyType, 4> zombies; + iterator end = this->end(); + for (iterator it = begin(); it != end; ++it) { + if (!it->value) + zombies.append(it->key); + } + for (size_t i = 0; i < zombies.size(); ++i) + remove(zombies[i]); + } + + void gcMapIfNeeded() { - WeakImpl* impl = m_map.take(FinalizerCallback::keyForFinalizer(context, HandleTypes<MappedType>::getFromSlot(handle.slot()))); - ASSERT(impl); - WeakSet::deallocate(impl); + if (size() < m_gcThreshold) + return; + + gcMap(); + m_gcThreshold = std::max(minGCThreshold, size() * 2 - 1); } - MapType m_map; + int m_gcThreshold; }; +template<typename KeyArg, typename RawMappedArg, typename HashArg, typename KeyTraitsArg> +const int WeakGCMap<KeyArg, RawMappedArg, HashArg, KeyTraitsArg>::minGCThreshold; + } // namespace JSC #endif // WeakGCMap_h diff --git a/Source/JavaScriptCore/runtime/WriteBarrier.h b/Source/JavaScriptCore/runtime/WriteBarrier.h index ef8c3aff8..fe07cf532 100644 --- a/Source/JavaScriptCore/runtime/WriteBarrier.h +++ b/Source/JavaScriptCore/runtime/WriteBarrier.h @@ -35,7 +35,7 @@ namespace JSC { class JSCell; -class JSGlobalData; +class VM; class JSGlobalObject; template<class T> class WriteBarrierBase; @@ -68,11 +68,11 @@ template<class T> inline void validateCell(T) // We have a separate base class with no constructors for use in Unions. template <typename T> class WriteBarrierBase { public: - void set(JSGlobalData& globalData, const JSCell* owner, T* value) + void set(VM& vm, const JSCell* owner, T* value) { ASSERT(value); validateCell(value); - setEarlyValue(globalData, owner, value); + setEarlyValue(vm, owner, value); } // This is meant to be used like operator=, but is called copyFrom instead, in @@ -82,16 +82,16 @@ public: m_cell = other.m_cell; } - void setMayBeNull(JSGlobalData& globalData, const JSCell* owner, T* value) + void setMayBeNull(VM& vm, const JSCell* owner, T* value) { if (value) validateCell(value); - setEarlyValue(globalData, owner, value); + setEarlyValue(vm, owner, value); } // Should only be used by JSCell during early initialisation // when some basic types aren't yet completely instantiated - void setEarlyValue(JSGlobalData&, const JSCell* owner, T* value) + void setEarlyValue(VM&, const JSCell* owner, T* value) { this->m_cell = reinterpret_cast<JSCell*>(value); Heap::writeBarrier(owner, this->m_cell); @@ -99,9 +99,11 @@ public: T* get() const { - if (m_cell) - validateCell(m_cell); - return reinterpret_cast<T*>(static_cast<void*>(m_cell)); + // Copy m_cell to a local to avoid multiple-read issues. (See <http://webkit.org/b/110854>) + JSCell* cell = m_cell; + if (cell) + validateCell(cell); + return reinterpret_cast<T*>(static_cast<void*>(cell)); } T* operator*() const @@ -145,7 +147,7 @@ private: template <> class WriteBarrierBase<Unknown> { public: - void set(JSGlobalData&, const JSCell* owner, JSValue value) + void set(VM&, const JSCell* owner, JSValue value) { m_value = JSValue::encode(value); Heap::writeBarrier(owner, value); @@ -195,15 +197,15 @@ public: this->setWithoutWriteBarrier(0); } - WriteBarrier(JSGlobalData& globalData, const JSCell* owner, T* value) + WriteBarrier(VM& vm, const JSCell* owner, T* value) { - this->set(globalData, owner, value); + this->set(vm, owner, value); } enum MayBeNullTag { MayBeNull }; - WriteBarrier(JSGlobalData& globalData, const JSCell* owner, T* value, MayBeNullTag) + WriteBarrier(VM& vm, const JSCell* owner, T* value, MayBeNullTag) { - this->setMayBeNull(globalData, owner, value); + this->setMayBeNull(vm, owner, value); } }; @@ -214,9 +216,9 @@ public: this->setWithoutWriteBarrier(JSValue()); } - WriteBarrier(JSGlobalData& globalData, const JSCell* owner, JSValue value) + WriteBarrier(VM& vm, const JSCell* owner, JSValue value) { - this->set(globalData, owner, value); + this->set(vm, owner, value); } }; |