diff options
Diffstat (limited to 'Source/JavaScriptCore/runtime')
438 files changed, 16150 insertions, 28432 deletions
diff --git a/Source/JavaScriptCore/runtime/ArgList.cpp b/Source/JavaScriptCore/runtime/ArgList.cpp index 5149815c2..e13104df5 100644 --- a/Source/JavaScriptCore/runtime/ArgList.cpp +++ b/Source/JavaScriptCore/runtime/ArgList.cpp @@ -24,7 +24,7 @@ #include "HeapRootVisitor.h" #include "JSCJSValue.h" #include "JSObject.h" -#include "JSCInlines.h" +#include "Operations.h" using std::min; diff --git a/Source/JavaScriptCore/runtime/Arguments.cpp b/Source/JavaScriptCore/runtime/Arguments.cpp new file mode 100644 index 000000000..8fd195cb9 --- /dev/null +++ b/Source/JavaScriptCore/runtime/Arguments.cpp @@ -0,0 +1,387 @@ +/* + * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) + * Copyright (C) 2007 Maks Orlovich + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "Arguments.h" + +#include "CallFrameInlines.h" +#include "JSActivation.h" +#include "JSArgumentsIterator.h" +#include "JSFunction.h" +#include "JSGlobalObject.h" +#include "Operations.h" + +using namespace std; + +namespace JSC { + +const ClassInfo Arguments::s_info = { "Arguments", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(Arguments) }; + +void Arguments::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + Arguments* thisObject = jsCast<Arguments*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + JSObject::visitChildren(thisObject, visitor); + + if (thisObject->m_registerArray) + visitor.appendValues(thisObject->m_registerArray.get(), thisObject->m_numArguments); + visitor.append(&thisObject->m_callee); + visitor.append(&thisObject->m_activation); +} + +static EncodedJSValue JSC_HOST_CALL argumentsFuncIterator(ExecState*); + +void Arguments::destroy(JSCell* cell) +{ + static_cast<Arguments*>(cell)->Arguments::~Arguments(); +} + +void Arguments::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t length) +{ + if (UNLIKELY(m_overrodeLength)) { + length = min(get(exec, exec->propertyNames().length).toUInt32(exec), length); + for (unsigned i = 0; i < length; i++) + callFrame->setArgument(i, get(exec, i)); + return; + } + ASSERT(length == this->length(exec)); + for (size_t i = 0; i < length; ++i) { + if (JSValue value = tryGetArgument(i)) + callFrame->setArgument(i, value); + else + callFrame->setArgument(i, get(exec, i)); + } +} + +void Arguments::fillArgList(ExecState* exec, MarkedArgumentBuffer& args) +{ + if (UNLIKELY(m_overrodeLength)) { + unsigned length = get(exec, exec->propertyNames().length).toUInt32(exec); + for (unsigned i = 0; i < length; i++) + args.append(get(exec, i)); + return; + } + uint32_t length = this->length(exec); + for (size_t i = 0; i < length; ++i) { + if (JSValue value = tryGetArgument(i)) + args.append(value); + else + args.append(get(exec, i)); + } +} + +bool Arguments::getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned i, PropertySlot& slot) +{ + Arguments* thisObject = jsCast<Arguments*>(object); + if (JSValue value = thisObject->tryGetArgument(i)) { + slot.setValue(thisObject, None, value); + return true; + } + + return JSObject::getOwnPropertySlot(thisObject, exec, Identifier::from(exec, i), slot); +} + +void Arguments::createStrictModeCallerIfNecessary(ExecState* exec) +{ + if (m_overrodeCaller) + return; + + VM& vm = exec->vm(); + m_overrodeCaller = true; + PropertyDescriptor descriptor; + descriptor.setAccessorDescriptor(globalObject()->throwTypeErrorGetterSetter(vm), DontEnum | DontDelete | Accessor); + methodTable()->defineOwnProperty(this, exec, vm.propertyNames->caller, descriptor, false); +} + +void Arguments::createStrictModeCalleeIfNecessary(ExecState* exec) +{ + if (m_overrodeCallee) + return; + + VM& vm = exec->vm(); + m_overrodeCallee = true; + PropertyDescriptor descriptor; + descriptor.setAccessorDescriptor(globalObject()->throwTypeErrorGetterSetter(vm), DontEnum | DontDelete | Accessor); + methodTable()->defineOwnProperty(this, exec, vm.propertyNames->callee, descriptor, false); +} + +bool Arguments::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) +{ + Arguments* thisObject = jsCast<Arguments*>(object); + unsigned i = propertyName.asIndex(); + if (JSValue value = thisObject->tryGetArgument(i)) { + RELEASE_ASSERT(i < PropertyName::NotAnIndex); + slot.setValue(thisObject, None, value); + return true; + } + + if (propertyName == exec->propertyNames().length && LIKELY(!thisObject->m_overrodeLength)) { + slot.setValue(thisObject, DontEnum, jsNumber(thisObject->m_numArguments)); + return true; + } + + if (propertyName == exec->propertyNames().callee && LIKELY(!thisObject->m_overrodeCallee)) { + if (!thisObject->m_isStrictMode) { + slot.setValue(thisObject, DontEnum, thisObject->m_callee.get()); + return true; + } + thisObject->createStrictModeCalleeIfNecessary(exec); + } + + if (propertyName == exec->propertyNames().caller && thisObject->m_isStrictMode) + thisObject->createStrictModeCallerIfNecessary(exec); + + if (JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot)) + return true; + if (propertyName == exec->propertyNames().iteratorPrivateName) { + VM& vm = exec->vm(); + JSGlobalObject* globalObject = exec->lexicalGlobalObject(); + thisObject->JSC_NATIVE_FUNCTION(exec->propertyNames().iteratorPrivateName, argumentsFuncIterator, DontEnum, 0); + if (JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot)) + return true; + } + return false; +} + +void Arguments::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +{ + Arguments* thisObject = jsCast<Arguments*>(object); + for (unsigned i = 0; i < thisObject->m_numArguments; ++i) { + if (!thisObject->isArgument(i)) + continue; + propertyNames.add(Identifier::from(exec, i)); + } + if (mode == IncludeDontEnumProperties) { + propertyNames.add(exec->propertyNames().callee); + propertyNames.add(exec->propertyNames().length); + } + JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode); +} + +void Arguments::putByIndex(JSCell* cell, ExecState* exec, unsigned i, JSValue value, bool shouldThrow) +{ + Arguments* thisObject = jsCast<Arguments*>(cell); + if (thisObject->trySetArgument(exec->vm(), i, value)) + return; + + PutPropertySlot slot(thisObject, shouldThrow); + JSObject::put(thisObject, exec, Identifier::from(exec, i), value, slot); +} + +void Arguments::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) +{ + Arguments* thisObject = jsCast<Arguments*>(cell); + unsigned i = propertyName.asIndex(); + if (thisObject->trySetArgument(exec->vm(), i, value)) + return; + + if (propertyName == exec->propertyNames().length && !thisObject->m_overrodeLength) { + thisObject->m_overrodeLength = true; + 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->vm(), propertyName, value, DontEnum); + return; + } + thisObject->createStrictModeCalleeIfNecessary(exec); + } + + if (propertyName == exec->propertyNames().caller && thisObject->m_isStrictMode) + thisObject->createStrictModeCallerIfNecessary(exec); + + JSObject::put(thisObject, exec, propertyName, value, slot); +} + +bool Arguments::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i) +{ + Arguments* thisObject = jsCast<Arguments*>(cell); + if (i < thisObject->m_numArguments) { + if (!Base::deletePropertyByIndex(cell, exec, i)) + return false; + if (thisObject->tryDeleteArgument(i)) + return true; + } + return JSObject::deletePropertyByIndex(thisObject, exec, i); +} + +bool Arguments::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) +{ + if (exec->vm().isInDefineOwnProperty()) + return Base::deleteProperty(cell, exec, propertyName); + + Arguments* thisObject = jsCast<Arguments*>(cell); + unsigned i = propertyName.asIndex(); + if (i < thisObject->m_numArguments) { + RELEASE_ASSERT(i < PropertyName::NotAnIndex); + if (!Base::deleteProperty(cell, exec, propertyName)) + return false; + if (thisObject->tryDeleteArgument(i)) + return true; + } + + if (propertyName == exec->propertyNames().length && !thisObject->m_overrodeLength) { + thisObject->m_overrodeLength = true; + return true; + } + + if (propertyName == exec->propertyNames().callee && !thisObject->m_overrodeCallee) { + if (!thisObject->m_isStrictMode) { + thisObject->m_overrodeCallee = true; + return true; + } + thisObject->createStrictModeCalleeIfNecessary(exec); + } + + if (propertyName == exec->propertyNames().caller && thisObject->m_isStrictMode) + thisObject->createStrictModeCallerIfNecessary(exec); + + return JSObject::deleteProperty(thisObject, exec, propertyName); +} + +bool Arguments::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow) +{ + Arguments* thisObject = jsCast<Arguments*>(object); + unsigned i = propertyName.asIndex(); + if (i < thisObject->m_numArguments) { + 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(thisObject); + if (!thisObject->isDeletedArgument(i) && !JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot)) { + JSValue value = thisObject->tryGetArgument(i); + ASSERT(value); + object->putDirectMayBeIndex(exec, propertyName, value); + } + if (!Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow)) + return false; + + // From ES 5.1, 10.6 Arguments Object + // 5. If the value of isMapped is not undefined, then + if (thisObject->isArgument(i)) { + // a. If IsAccessorDescriptor(Desc) is true, then + if (descriptor.isAccessorDescriptor()) { + // i. Call the [[Delete]] internal method of map passing P, and false as the arguments. + thisObject->tryDeleteArgument(i); + } else { // b. Else + // i. If Desc.[[Value]] is present, then + // 1. Call the [[Put]] internal method of map passing P, Desc.[[Value]], and Throw as the arguments. + if (descriptor.value()) + thisObject->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()) + thisObject->tryDeleteArgument(i); + } + } + return true; + } + + if (propertyName == exec->propertyNames().length && !thisObject->m_overrodeLength) { + 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->vm(), propertyName, thisObject->m_callee.get(), DontEnum); + thisObject->m_overrodeCallee = true; + } else if (propertyName == exec->propertyNames().caller && thisObject->m_isStrictMode) + thisObject->createStrictModeCallerIfNecessary(exec); + + return Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow); +} + +void Arguments::tearOff(CallFrame* callFrame) +{ + if (isTornOff()) + return; + + if (!m_numArguments) + return; + + // Must be called for the same call frame from which it was created. + ASSERT(bitwise_cast<WriteBarrier<Unknown>*>(callFrame) == m_registers); + + m_registerArray = std::make_unique<WriteBarrier<Unknown>[]>(m_numArguments); + m_registers = m_registerArray.get() - CallFrame::offsetFor(1) - 1; + + // If we have a captured argument that logically aliases activation storage, + // but we optimize away the activation, the argument needs to tear off into + // our storage. The simplest way to do this is to revert it to Normal status. + if (m_slowArgumentData && !m_activation) { + for (size_t i = 0; i < m_numArguments; ++i) { + if (m_slowArgumentData->slowArguments[i].status != SlowArgument::Captured) + continue; + m_slowArgumentData->slowArguments[i].status = SlowArgument::Normal; + m_slowArgumentData->slowArguments[i].index = CallFrame::argumentOffset(i); + } + } + + for (size_t i = 0; i < m_numArguments; ++i) + trySetArgument(callFrame->vm(), i, callFrame->argumentAfterCapture(i)); +} + +void Arguments::didTearOffActivation(ExecState* exec, JSActivation* activation) +{ + RELEASE_ASSERT(activation); + if (isTornOff()) + return; + + if (!m_numArguments) + return; + + m_activation.set(exec->vm(), this, activation); + tearOff(exec); +} + +void Arguments::tearOff(CallFrame* callFrame, InlineCallFrame* inlineCallFrame) +{ + if (isTornOff()) + return; + + if (!m_numArguments) + return; + + m_registerArray = std::make_unique<WriteBarrier<Unknown>[]>(m_numArguments); + m_registers = m_registerArray.get() - CallFrame::offsetFor(1) - 1; + + for (size_t i = 0; i < m_numArguments; ++i) { + ValueRecovery& recovery = inlineCallFrame->arguments[i + 1]; + trySetArgument(callFrame->vm(), i, recovery.recover(callFrame)); + } +} + +EncodedJSValue JSC_HOST_CALL argumentsFuncIterator(ExecState* exec) +{ + JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); + Arguments* arguments = jsDynamicCast<Arguments*>(thisObj); + if (!arguments) + return JSValue::encode(throwTypeError(exec, "Attempted to use Arguments iterator on non-Arguments object")); + return JSValue::encode(JSArgumentsIterator::create(exec->vm(), exec->callee()->globalObject()->argumentsIteratorStructure(), arguments)); +} + + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Arguments.h b/Source/JavaScriptCore/runtime/Arguments.h new file mode 100644 index 000000000..18f389171 --- /dev/null +++ b/Source/JavaScriptCore/runtime/Arguments.h @@ -0,0 +1,298 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) + * Copyright (C) 2007 Maks Orlovich + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef Arguments_h +#define Arguments_h + +#include "CodeOrigin.h" +#include "JSActivation.h" +#include "JSDestructibleObject.h" +#include "JSFunction.h" +#include "JSGlobalObject.h" +#include "Interpreter.h" +#include "ObjectConstructor.h" +#include <wtf/StdLibExtras.h> + +namespace JSC { + +class Arguments : public JSDestructibleObject { + friend class JIT; + friend class JSArgumentsIterator; +public: + typedef JSDestructibleObject Base; + + static Arguments* create(VM& vm, CallFrame* callFrame) + { + Arguments* arguments = new (NotNull, allocateCell<Arguments>(vm.heap)) Arguments(callFrame); + arguments->finishCreation(callFrame); + return arguments; + } + + static Arguments* create(VM& vm, CallFrame* callFrame, InlineCallFrame* inlineCallFrame) + { + Arguments* arguments = new (NotNull, allocateCell<Arguments>(vm.heap)) Arguments(callFrame); + arguments->finishCreation(callFrame, inlineCallFrame); + return arguments; + } + + enum { MaxArguments = 0x10000 }; + +private: + enum NoParametersType { NoParameters }; + + Arguments(CallFrame*); + Arguments(CallFrame*, NoParametersType); + +public: + DECLARE_INFO; + + static void visitChildren(JSCell*, SlotVisitor&); + + void fillArgList(ExecState*, MarkedArgumentBuffer&); + + uint32_t length(ExecState* exec) const + { + if (UNLIKELY(m_overrodeLength)) + return get(exec, exec->propertyNames().length).toUInt32(exec); + return m_numArguments; + } + + void copyToArguments(ExecState*, CallFrame*, uint32_t length); + void tearOff(CallFrame*); + void tearOff(CallFrame*, InlineCallFrame*); + bool isTornOff() const { return m_registerArray.get(); } + void didTearOffActivation(ExecState*, JSActivation*); + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } + + static ptrdiff_t offsetOfNumArguments() { return OBJECT_OFFSETOF(Arguments, m_numArguments); } + static ptrdiff_t offsetOfRegisters() { return OBJECT_OFFSETOF(Arguments, m_registers); } + static ptrdiff_t offsetOfSlowArgumentData() { return OBJECT_OFFSETOF(Arguments, m_slowArgumentData); } + static ptrdiff_t offsetOfOverrodeLength() { return OBJECT_OFFSETOF(Arguments, m_overrodeLength); } + +protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags; + + void finishCreation(CallFrame*); + void finishCreation(CallFrame*, InlineCallFrame*); + +private: + static void destroy(JSCell*); + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&); + static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); + static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); + static bool deleteProperty(JSCell*, ExecState*, PropertyName); + static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); + static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow); + void createStrictModeCallerIfNecessary(ExecState*); + void createStrictModeCalleeIfNecessary(ExecState*); + + bool isArgument(size_t); + bool trySetArgument(VM&, size_t argument, JSValue); + JSValue tryGetArgument(size_t argument); + bool isDeletedArgument(size_t); + bool tryDeleteArgument(size_t); + WriteBarrierBase<Unknown>& argument(size_t); + void allocateSlowArguments(); + + void init(CallFrame*); + + WriteBarrier<JSActivation> m_activation; + + unsigned m_numArguments; + + // We make these full byte booleans to make them easy to test from the JIT, + // and because even if they were single-bit booleans we still wouldn't save + // any space. + bool m_overrodeLength; + bool m_overrodeCallee; + bool m_overrodeCaller; + bool m_isStrictMode; + + WriteBarrierBase<Unknown>* m_registers; + std::unique_ptr<WriteBarrier<Unknown>[]> m_registerArray; + + struct SlowArgumentData { + std::unique_ptr<SlowArgument[]> slowArguments; + int bytecodeToMachineCaptureOffset; // Add this if you have a bytecode offset into captured registers and you want the machine offset instead. Subtract if you want to do the opposite. + }; + + std::unique_ptr<SlowArgumentData> m_slowArgumentData; + + WriteBarrier<JSFunction> m_callee; +}; + +Arguments* asArguments(JSValue); + +inline Arguments* asArguments(JSValue value) +{ + ASSERT(asObject(value)->inherits(Arguments::info())); + return static_cast<Arguments*>(asObject(value)); +} + +inline Arguments::Arguments(CallFrame* callFrame) + : JSDestructibleObject(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure()) +{ +} + +inline Arguments::Arguments(CallFrame* callFrame, NoParametersType) + : JSDestructibleObject(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure()) +{ +} + +inline void Arguments::allocateSlowArguments() +{ + if (m_slowArgumentData) + return; + m_slowArgumentData = std::make_unique<SlowArgumentData>(); + m_slowArgumentData->bytecodeToMachineCaptureOffset = 0; + m_slowArgumentData->slowArguments = std::make_unique<SlowArgument[]>(m_numArguments); + for (size_t i = 0; i < m_numArguments; ++i) { + ASSERT(m_slowArgumentData->slowArguments[i].status == SlowArgument::Normal); + m_slowArgumentData->slowArguments[i].index = CallFrame::argumentOffset(i); + } +} + +inline bool Arguments::tryDeleteArgument(size_t argument) +{ + if (!isArgument(argument)) + return false; + allocateSlowArguments(); + m_slowArgumentData->slowArguments[argument].status = SlowArgument::Deleted; + return true; +} + +inline bool Arguments::trySetArgument(VM& vm, size_t argument, JSValue value) +{ + if (!isArgument(argument)) + return false; + this->argument(argument).set(vm, this, value); + return true; +} + +inline JSValue Arguments::tryGetArgument(size_t argument) +{ + if (!isArgument(argument)) + return JSValue(); + return this->argument(argument).get(); +} + +inline bool Arguments::isDeletedArgument(size_t argument) +{ + if (argument >= m_numArguments) + return false; + if (!m_slowArgumentData) + return false; + if (m_slowArgumentData->slowArguments[argument].status != SlowArgument::Deleted) + return false; + return true; +} + +inline bool Arguments::isArgument(size_t argument) +{ + if (argument >= m_numArguments) + return false; + if (m_slowArgumentData && m_slowArgumentData->slowArguments[argument].status == SlowArgument::Deleted) + return false; + return true; +} + +inline WriteBarrierBase<Unknown>& Arguments::argument(size_t argument) +{ + ASSERT(isArgument(argument)); + if (!m_slowArgumentData) + return m_registers[CallFrame::argumentOffset(argument)]; + + int index = m_slowArgumentData->slowArguments[argument].index; + if (!m_activation || m_slowArgumentData->slowArguments[argument].status != SlowArgument::Captured) + return m_registers[index]; + + return m_activation->registerAt(index - m_slowArgumentData->bytecodeToMachineCaptureOffset); +} + +inline void Arguments::finishCreation(CallFrame* callFrame) +{ + Base::finishCreation(callFrame->vm()); + ASSERT(inherits(info())); + + JSFunction* callee = jsCast<JSFunction*>(callFrame->callee()); + m_numArguments = callFrame->argumentCount(); + m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers()); + m_callee.set(callFrame->vm(), this, callee); + m_overrodeLength = false; + m_overrodeCallee = false; + m_overrodeCaller = false; + m_isStrictMode = callFrame->codeBlock()->isStrictMode(); + + CodeBlock* codeBlock = callFrame->codeBlock(); + if (codeBlock->hasSlowArguments()) { + SymbolTable* symbolTable = codeBlock->symbolTable(); + const SlowArgument* slowArguments = codeBlock->machineSlowArguments(); + allocateSlowArguments(); + size_t count = std::min<unsigned>(m_numArguments, symbolTable->parameterCount()); + for (size_t i = 0; i < count; ++i) + m_slowArgumentData->slowArguments[i] = slowArguments[i]; + m_slowArgumentData->bytecodeToMachineCaptureOffset = + codeBlock->framePointerOffsetToGetActivationRegisters(); + } + + // The bytecode generator omits op_tear_off_activation in cases of no + // declared parameters, so we need to tear off immediately. + if (m_isStrictMode || !callee->jsExecutable()->parameterCount()) + tearOff(callFrame); +} + +inline void Arguments::finishCreation(CallFrame* callFrame, InlineCallFrame* inlineCallFrame) +{ + Base::finishCreation(callFrame->vm()); + ASSERT(inherits(info())); + + JSFunction* callee = inlineCallFrame->calleeForCallFrame(callFrame); + m_numArguments = inlineCallFrame->arguments.size() - 1; + + if (m_numArguments) { + int offsetForArgumentOne = inlineCallFrame->arguments[1].virtualRegister().offset(); + m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(callFrame->registers()) + offsetForArgumentOne - virtualRegisterForArgument(1).offset(); + } else + m_registers = 0; + m_callee.set(callFrame->vm(), this, callee); + m_overrodeLength = false; + m_overrodeCallee = false; + m_overrodeCaller = false; + m_isStrictMode = jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->isStrictMode(); + ASSERT(!jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->symbolTable(inlineCallFrame->isCall ? CodeForCall : CodeForConstruct)->slowArguments()); + + // The bytecode generator omits op_tear_off_activation in cases of no + // declared parameters, so we need to tear off immediately. + if (m_isStrictMode || !callee->jsExecutable()->parameterCount()) + tearOff(callFrame, inlineCallFrame); +} + +} // namespace JSC + +#endif // Arguments_h diff --git a/Source/JavaScriptCore/runtime/JSWeakSet.cpp b/Source/JavaScriptCore/runtime/ArgumentsIteratorConstructor.cpp index 3b807535f..afb59790c 100644 --- a/Source/JavaScriptCore/runtime/JSWeakSet.cpp +++ b/Source/JavaScriptCore/runtime/ArgumentsIteratorConstructor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Apple, Inc. All rights reserved. + * 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 @@ -24,29 +24,22 @@ */ #include "config.h" -#include "JSWeakSet.h" +#include "ArgumentsIteratorConstructor.h" +#include "ArgumentsIteratorPrototype.h" +#include "JSArgumentsIterator.h" #include "JSCJSValueInlines.h" -#include "SlotVisitorInlines.h" -#include "StructureInlines.h" -#include "WeakMapData.h" -#include "WriteBarrierInlines.h" +#include "JSCellInlines.h" +#include "JSGlobalObject.h" namespace JSC { -const ClassInfo JSWeakSet::s_info = { "WeakSet", &Base::s_info, 0, CREATE_METHOD_TABLE(JSWeakSet) }; +const ClassInfo ArgumentsIteratorConstructor::s_info = { "ArgumentsIterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ArgumentsIteratorConstructor) }; -void JSWeakSet::finishCreation(VM& vm) +void ArgumentsIteratorConstructor::finishCreation(VM& vm, ArgumentsIteratorPrototype* prototype) { Base::finishCreation(vm); - m_weakMapData.set(vm, this, WeakMapData::create(vm)); -} - -void JSWeakSet::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - Base::visitChildren(cell, visitor); - JSWeakSet* thisObj = jsCast<JSWeakSet*>(cell); - visitor.append(&thisObj->m_weakMapData); + putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, DontEnum | DontDelete | ReadOnly); } } diff --git a/Source/JavaScriptCore/runtime/WeakSetConstructor.h b/Source/JavaScriptCore/runtime/ArgumentsIteratorConstructor.h index 7f6fb6a5e..8360c59b2 100644 --- a/Source/JavaScriptCore/runtime/WeakSetConstructor.h +++ b/Source/JavaScriptCore/runtime/ArgumentsIteratorConstructor.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Apple, Inc. All rights reserved. + * 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 @@ -23,22 +23,22 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef WeakSetConstructor_h -#define WeakSetConstructor_h +#ifndef ArgumentsIteratorConstructor_h +#define ArgumentsIteratorConstructor_h #include "InternalFunction.h" namespace JSC { -class WeakSetPrototype; +class ArgumentsIteratorPrototype; -class WeakSetConstructor : public InternalFunction { +class ArgumentsIteratorConstructor : public JSNonFinalObject { public: - typedef InternalFunction Base; + typedef JSNonFinalObject Base; - static WeakSetConstructor* create(VM& vm, Structure* structure, WeakSetPrototype* prototype) + static ArgumentsIteratorConstructor* create(VM& vm, Structure* structure, ArgumentsIteratorPrototype* prototype) { - WeakSetConstructor* constructor = new (NotNull, allocateCell<WeakSetConstructor>(vm.heap)) WeakSetConstructor(vm, structure); + ArgumentsIteratorConstructor* constructor = new (NotNull, allocateCell<ArgumentsIteratorConstructor>(vm.heap)) ArgumentsIteratorConstructor(vm, structure); constructor->finishCreation(vm, prototype); return constructor; } @@ -51,15 +51,13 @@ public: } private: - WeakSetConstructor(VM& vm, Structure* structure) + ArgumentsIteratorConstructor(VM& vm, Structure* structure) : Base(vm, structure) { } - void finishCreation(VM&, WeakSetPrototype*); - static ConstructType getConstructData(JSCell*, ConstructData&); - static CallType getCallData(JSCell*, CallData&); + void finishCreation(VM&, ArgumentsIteratorPrototype*); }; } -#endif // !defined(WeakSetConstructor_h) +#endif // !defined(ArgumentsIteratorConstructor_h) diff --git a/Source/JavaScriptCore/runtime/StringIteratorPrototype.cpp b/Source/JavaScriptCore/runtime/ArgumentsIteratorPrototype.cpp index b58d0ddfb..dd0894f14 100644 --- a/Source/JavaScriptCore/runtime/StringIteratorPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ArgumentsIteratorPrototype.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2013 Apple, Inc. All rights reserved. - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -21,45 +20,42 @@ * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" -#include "StringIteratorPrototype.h" +#include "ArgumentsIteratorPrototype.h" -#include "JSCJSValueInlines.h" -#include "JSCellInlines.h" -#include "JSGlobalObject.h" -#include "JSStringIterator.h" -#include "ObjectConstructor.h" -#include "StructureInlines.h" +#include "JSArgumentsIterator.h" namespace JSC { -} - -#include "StringIteratorPrototype.lut.h" - -namespace JSC { - -const ClassInfo StringIteratorPrototype::s_info = { "String Iterator", &Base::s_info, &stringIteratorPrototypeTable, CREATE_METHOD_TABLE(StringIteratorPrototype) }; +const ClassInfo ArgumentsIteratorPrototype::s_info = { "ArgumentsIterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ArgumentsIteratorPrototype) }; -/* Source for StringIteratorPrototype.lut.h -@begin stringIteratorPrototypeTable - next stringIteratorPrototypeFuncNext DontEnum|Function 0 -@end -*/ +static EncodedJSValue JSC_HOST_CALL argumentsIteratorPrototypeFuncIterator(ExecState*); +static EncodedJSValue JSC_HOST_CALL argumentsIteratorPrototypeFuncNext(ExecState*); -void StringIteratorPrototype::finishCreation(VM& vm, JSGlobalObject*) +void ArgumentsIteratorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) { Base::finishCreation(vm); ASSERT(inherits(info())); vm.prototypeMap.addPrototype(this); + + JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorPrivateName, argumentsIteratorPrototypeFuncIterator, DontEnum, 0); + JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorNextPrivateName, argumentsIteratorPrototypeFuncNext, DontEnum, 0); } -bool StringIteratorPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) +EncodedJSValue JSC_HOST_CALL argumentsIteratorPrototypeFuncIterator(CallFrame* callFrame) { - return getStaticFunctionSlot<Base>(exec, stringIteratorPrototypeTable, jsCast<StringIteratorPrototype*>(object), propertyName, slot); + return JSValue::encode(callFrame->thisValue()); } -} // namespace JSC +EncodedJSValue JSC_HOST_CALL argumentsIteratorPrototypeFuncNext(CallFrame* callFrame) +{ + JSValue result; + if (jsCast<JSArgumentsIterator*>(callFrame->thisValue())->next(callFrame, result)) + return JSValue::encode(result); + return JSValue::encode(callFrame->vm().iterationTerminator.get()); +} + +} diff --git a/Source/JavaScriptCore/runtime/WeakSetPrototype.h b/Source/JavaScriptCore/runtime/ArgumentsIteratorPrototype.h index 94d90f9c9..21839bfa1 100644 --- a/Source/JavaScriptCore/runtime/WeakSetPrototype.h +++ b/Source/JavaScriptCore/runtime/ArgumentsIteratorPrototype.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Apple, Inc. All rights reserved. + * 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 @@ -23,20 +23,20 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef WeakSetPrototype_h -#define WeakSetPrototype_h +#ifndef ArgumentsIteratorPrototype_h +#define ArgumentsIteratorPrototype_h #include "JSObject.h" namespace JSC { -class WeakSetPrototype : public JSNonFinalObject { +class ArgumentsIteratorPrototype : public JSNonFinalObject { public: typedef JSNonFinalObject Base; - static WeakSetPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) + static ArgumentsIteratorPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) { - WeakSetPrototype* prototype = new (NotNull, allocateCell<WeakSetPrototype>(vm.heap)) WeakSetPrototype(vm, structure); + ArgumentsIteratorPrototype* prototype = new (NotNull, allocateCell<ArgumentsIteratorPrototype>(vm.heap)) ArgumentsIteratorPrototype(vm, structure); prototype->finishCreation(vm, globalObject); return prototype; } @@ -49,7 +49,7 @@ public: } private: - WeakSetPrototype(VM& vm, Structure* structure) + ArgumentsIteratorPrototype(VM& vm, Structure* structure) : Base(vm, structure) { } @@ -58,4 +58,4 @@ private: } -#endif // !defined(WeakSetPrototype_h) +#endif // !defined(ArgumentsIteratorPrototype_h) diff --git a/Source/JavaScriptCore/runtime/ArgumentsMode.h b/Source/JavaScriptCore/runtime/ArgumentsMode.h deleted file mode 100644 index 67cd3348d..000000000 --- a/Source/JavaScriptCore/runtime/ArgumentsMode.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2015 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 ArgumentsMode_h -#define ArgumentsMode_h - -namespace JSC { - -enum class ArgumentsMode { - Cloned, - FakeValues -}; - -} // namespace JSC - -#endif // ArgumentsMode_h - diff --git a/Source/JavaScriptCore/runtime/ArityCheckMode.h b/Source/JavaScriptCore/runtime/ArityCheckMode.h deleted file mode 100644 index f2090c057..000000000 --- a/Source/JavaScriptCore/runtime/ArityCheckMode.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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 ArityCheckMode_h -#define ArityCheckMode_h - -namespace JSC { - -enum ArityCheckMode { - ArityCheckNotRequired, - MustCheckArity -}; - -} // namespace JSC - -#endif // ArityCheckMode_h - diff --git a/Source/JavaScriptCore/runtime/ArrayBuffer.cpp b/Source/JavaScriptCore/runtime/ArrayBuffer.cpp index f78a0c0f0..2c49b6976 100644 --- a/Source/JavaScriptCore/runtime/ArrayBuffer.cpp +++ b/Source/JavaScriptCore/runtime/ArrayBuffer.cpp @@ -28,7 +28,7 @@ #include "ArrayBufferNeuteringWatchpoint.h" #include "JSArrayBufferView.h" -#include "JSCInlines.h" +#include "Operations.h" #include <wtf/RefPtr.h> namespace JSC { @@ -57,7 +57,7 @@ bool ArrayBuffer::transfer(ArrayBufferContents& result) if (JSArrayBufferView* view = jsDynamicCast<JSArrayBufferView*>(cell)) view->neuter(); else if (ArrayBufferNeuteringWatchpoint* watchpoint = jsDynamicCast<ArrayBufferNeuteringWatchpoint*>(cell)) - watchpoint->fireAll(); + watchpoint->set()->fireAll(); } return true; } diff --git a/Source/JavaScriptCore/runtime/ArrayBuffer.h b/Source/JavaScriptCore/runtime/ArrayBuffer.h index a7b6f33d7..f0d7d2719 100644 --- a/Source/JavaScriptCore/runtime/ArrayBuffer.h +++ b/Source/JavaScriptCore/runtime/ArrayBuffer.h @@ -96,7 +96,7 @@ public: static inline PassRefPtr<ArrayBuffer> create(ArrayBufferContents&); static inline PassRefPtr<ArrayBuffer> createAdopted(const void* data, unsigned byteLength); - // Only for use by Uint8ClampedArray::createUninitialized and SharedBuffer::createArrayBuffer. + // Only for use by Uint8ClampedArray::createUninitialized. static inline PassRefPtr<ArrayBuffer> createUninitialized(unsigned numElements, unsigned elementByteSize); inline void* data(); diff --git a/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.cpp b/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.cpp index a15b50440..b11a0ad3a 100644 --- a/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.cpp +++ b/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.cpp @@ -26,12 +26,12 @@ #include "config.h" #include "ArrayBufferNeuteringWatchpoint.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { const ClassInfo ArrayBufferNeuteringWatchpoint::s_info = { - "ArrayBufferNeuteringWatchpoint", 0, 0, + "ArrayBufferNeuteringWatchpoint", 0, 0, 0, CREATE_METHOD_TABLE(ArrayBufferNeuteringWatchpoint) }; @@ -57,12 +57,7 @@ ArrayBufferNeuteringWatchpoint* ArrayBufferNeuteringWatchpoint::create(VM& vm) Structure* ArrayBufferNeuteringWatchpoint::createStructure(VM& vm) { - return Structure::create(vm, 0, jsNull(), TypeInfo(CellType, StructureFlags), info()); -} - -void ArrayBufferNeuteringWatchpoint::fireAll() -{ - set()->fireAll("Array buffer was neutered"); + return Structure::create(vm, 0, jsNull(), TypeInfo(CompoundType, StructureFlags), info()); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.h b/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.h index ab26f0332..96dbd69c7 100644 --- a/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.h +++ b/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.h @@ -31,27 +31,27 @@ namespace JSC { -class ArrayBufferNeuteringWatchpoint final : public JSCell { +class ArrayBufferNeuteringWatchpoint : public JSCell { public: typedef JSCell Base; - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; - + +private: + ArrayBufferNeuteringWatchpoint(VM&); + +public: DECLARE_INFO; static ArrayBufferNeuteringWatchpoint* create(VM&); static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; static void destroy(JSCell*); static Structure* createStructure(VM&); WatchpointSet* set() { return m_set.get(); } - - void fireAll(); private: - explicit ArrayBufferNeuteringWatchpoint(VM&); - RefPtr<WatchpointSet> m_set; }; diff --git a/Source/JavaScriptCore/runtime/ArrayBufferView.cpp b/Source/JavaScriptCore/runtime/ArrayBufferView.cpp index f0fe06be4..2332e2663 100644 --- a/Source/JavaScriptCore/runtime/ArrayBufferView.cpp +++ b/Source/JavaScriptCore/runtime/ArrayBufferView.cpp @@ -10,10 +10,10 @@ * 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 + * 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 INC. OR + * 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 diff --git a/Source/JavaScriptCore/runtime/ArrayBufferView.h b/Source/JavaScriptCore/runtime/ArrayBufferView.h index 3fc10b0dd..2b8f70d8b 100644 --- a/Source/JavaScriptCore/runtime/ArrayBufferView.h +++ b/Source/JavaScriptCore/runtime/ArrayBufferView.h @@ -10,10 +10,10 @@ * 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 + * 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 INC. OR + * 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 @@ -77,20 +77,22 @@ public: JS_EXPORT_PRIVATE virtual ~ArrayBufferView(); - // Helper to verify byte offset is size aligned. - static bool verifyByteOffsetAlignment(unsigned byteOffset, size_t size) - { - return !(byteOffset & (size - 1)); - } - // Helper to verify that a given sub-range of an ArrayBuffer is // within range. - static bool verifySubRangeLength(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned numElements, size_t size) + // FIXME: This should distinguish between alignment errors and bounds errors. + // https://bugs.webkit.org/show_bug.cgi?id=125391 + template <typename T> + static bool verifySubRange( + PassRefPtr<ArrayBuffer> buffer, + unsigned byteOffset, + unsigned numElements) { unsigned byteLength = buffer->byteLength(); + if (sizeof(T) > 1 && byteOffset % sizeof(T)) + return false; if (byteOffset > byteLength) return false; - unsigned remainingElements = (byteLength - byteOffset) / size; + unsigned remainingElements = (byteLength - byteOffset) / sizeof(T); if (numElements > remainingElements) return false; return true; diff --git a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp index 194f9217c..72fc5619f 100644 --- a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp @@ -32,7 +32,7 @@ #include "JSArray.h" #include "JSFunction.h" #include "Lookup.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { @@ -46,13 +46,11 @@ namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ArrayConstructor); -const ClassInfo ArrayConstructor::s_info = { "Function", &InternalFunction::s_info, &arrayConstructorTable, CREATE_METHOD_TABLE(ArrayConstructor) }; +const ClassInfo ArrayConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::arrayConstructorTable, CREATE_METHOD_TABLE(ArrayConstructor) }; /* Source for ArrayConstructor.lut.h @begin arrayConstructorTable isArray arrayConstructorIsArray DontEnum|Function 1 - of arrayConstructorOf DontEnum|Function 0 - from arrayConstructorFrom DontEnum|Function 0 @end */ @@ -70,7 +68,7 @@ void ArrayConstructor::finishCreation(VM& vm, ArrayPrototype* arrayPrototype) bool ArrayConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot) { - return getStaticFunctionSlot<InternalFunction>(exec, arrayConstructorTable, jsCast<ArrayConstructor*>(object), propertyName, slot); + return getStaticFunctionSlot<InternalFunction>(exec, ExecState::arrayConstructorTable(exec->vm()), jsCast<ArrayConstructor*>(object), propertyName, slot); } // ------------------------------ Functions --------------------------- diff --git a/Source/JavaScriptCore/runtime/ArrayConstructor.h b/Source/JavaScriptCore/runtime/ArrayConstructor.h index 040f26c4c..a6ac76ea4 100644 --- a/Source/JavaScriptCore/runtime/ArrayConstructor.h +++ b/Source/JavaScriptCore/runtime/ArrayConstructor.h @@ -32,7 +32,6 @@ class JSArray; class ArrayConstructor : public InternalFunction { public: typedef InternalFunction Base; - static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags; static ArrayConstructor* create(VM& vm, Structure* structure, ArrayPrototype* arrayPrototype) { @@ -50,6 +49,7 @@ public: protected: void finishCreation(VM&, ArrayPrototype*); + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags; private: ArrayConstructor(VM&, Structure*); diff --git a/Source/JavaScriptCore/runtime/ArrayConventions.h b/Source/JavaScriptCore/runtime/ArrayConventions.h index 9c62ea9b8..e5ef96336 100644 --- a/Source/JavaScriptCore/runtime/ArrayConventions.h +++ b/Source/JavaScriptCore/runtime/ArrayConventions.h @@ -38,7 +38,7 @@ namespace JSC { // (specifically, this is only one property - the value 0xFFFFFFFFU as an unsigned 32-bit // integer) are not considered array indices and will be stored in the JSObject property map. // -// All properties with a numeric identifier, representable as an unsigned integer i, +// All properties with a numeric identifer, representable as an unsigned integer i, // where (i <= MAX_ARRAY_INDEX), are an array index and will be stored in either the // storage vector or the sparse map. An array index i will be handled in the following // fashion: @@ -58,14 +58,7 @@ namespace JSC { // These values have to be macros to be used in max() and min() without introducing // a PIC branch in Mach-O binaries, see <rdar://problem/5971391>. - -// If you grow an ArrayStorage array by more than this, then the array will go sparse. Note that we -// could probably make this smaller (it's large because it used to be conflated with -// MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH). #define MIN_SPARSE_ARRAY_INDEX 100000U -// If you try to allocate a contiguous array larger than this, then we will allocate an ArrayStorage -// array instead. We allow for an array that occupies 1GB of VM. -#define MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH 1024 * 1024 * 1024 / 8 #define MAX_STORAGE_VECTOR_INDEX (MAX_STORAGE_VECTOR_LENGTH - 1) // 0xFFFFFFFF is a bit weird -- is not an array index even though it's an integer. #define MAX_ARRAY_INDEX 0xFFFFFFFEU diff --git a/Source/JavaScriptCore/runtime/JSConsole.cpp b/Source/JavaScriptCore/runtime/ArrayIteratorConstructor.cpp index 7d04abf58..0916eeef2 100644 --- a/Source/JavaScriptCore/runtime/JSConsole.cpp +++ b/Source/JavaScriptCore/runtime/ArrayIteratorConstructor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Apple Inc. All rights reserved. + * 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 @@ -20,17 +20,23 @@ * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" -#include "JSConsole.h" +#include "ArrayIteratorConstructor.h" #include "JSCJSValueInlines.h" -#include "StructureInlines.h" +#include "JSCellInlines.h" +#include "JSGlobalObject.h" namespace JSC { -const ClassInfo JSConsole::s_info = { "Console", &Base::s_info, 0, CREATE_METHOD_TABLE(JSConsole) }; +const ClassInfo ArrayIteratorConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ArrayIteratorConstructor) }; + +void ArrayIteratorConstructor::finishCreation(VM& vm) +{ + Base::finishCreation(vm); +} } diff --git a/Source/JavaScriptCore/runtime/JSConsole.h b/Source/JavaScriptCore/runtime/ArrayIteratorConstructor.h index de611ec76..489d5d9e9 100644 --- a/Source/JavaScriptCore/runtime/JSConsole.h +++ b/Source/JavaScriptCore/runtime/ArrayIteratorConstructor.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Apple Inc. All rights reserved. + * 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 @@ -20,46 +20,44 @@ * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSConsole_h -#define JSConsole_h +#ifndef ArrayIteratorConstructor_h +#define ArrayIteratorConstructor_h -#include "JSObject.h" +#include "InternalFunction.h" namespace JSC { -class JSConsole : public JSNonFinalObject { +class ArrayIteratorPrototype; + +class ArrayIteratorConstructor : public JSNonFinalObject { public: typedef JSNonFinalObject Base; - DECLARE_EXPORT_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + static ArrayIteratorConstructor* create(VM& vm, Structure* structure, ArrayIteratorPrototype*) { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + ArrayIteratorConstructor* constructor = new (NotNull, allocateCell<ArrayIteratorConstructor>(vm.heap)) ArrayIteratorConstructor(vm, structure); + constructor->finishCreation(vm); + return constructor; } - static JSConsole* create(VM& vm, Structure* structure) - { - JSConsole* instance = new (NotNull, allocateCell<JSConsole>(vm.heap)) JSConsole(vm, structure); - instance->finishCreation(vm); - return instance; - } + DECLARE_INFO; - static JSConsole* create(ExecState* exec, Structure* structure) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return create(exec->vm(), structure); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } private: - JSConsole(VM& vm, Structure* structure) + ArrayIteratorConstructor(VM& vm, Structure* structure) : Base(vm, structure) { } + void finishCreation(VM&); }; } -#endif // !defined(JSConsole_h) +#endif // !defined(ArrayIteratorConstructor_h) diff --git a/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.cpp index c33091259..1ccb791b7 100644 --- a/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.cpp @@ -20,50 +20,36 @@ * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "ArrayIteratorPrototype.h" -namespace JSC { - -} - -#include "ArrayIteratorPrototype.lut.h" - -#include "IteratorOperations.h" #include "JSArrayIterator.h" -#include "JSCInlines.h" #include "JSCJSValueInlines.h" #include "JSCellInlines.h" #include "JSGlobalObject.h" #include "ObjectConstructor.h" -#include "StructureInlines.h" namespace JSC { +const ClassInfo ArrayIteratorPrototype::s_info = { "Array Iterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ArrayIteratorPrototype) }; -const ClassInfo ArrayIteratorPrototype::s_info = { "Array Iterator", &Base::s_info, &arrayIteratorPrototypeTable, CREATE_METHOD_TABLE(ArrayIteratorPrototype) }; +static EncodedJSValue JSC_HOST_CALL arrayIteratorPrototypeIterate(ExecState*); -/* Source for ArrayIteratorPrototype.lut.h -@begin arrayIteratorPrototypeTable - next arrayIteratorProtoFuncNext DontEnum|Function 0 -@end -*/ - -void ArrayIteratorPrototype::finishCreation(VM& vm, JSGlobalObject*) +void ArrayIteratorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) { Base::finishCreation(vm); ASSERT(inherits(info())); vm.prototypeMap.addPrototype(this); + + JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorPrivateName, arrayIteratorPrototypeIterate, DontEnum, 0); } -bool ArrayIteratorPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) +EncodedJSValue JSC_HOST_CALL arrayIteratorPrototypeIterate(CallFrame* callFrame) { - return getStaticFunctionSlot<Base>(exec, arrayIteratorPrototypeTable, jsCast<ArrayIteratorPrototype*>(object), propertyName, slot); + return JSValue::encode(callFrame->thisValue()); } -// ------------------------------ Array Functions ---------------------------- - -} // namespace JSC +} diff --git a/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.h b/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.h index 2b234f8ee..10ee9a6a2 100644 --- a/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.h +++ b/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.h @@ -33,7 +33,6 @@ namespace JSC { class ArrayIteratorPrototype : public JSNonFinalObject { public: typedef JSNonFinalObject Base; - static const unsigned StructureFlags = OverridesGetOwnPropertySlot | Base::StructureFlags; static ArrayIteratorPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) { @@ -54,9 +53,7 @@ private: : Base(vm, structure) { } - void finishCreation(VM&, JSGlobalObject*); - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); }; } diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp index 3cc351b31..c8659eee2 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, 2013, 2015 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) * @@ -32,13 +32,11 @@ #include "Interpreter.h" #include "JIT.h" #include "JSArrayIterator.h" -#include "JSCBuiltins.h" -#include "JSCInlines.h" #include "JSStringBuilder.h" #include "JSStringJoiner.h" #include "Lookup.h" -#include "ObjectConstructor.h" #include "ObjectPrototype.h" +#include "Operations.h" #include "StringRecursionChecker.h" #include <algorithm> #include <wtf/Assertions.h> @@ -46,27 +44,82 @@ namespace JSC { -EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState*); -EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState*); -EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState*); -EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState*); -EncodedJSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState*); -EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState*); -EncodedJSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState*); -EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState*); -EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState*); -EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState*); -EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState*); -EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState*); -EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState*); -EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState*); -EncodedJSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState*); -EncodedJSValue JSC_HOST_CALL arrayProtoFuncKeys(ExecState*); -EncodedJSValue JSC_HOST_CALL arrayProtoFuncEntries(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncValues(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncKeys(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayProtoFuncEntries(ExecState*); + +} + +#include "ArrayPrototype.lut.h" + +namespace JSC { + +static inline bool isNumericCompareFunction(ExecState* exec, CallType callType, const CallData& callData) +{ + if (callType != CallTypeJS) + return false; + + FunctionExecutable* executable = callData.js.functionExecutable; + + JSObject* error = executable->prepareForExecution(exec, callData.js.scope, CodeForCall); + if (error) + return false; + + return executable->codeBlockForCall()->isNumericCompareFunction(); +} // ------------------------------ ArrayPrototype ---------------------------- -const ClassInfo ArrayPrototype::s_info = {"Array", &JSArray::s_info, nullptr, CREATE_METHOD_TABLE(ArrayPrototype)}; +const ClassInfo ArrayPrototype::s_info = {"Array", &JSArray::s_info, 0, ExecState::arrayPrototypeTable, CREATE_METHOD_TABLE(ArrayPrototype)}; + +/* Source for ArrayPrototype.lut.h +@begin arrayPrototypeTable 16 + toString arrayProtoFuncToString DontEnum|Function 0 + toLocaleString arrayProtoFuncToLocaleString DontEnum|Function 0 + concat arrayProtoFuncConcat DontEnum|Function 1 + join arrayProtoFuncJoin DontEnum|Function 1 + pop arrayProtoFuncPop DontEnum|Function 0 + push arrayProtoFuncPush DontEnum|Function 1 + reverse arrayProtoFuncReverse DontEnum|Function 0 + shift arrayProtoFuncShift DontEnum|Function 0 + slice arrayProtoFuncSlice DontEnum|Function 2 + sort arrayProtoFuncSort DontEnum|Function 1 + splice arrayProtoFuncSplice DontEnum|Function 2 + unshift arrayProtoFuncUnShift DontEnum|Function 1 + every arrayProtoFuncEvery DontEnum|Function 1 + forEach arrayProtoFuncForEach DontEnum|Function 1 + some arrayProtoFuncSome DontEnum|Function 1 + indexOf arrayProtoFuncIndexOf DontEnum|Function 1 + lastIndexOf arrayProtoFuncLastIndexOf DontEnum|Function 1 + filter arrayProtoFuncFilter DontEnum|Function 1 + reduce arrayProtoFuncReduce DontEnum|Function 1 + reduceRight arrayProtoFuncReduceRight DontEnum|Function 1 + map arrayProtoFuncMap DontEnum|Function 1 + entries arrayProtoFuncEntries DontEnum|Function 0 + keys arrayProtoFuncKeys DontEnum|Function 0 +@end +*/ ArrayPrototype* ArrayPrototype::create(VM& vm, JSGlobalObject* globalObject, Structure* structure) { @@ -86,80 +139,32 @@ void ArrayPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) Base::finishCreation(vm); ASSERT(inherits(info())); vm.prototypeMap.addPrototype(this); + JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorPrivateName, arrayProtoFuncValues, DontEnum, 0); +} - putDirectWithoutTransition(vm, vm.propertyNames->values, globalObject->arrayProtoValuesFunction(), DontEnum); - putDirectWithoutTransition(vm, vm.propertyNames->iteratorSymbol, globalObject->arrayProtoValuesFunction(), DontEnum); - - JSC_NATIVE_FUNCTION(vm.propertyNames->toString, arrayProtoFuncToString, DontEnum, 0); - JSC_NATIVE_FUNCTION(vm.propertyNames->toLocaleString, arrayProtoFuncToLocaleString, DontEnum, 0); - JSC_NATIVE_FUNCTION("concat", arrayProtoFuncConcat, DontEnum, 1); - JSC_BUILTIN_FUNCTION("fill", arrayPrototypeFillCodeGenerator, DontEnum); - JSC_NATIVE_FUNCTION(vm.propertyNames->join, arrayProtoFuncJoin, DontEnum, 1); - JSC_NATIVE_INTRINSIC_FUNCTION("pop", arrayProtoFuncPop, DontEnum, 0, ArrayPopIntrinsic); - JSC_NATIVE_INTRINSIC_FUNCTION("push", arrayProtoFuncPush, DontEnum, 1, ArrayPushIntrinsic); - JSC_NATIVE_FUNCTION("reverse", arrayProtoFuncReverse, DontEnum, 0); - JSC_NATIVE_FUNCTION("shift", arrayProtoFuncShift, DontEnum, 0); - JSC_NATIVE_FUNCTION(vm.propertyNames->slice, arrayProtoFuncSlice, DontEnum, 2); - JSC_BUILTIN_FUNCTION("sort", arrayPrototypeSortCodeGenerator, DontEnum); - JSC_NATIVE_FUNCTION("splice", arrayProtoFuncSplice, DontEnum, 2); - JSC_NATIVE_FUNCTION("unshift", arrayProtoFuncUnShift, DontEnum, 1); - JSC_BUILTIN_FUNCTION("every", arrayPrototypeEveryCodeGenerator, DontEnum); - JSC_BUILTIN_FUNCTION("forEach", arrayPrototypeForEachCodeGenerator, DontEnum); - JSC_BUILTIN_FUNCTION("some", arrayPrototypeSomeCodeGenerator, DontEnum); - JSC_NATIVE_FUNCTION("indexOf", arrayProtoFuncIndexOf, DontEnum, 1); - JSC_NATIVE_FUNCTION("lastIndexOf", arrayProtoFuncLastIndexOf, DontEnum, 1); - JSC_BUILTIN_FUNCTION("filter", arrayPrototypeFilterCodeGenerator, DontEnum); - JSC_BUILTIN_FUNCTION("reduce", arrayPrototypeReduceCodeGenerator, DontEnum); - JSC_BUILTIN_FUNCTION("reduceRight", arrayPrototypeReduceRightCodeGenerator, DontEnum); - JSC_BUILTIN_FUNCTION("map", arrayPrototypeMapCodeGenerator, DontEnum); - JSC_NATIVE_FUNCTION(vm.propertyNames->entries, arrayProtoFuncEntries, DontEnum, 0); - JSC_NATIVE_FUNCTION(vm.propertyNames->keys, arrayProtoFuncKeys, DontEnum, 0); - JSC_BUILTIN_FUNCTION("find", arrayPrototypeFindCodeGenerator, DontEnum); - JSC_BUILTIN_FUNCTION("findIndex", arrayPrototypeFindIndexCodeGenerator, DontEnum); - JSC_BUILTIN_FUNCTION("includes", arrayPrototypeIncludesCodeGenerator, DontEnum); - JSC_BUILTIN_FUNCTION("copyWithin", arrayPrototypeCopyWithinCodeGenerator, DontEnum); - - JSObject* unscopables = constructEmptyObject(globalObject->globalExec(), globalObject->nullPrototypeObjectStructure()); - const char* unscopableNames[] = { - "copyWithin", - "entries", - "fill", - "find", - "findIndex", - "keys", - "values" - }; - for (const char* unscopableName : unscopableNames) - unscopables->putDirect(vm, Identifier::fromString(&vm, unscopableName), jsBoolean(true)); - putDirectWithoutTransition(vm, vm.propertyNames->unscopablesSymbol, unscopables, DontEnum | ReadOnly); +bool ArrayPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) +{ + return getStaticFunctionSlot<JSArray>(exec, ExecState::arrayPrototypeTable(exec->vm()), jsCast<ArrayPrototype*>(object), propertyName, slot); } // ------------------------------ Array Functions ---------------------------- -static ALWAYS_INLINE JSValue getProperty(ExecState* exec, JSObject* object, unsigned index) +// Helper function +static JSValue getProperty(ExecState* exec, JSObject* obj, unsigned index) { - if (JSValue result = object->tryGetIndexQuickly(index)) - return result; - PropertySlot slot(object); - if (!object->getPropertySlot(exec, index, slot)) + PropertySlot slot(obj); + if (!obj->getPropertySlot(exec, index, slot)) return JSValue(); return slot.getValue(exec, index); } -static ALWAYS_INLINE unsigned getLength(ExecState* exec, JSObject* obj) -{ - if (isJSArray(obj)) - return jsCast<JSArray*>(obj)->length(); - return obj->get(exec, exec->propertyNames().length).toUInt32(exec); -} - -static void putLength(ExecState* exec, JSObject* obj, JSValue value) +static void putProperty(ExecState* exec, JSObject* obj, PropertyName propertyName, JSValue value) { PutPropertySlot slot(obj); - obj->methodTable()->put(obj, exec, exec->propertyNames().length, value, slot); + obj->methodTable()->put(obj, exec, propertyName, value, slot); } -static inline unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument, unsigned length, unsigned undefinedValue = 0) +static unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument, unsigned length, unsigned undefinedValue = 0) { JSValue value = exec->argument(argument); if (value.isUndefined()) @@ -173,6 +178,7 @@ static inline unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int a return indexDouble > length ? length : static_cast<unsigned>(indexDouble); } + // The shift/unshift function implement the shift/unshift behaviour required // by the corresponding array prototype methods, and by splice. In both cases, // the methods are operating an an array or array like object. @@ -187,7 +193,6 @@ static inline unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int a // currentCount) will be shifted to the left or right as appropriate; in the // case of shift this must be removing values, in the case of unshift this // must be introducing new values. - template<JSArray::ShiftCountMode shiftCountMode> void shift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length) { @@ -199,32 +204,33 @@ void shift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned current if (isJSArray(thisObj)) { JSArray* array = asArray(thisObj); - if (array->length() == length && array->shiftCount<shiftCountMode>(exec, header, count)) + if (array->length() == length && asArray(thisObj)->shiftCount<shiftCountMode>(exec, header, count)) return; } for (unsigned k = header; k < length - currentCount; ++k) { unsigned from = k + currentCount; unsigned to = k + resultCount; - if (JSValue value = getProperty(exec, thisObj, from)) { + PropertySlot slot(thisObj); + if (thisObj->getPropertySlot(exec, from, slot)) { + JSValue value = slot.getValue(exec, from); if (exec->hadException()) return; - thisObj->putByIndexInline(exec, to, value, true); + thisObj->methodTable()->putByIndex(thisObj, exec, to, value, true); if (exec->hadException()) return; - } else if (!thisObj->methodTable(exec->vm())->deletePropertyByIndex(thisObj, exec, to)) { + } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, to)) { throwTypeError(exec, ASCIILiteral("Unable to delete property.")); return; } } for (unsigned k = length; k > length - count; --k) { - if (!thisObj->methodTable(exec->vm())->deletePropertyByIndex(thisObj, exec, k - 1)) { + if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, k - 1)) { throwTypeError(exec, ASCIILiteral("Unable to delete property.")); return; } } } - template<JSArray::ShiftCountMode shiftCountMode> void unshift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length) { @@ -245,15 +251,17 @@ void unshift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned curre if (array->length() == length && array->unshiftCount<shiftCountMode>(exec, header, count)) return; } - + for (unsigned k = length - currentCount; k > header; --k) { unsigned from = k + currentCount - 1; unsigned to = k + resultCount - 1; - if (JSValue value = getProperty(exec, thisObj, from)) { + PropertySlot slot(thisObj); + if (thisObj->getPropertySlot(exec, from, slot)) { + JSValue value = slot.getValue(exec, from); if (exec->hadException()) return; - thisObj->putByIndexInline(exec, to, value, true); - } else if (!thisObj->methodTable(exec->vm())->deletePropertyByIndex(thisObj, exec, to)) { + thisObj->methodTable()->putByIndex(thisObj, exec, to, value, true); + } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, to)) { throwTypeError(exec, ASCIILiteral("Unable to delete property.")); return; } @@ -264,7 +272,7 @@ void unshift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned curre EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec) { - JSValue thisValue = exec->thisValue().toThis(exec, StrictMode); + JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode); // 1. Let array be the result of calling ToObject on the this value. JSObject* thisObject = thisValue.toObject(exec); @@ -276,274 +284,155 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec) // 3. If IsCallable(func) is false, then let func be the standard built-in method Object.prototype.toString (15.2.4.2). if (!function.isCell()) - return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisObject->methodTable(exec->vm())->className(thisObject), "]")); + return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisObject->methodTable()->className(thisObject), "]")); CallData callData; CallType callType = getCallData(function, callData); if (callType == CallTypeNone) - return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisObject->methodTable(exec->vm())->className(thisObject), "]")); + return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisObject->methodTable()->className(thisObject), "]")); // 4. Return the result of calling the [[Call]] internal method of func providing array as the this value and an empty arguments list. if (!isJSArray(thisObject) || callType != CallTypeHost || callData.native.function != arrayProtoFuncJoin) return JSValue::encode(call(exec, function, callType, callData, thisObject, exec->emptyList())); ASSERT(isJSArray(thisValue)); - JSArray* thisArray = asArray(thisValue); - - unsigned length = thisArray->length(); + JSArray* thisObj = asArray(thisValue); + + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); - StringRecursionChecker checker(exec, thisArray); + StringRecursionChecker checker(exec, thisObj); if (JSValue earlyReturnValue = checker.earlyReturnValue()) return JSValue::encode(earlyReturnValue); - JSStringJoiner joiner(*exec, ',', length); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - for (unsigned i = 0; i < length; ++i) { - JSValue element = thisArray->tryGetIndexQuickly(i); - if (!element) { - element = thisArray->get(exec, i); + 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 { + element = thisObj->get(exec, k); if (exec->hadException()) return JSValue::encode(jsUndefined()); } - joiner.append(*exec, element); + + if (element.isUndefinedOrNull()) + stringJoiner.append(String()); + else + stringJoiner.append(element.toWTFString(exec)); + if (exec->hadException()) return JSValue::encode(jsUndefined()); } - - return JSValue::encode(joiner.join(*exec)); + return JSValue::encode(stringJoiner.join(exec)); } EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec) { - JSValue thisValue = exec->thisValue().toThis(exec, StrictMode); + JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode); - JSObject* thisObject = thisValue.toObject(exec); + JSObject* thisObj = thisValue.toObject(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); - unsigned length = getLength(exec, thisObject); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); - StringRecursionChecker checker(exec, thisObject); + StringRecursionChecker checker(exec, thisObj); if (JSValue earlyReturnValue = checker.earlyReturnValue()) return JSValue::encode(earlyReturnValue); - JSStringJoiner stringJoiner(*exec, ',', length); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - for (unsigned i = 0; i < length; ++i) { - JSValue element = thisObject->getIndex(exec, i); + String separator(",", String::ConstructFromLiteral); + JSStringJoiner stringJoiner(separator, length); + for (unsigned k = 0; k < length; k++) { + JSValue element = thisObj->get(exec, k); if (exec->hadException()) return JSValue::encode(jsUndefined()); - if (element.isUndefinedOrNull()) - continue; - JSValue conversionFunction = element.get(exec, exec->propertyNames().toLocaleString); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - CallData callData; - CallType callType = getCallData(conversionFunction, callData); - if (callType != CallTypeNone) { - element = call(exec, conversionFunction, callType, callData, element, exec->emptyList()); + if (!element.isUndefinedOrNull()) { + JSObject* o = element.toObject(exec); + JSValue conversionFunction = o->get(exec, exec->propertyNames().toLocaleString); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + String str; + CallData callData; + CallType callType = getCallData(conversionFunction, callData); + if (callType != CallTypeNone) + str = call(exec, conversionFunction, callType, callData, element, exec->emptyList()).toWTFString(exec); + else + str = element.toWTFString(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); + stringJoiner.append(str); } - stringJoiner.append(*exec, element); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); } - return JSValue::encode(stringJoiner.join(*exec)); + return JSValue::encode(stringJoiner.join(exec)); } -static inline bool isHole(double value) +EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec) { - return std::isnan(value); -} + JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); -static inline bool isHole(const WriteBarrier<Unknown>& value) -{ - return !value; -} + StringRecursionChecker checker(exec, thisObj); + if (JSValue earlyReturnValue = checker.earlyReturnValue()) + return JSValue::encode(earlyReturnValue); -template<typename T> static inline bool containsHole(T* data, unsigned length) -{ - for (unsigned i = 0; i < length; ++i) { - if (isHole(data[i])) - return true; - } - return false; -} + String separator; + if (!exec->argument(0).isUndefined()) + separator = exec->argument(0).toWTFString(exec); + if (separator.isNull()) + separator = String(",", String::ConstructFromLiteral); -static inline bool holesMustForwardToPrototype(ExecState& state, JSObject* object) -{ - auto& vm = state.vm(); - return object->structure(vm)->holesMustForwardToPrototype(vm); -} + JSStringJoiner stringJoiner(separator, length); -static inline JSValue join(ExecState& state, JSObject* thisObject, StringView separator) -{ - unsigned length = getLength(&state, thisObject); - if (state.hadException()) - return jsUndefined(); + unsigned k = 0; + if (isJSArray(thisObj)) { + JSArray* array = asArray(thisObj); - switch (thisObject->indexingType()) { - case ALL_CONTIGUOUS_INDEXING_TYPES: - case ALL_INT32_INDEXING_TYPES: { - auto& butterfly = *thisObject->butterfly(); - if (length > butterfly.publicLength()) - break; - JSStringJoiner joiner(state, separator, length); - if (state.hadException()) - return jsUndefined(); - auto data = butterfly.contiguous().data(); - bool holesKnownToBeOK = false; - for (unsigned i = 0; i < length; ++i) { - if (JSValue value = data[i].get()) { - joiner.append(state, value); - if (state.hadException()) - return jsUndefined(); - } else { - if (!holesKnownToBeOK) { - if (holesMustForwardToPrototype(state, thisObject)) - goto generalCase; - holesKnownToBeOK = true; - } - joiner.appendEmptyString(); - } - } - return joiner.join(state); - } - case ALL_DOUBLE_INDEXING_TYPES: { - auto& butterfly = *thisObject->butterfly(); - if (length > butterfly.publicLength()) - break; - JSStringJoiner joiner(state, separator, length); - if (state.hadException()) - return jsUndefined(); - auto data = butterfly.contiguousDouble().data(); - bool holesKnownToBeOK = false; - for (unsigned i = 0; i < length; ++i) { - double value = data[i]; - if (!isHole(value)) - joiner.append(state, jsDoubleNumber(value)); - else { - if (!holesKnownToBeOK) { - if (thisObject->structure(state.vm())->holesMustForwardToPrototype(state.vm())) - goto generalCase; - holesKnownToBeOK = true; - } - joiner.appendEmptyString(); - } - } - return joiner.join(state); - } - case ALL_ARRAY_STORAGE_INDEXING_TYPES: { - auto& storage = *thisObject->butterfly()->arrayStorage(); - if (length > storage.vectorLength()) - break; - if (storage.hasHoles() && thisObject->structure(state.vm())->holesMustForwardToPrototype(state.vm())) - break; - JSStringJoiner joiner(state, separator, length); - if (state.hadException()) - return jsUndefined(); - auto data = storage.vector().data(); - for (unsigned i = 0; i < length; ++i) { - if (JSValue value = data[i].get()) { - joiner.append(state, value); - if (state.hadException()) - return jsUndefined(); - } else - joiner.appendEmptyString(); - } - return joiner.join(state); - } - } + for (; k < length; k++) { + if (!array->canGetIndexQuickly(k)) + break; -generalCase: - JSStringJoiner joiner(state, separator, length); - if (state.hadException()) - return jsUndefined(); - for (unsigned i = 0; i < length; ++i) { - JSValue element = thisObject->getIndex(&state, i); - if (state.hadException()) - return jsUndefined(); - joiner.append(state, element); - if (state.hadException()) - return jsUndefined(); + JSValue element = array->getIndexQuickly(k); + if (!element.isUndefinedOrNull()) + stringJoiner.append(element.toWTFStringInline(exec)); + else + stringJoiner.append(String()); + } } - return joiner.join(state); -} -EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec) -{ - JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec); - - StringRecursionChecker checker(exec, thisObject); - if (JSValue earlyReturnValue = checker.earlyReturnValue()) - return JSValue::encode(earlyReturnValue); - - JSValue separatorValue = exec->argument(0); - if (separatorValue.isUndefined()) { - const LChar comma = ','; - return JSValue::encode(join(*exec, thisObject, { &comma, 1 })); + for (; k < length; k++) { + JSValue element = thisObj->get(exec, k); + if (!element.isUndefinedOrNull()) + stringJoiner.append(element.toWTFStringInline(exec)); + else + stringJoiner.append(String()); } - JSString* separator = separatorValue.toString(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - return JSValue::encode(join(*exec, thisObject, separator->view(exec))); + return JSValue::encode(stringJoiner.join(exec)); } EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec) { - JSValue thisValue = exec->thisValue().toThis(exec, StrictMode); - unsigned argCount = exec->argumentCount(); + JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode); + JSArray* arr = constructEmptyArray(exec, 0); + unsigned n = 0; JSValue curArg = thisValue.toObject(exec); - Checked<unsigned, RecordOverflow> finalArraySize = 0; - - JSArray* currentArray = nullptr; - JSArray* previousArray = nullptr; - for (unsigned i = 0; ; ++i) { - previousArray = currentArray; - currentArray = jsDynamicCast<JSArray*>(curArg); - if (currentArray) { - // Can't use JSArray::length here because this might be a RuntimeArray! - finalArraySize += getLength(exec, currentArray); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - } else - ++finalArraySize; - if (i == argCount) - break; - curArg = exec->uncheckedArgument(i); - } - - if (finalArraySize.hasOverflowed()) - return JSValue::encode(throwOutOfMemoryError(exec)); - - if (argCount == 1 && previousArray && currentArray && finalArraySize.unsafeGet() < MIN_SPARSE_ARRAY_INDEX) { - IndexingType type = JSArray::fastConcatType(exec->vm(), *previousArray, *currentArray); - if (type != NonArray) - return previousArray->fastConcatWith(*exec, *currentArray); - } - - JSArray* arr = constructEmptyArray(exec, nullptr, finalArraySize.unsafeGet()); if (exec->hadException()) return JSValue::encode(jsUndefined()); - - curArg = thisValue.toObject(exec); - unsigned n = 0; - for (unsigned i = 0; ; ++i) { - if (JSArray* currentArray = jsDynamicCast<JSArray*>(curArg)) { - // Can't use JSArray::length here because this might be a RuntimeArray! - unsigned length = getLength(exec, currentArray); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + size_t i = 0; + size_t argCount = exec->argumentCount(); + while (1) { + if (curArg.inherits(JSArray::info())) { + unsigned length = curArg.get(exec, exec->propertyNames().length).toUInt32(exec); + JSObject* curObject = curArg.toObject(exec); for (unsigned k = 0; k < length; ++k) { - JSValue v = getProperty(exec, currentArray, k); + JSValue v = getProperty(exec, curObject, k); if (exec->hadException()) return JSValue::encode(jsUndefined()); if (v) @@ -557,6 +446,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec) if (i == argCount) break; curArg = exec->uncheckedArgument(i); + ++i; } arr->setLength(exec, n); return JSValue::encode(arr); @@ -564,36 +454,36 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState* exec) { - JSValue thisValue = exec->thisValue().toThis(exec, StrictMode); + JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode); if (isJSArray(thisValue)) return JSValue::encode(asArray(thisValue)->pop(exec)); JSObject* thisObj = thisValue.toObject(exec); - unsigned length = getLength(exec, thisObj); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); JSValue result; if (length == 0) { - putLength(exec, thisObj, jsNumber(length)); + putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length)); result = jsUndefined(); } else { result = thisObj->get(exec, length - 1); if (exec->hadException()) return JSValue::encode(jsUndefined()); - if (!thisObj->methodTable(exec->vm())->deletePropertyByIndex(thisObj, exec, length - 1)) { + if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, length - 1)) { throwTypeError(exec, ASCIILiteral("Unable to delete property.")); return JSValue::encode(jsUndefined()); } - putLength(exec, thisObj, jsNumber(length - 1)); + putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - 1)); } return JSValue::encode(result); } EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec) { - JSValue thisValue = exec->thisValue().toThis(exec, StrictMode); + JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode); if (isJSArray(thisValue) && exec->argumentCount() == 1) { JSArray* array = asArray(thisValue); @@ -602,7 +492,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec) } JSObject* thisObj = thisValue.toObject(exec); - unsigned length = getLength(exec, thisObj); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); @@ -612,7 +502,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec) thisObj->methodTable()->putByIndex(thisObj, exec, length + n, exec->uncheckedArgument(n), true); else { PutPropertySlot slot(thisObj); - Identifier propertyName = Identifier::fromString(exec, JSValue(static_cast<int64_t>(length) + static_cast<int64_t>(n)).toWTFString(exec)); + Identifier propertyName(exec, JSValue(static_cast<int64_t>(length) + static_cast<int64_t>(n)).toWTFString(exec)); thisObj->methodTable()->put(thisObj, exec, propertyName, exec->uncheckedArgument(n), slot); } if (exec->hadException()) @@ -620,100 +510,65 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec) } JSValue newLength(static_cast<int64_t>(length) + static_cast<int64_t>(exec->argumentCount())); - putLength(exec, thisObj, newLength); + putProperty(exec, thisObj, exec->propertyNames().length, newLength); return JSValue::encode(newLength); } EncodedJSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState* exec) { - JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec); - - unsigned length = getLength(exec, thisObject); + JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); - switch (thisObject->indexingType()) { - case ALL_CONTIGUOUS_INDEXING_TYPES: - case ALL_INT32_INDEXING_TYPES: { - auto& butterfly = *thisObject->butterfly(); - if (length > butterfly.publicLength()) - break; - auto data = butterfly.contiguous().data(); - if (containsHole(data, length) && holesMustForwardToPrototype(*exec, thisObject)) - break; - std::reverse(data, data + length); - return JSValue::encode(thisObject); - } - case ALL_DOUBLE_INDEXING_TYPES: { - auto& butterfly = *thisObject->butterfly(); - if (length > butterfly.publicLength()) - break; - auto data = butterfly.contiguousDouble().data(); - if (containsHole(data, length) && holesMustForwardToPrototype(*exec, thisObject)) - break; - std::reverse(data, data + length); - return JSValue::encode(thisObject); - } - case ALL_ARRAY_STORAGE_INDEXING_TYPES: { - auto& storage = *thisObject->butterfly()->arrayStorage(); - if (length > storage.vectorLength()) - break; - if (storage.hasHoles() && holesMustForwardToPrototype(*exec, thisObject)) - break; - auto data = storage.vector().data(); - std::reverse(data, data + length); - return JSValue::encode(thisObject); - } - } - unsigned middle = length / 2; for (unsigned k = 0; k < middle; k++) { unsigned lk1 = length - k - 1; - JSValue obj2 = getProperty(exec, thisObject, lk1); + JSValue obj2 = getProperty(exec, thisObj, lk1); if (exec->hadException()) return JSValue::encode(jsUndefined()); - JSValue obj = getProperty(exec, thisObject, k); + JSValue obj = getProperty(exec, thisObj, k); if (exec->hadException()) return JSValue::encode(jsUndefined()); if (obj2) { - thisObject->putByIndexInline(exec, k, obj2, true); + thisObj->methodTable()->putByIndex(thisObj, exec, k, obj2, true); if (exec->hadException()) return JSValue::encode(jsUndefined()); - } else if (!thisObject->methodTable(exec->vm())->deletePropertyByIndex(thisObject, exec, k)) { + } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, k)) { throwTypeError(exec, ASCIILiteral("Unable to delete property.")); return JSValue::encode(jsUndefined()); } if (obj) { - thisObject->putByIndexInline(exec, lk1, obj, true); + thisObj->methodTable()->putByIndex(thisObj, exec, lk1, obj, true); if (exec->hadException()) return JSValue::encode(jsUndefined()); - } else if (!thisObject->methodTable(exec->vm())->deletePropertyByIndex(thisObject, exec, lk1)) { + } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, lk1)) { throwTypeError(exec, ASCIILiteral("Unable to delete property.")); return JSValue::encode(jsUndefined()); } } - return JSValue::encode(thisObject); + return JSValue::encode(thisObj); } EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState* exec) { - JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = getLength(exec, thisObj); + JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); JSValue result; if (length == 0) { - putLength(exec, thisObj, jsNumber(length)); + putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length)); result = jsUndefined(); } else { - result = thisObj->getIndex(exec, 0); + result = thisObj->get(exec, 0); shift<JSArray::ShiftCountForShift>(exec, thisObj, 0, 1, 0, length); if (exec->hadException()) return JSValue::encode(jsUndefined()); - putLength(exec, thisObj, jsNumber(length - 1)); + putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - 1)); } return JSValue::encode(result); } @@ -721,46 +576,198 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec) { // http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 or 15.4.4.10 - JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = getLength(exec, thisObj); + JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); + // We return a new array + JSArray* resObj = constructEmptyArray(exec, 0); + JSValue result = resObj; + unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length); unsigned end = argumentClampedIndexFromStartOrEnd(exec, 1, length, length); - if (isJSArray(thisObj)) { - if (JSArray* result = asArray(thisObj)->fastSlice(*exec, begin, end - begin)) - return JSValue::encode(result); - } - - JSArray* result = constructEmptyArray(exec, nullptr, end - begin); - unsigned n = 0; for (unsigned k = begin; k < end; k++, n++) { JSValue v = getProperty(exec, thisObj, k); if (exec->hadException()) return JSValue::encode(jsUndefined()); if (v) - result->putDirectIndex(exec, n, v); + resObj->putDirectIndex(exec, n, v); } - result->setLength(exec, n); + resObj->setLength(exec, n); return JSValue::encode(result); } +inline JSValue getOrHole(JSObject* obj, ExecState* exec, unsigned propertyName) +{ + PropertySlot slot(obj); + if (obj->getPropertySlot(exec, propertyName, slot)) + return slot.getValue(exec, propertyName); + + return JSValue(); +} + +static bool attemptFastSort(ExecState* exec, JSObject* thisObj, JSValue function, CallData& callData, CallType& callType) +{ + if (thisObj->classInfo() != JSArray::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 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 false; + double compareResult; + if (!jObj) + compareResult = 1; + else if (!minObj) + compareResult = -1; + else if (jObj.isUndefined()) + compareResult = 1; // don't check minObj because there's no need to differentiate == (0) from > (1) + else if (minObj.isUndefined()) + compareResult = -1; + else if (callType != CallTypeNone) { + MarkedArgumentBuffer l; + l.append(jObj); + l.append(minObj); + compareResult = call(exec, function, callType, callData, jsUndefined(), l).toNumber(exec); + } else + compareResult = codePointCompareLessThan(jObj.toWTFStringInline(exec), minObj.toWTFStringInline(exec)) ? -1 : 1; + + if (compareResult < 0) { + themin = j; + minObj = jObj; + } + } + // Swap themin and i + if (themin > i) { + if (minObj) { + thisObj->methodTable()->putByIndex(thisObj, exec, i, minObj, true); + if (exec->hadException()) + return false; + } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, i)) { + throwTypeError(exec, "Unable to delete property."); + return false; + } + if (iObj) { + thisObj->methodTable()->putByIndex(thisObj, exec, themin, iObj, true); + if (exec->hadException()) + return false; + } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, themin)) { + throwTypeError(exec, "Unable to delete property."); + return false; + } + } + } + return true; +} + +EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec) +{ + JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).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); +} + EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec) { // 15.4.4.12 - VM& vm = exec->vm(); - - JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = getLength(exec, thisObj); + JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); if (!exec->argumentCount()) - return JSValue::encode(constructEmptyArray(exec, nullptr)); + return JSValue::encode(constructEmptyArray(exec, 0)); unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length); @@ -775,22 +782,17 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec) deleteCount = static_cast<unsigned>(deleteDouble); } - JSArray* result = nullptr; - - if (isJSArray(thisObj)) - result = asArray(thisObj)->fastSlice(*exec, begin, deleteCount); - - if (!result) { - result = JSArray::tryCreateUninitialized(vm, exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), deleteCount); - if (!result) - return JSValue::encode(throwOutOfMemoryError(exec)); + JSArray* resObj = JSArray::tryCreateUninitialized(exec->vm(), exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), deleteCount); + if (!resObj) + return JSValue::encode(throwOutOfMemoryError(exec)); - for (unsigned k = 0; k < deleteCount; ++k) { - JSValue v = getProperty(exec, thisObj, k + begin); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - result->initializeIndex(vm, k, v); - } + JSValue result = resObj; + 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(vm, k, v); } unsigned additionalArgs = std::max<int>(exec->argumentCount() - 2, 0); @@ -804,12 +806,12 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec) return JSValue::encode(jsUndefined()); } for (unsigned k = 0; k < additionalArgs; ++k) { - thisObj->putByIndexInline(exec, k + begin, exec->uncheckedArgument(k + 2), true); + thisObj->methodTable()->putByIndex(thisObj, exec, k + begin, exec->uncheckedArgument(k + 2), true); if (exec->hadException()) return JSValue::encode(jsUndefined()); } - putLength(exec, thisObj, jsNumber(length - deleteCount + additionalArgs)); + putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - deleteCount + additionalArgs)); return JSValue::encode(result); } @@ -817,8 +819,8 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState* exec) { // 15.4.4.13 - JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = getLength(exec, thisObj); + JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); @@ -829,20 +831,459 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState* exec) return JSValue::encode(jsUndefined()); } for (unsigned k = 0; k < nrArgs; ++k) { - thisObj->putByIndexInline(exec, k, exec->uncheckedArgument(k), true); + thisObj->methodTable()->putByIndex(thisObj, exec, k, exec->uncheckedArgument(k), true); if (exec->hadException()) return JSValue::encode(jsUndefined()); } JSValue result = jsNumber(length + nrArgs); - putLength(exec, thisObj, result); + putProperty(exec, thisObj, exec->propertyNames().length, result); + return JSValue::encode(result); +} + +EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec) +{ + JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + JSValue function = exec->argument(0); + CallData callData; + CallType callType = getCallData(function, callData); + if (callType == CallTypeNone) + return throwVMTypeError(exec); + + JSValue applyThis = exec->argument(1); + JSArray* resultArray = constructEmptyArray(exec, 0); + + unsigned filterIndex = 0; + unsigned k = 0; + if (callType == CallTypeJS && isJSArray(thisObj)) { + JSFunction* f = jsCast<JSFunction*>(function); + JSArray* array = asArray(thisObj); + CachedCall cachedCall(exec, f, 3); + for (; k < length && !exec->hadException(); ++k) { + if (!array->canGetIndexQuickly(k)) + break; + JSValue v = array->getIndexQuickly(k); + cachedCall.setThis(applyThis); + cachedCall.setArgument(0, v); + cachedCall.setArgument(1, jsNumber(k)); + cachedCall.setArgument(2, thisObj); + + JSValue result = cachedCall.call(); + if (result.toBoolean(exec)) + resultArray->putDirectIndex(exec, filterIndex++, v); + } + if (k == length) + return JSValue::encode(resultArray); + } + for (; k < length && !exec->hadException(); ++k) { + PropertySlot slot(thisObj); + if (!thisObj->getPropertySlot(exec, k, slot)) + continue; + JSValue v = slot.getValue(exec, k); + + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + MarkedArgumentBuffer eachArguments; + eachArguments.append(v); + eachArguments.append(jsNumber(k)); + eachArguments.append(thisObj); + + JSValue result = call(exec, function, callType, callData, applyThis, eachArguments); + if (result.toBoolean(exec)) + resultArray->putDirectIndex(exec, filterIndex++, v); + } + return JSValue::encode(resultArray); +} + +EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec) +{ + JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + JSValue function = exec->argument(0); + CallData callData; + CallType callType = getCallData(function, callData); + if (callType == CallTypeNone) + return throwVMTypeError(exec); + + JSValue applyThis = exec->argument(1); + + JSArray* resultArray = constructEmptyArray(exec, 0, length); + unsigned k = 0; + if (callType == CallTypeJS && isJSArray(thisObj)) { + JSFunction* f = jsCast<JSFunction*>(function); + JSArray* array = asArray(thisObj); + CachedCall cachedCall(exec, f, 3); + for (; k < length && !exec->hadException(); ++k) { + if (UNLIKELY(!array->canGetIndexQuickly(k))) + break; + + cachedCall.setThis(applyThis); + cachedCall.setArgument(0, array->getIndexQuickly(k)); + cachedCall.setArgument(1, jsNumber(k)); + cachedCall.setArgument(2, thisObj); + + resultArray->putDirectIndex(exec, k, cachedCall.call()); + } + } + for (; k < length && !exec->hadException(); ++k) { + PropertySlot slot(thisObj); + if (!thisObj->getPropertySlot(exec, k, slot)) + continue; + JSValue v = slot.getValue(exec, k); + + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + MarkedArgumentBuffer eachArguments; + eachArguments.append(v); + eachArguments.append(jsNumber(k)); + eachArguments.append(thisObj); + + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + JSValue result = call(exec, function, callType, callData, applyThis, eachArguments); + resultArray->putDirectIndex(exec, k, result); + } + + return JSValue::encode(resultArray); +} + +// Documentation for these three is available at: +// http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:every +// http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:forEach +// http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:some + +EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState* exec) +{ + JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + JSValue function = exec->argument(0); + CallData callData; + CallType callType = getCallData(function, callData); + if (callType == CallTypeNone) + return throwVMTypeError(exec); + + JSValue applyThis = exec->argument(1); + + JSValue result = jsBoolean(true); + + unsigned k = 0; + if (callType == CallTypeJS && isJSArray(thisObj)) { + JSFunction* f = jsCast<JSFunction*>(function); + JSArray* array = asArray(thisObj); + CachedCall cachedCall(exec, f, 3); + for (; k < length && !exec->hadException(); ++k) { + if (UNLIKELY(!array->canGetIndexQuickly(k))) + break; + + cachedCall.setThis(applyThis); + cachedCall.setArgument(0, array->getIndexQuickly(k)); + cachedCall.setArgument(1, jsNumber(k)); + cachedCall.setArgument(2, thisObj); + JSValue result = cachedCall.call(); + if (!result.toBoolean(exec)) + return JSValue::encode(jsBoolean(false)); + } + } + for (; k < length && !exec->hadException(); ++k) { + PropertySlot slot(thisObj); + if (!thisObj->getPropertySlot(exec, k, slot)) + continue; + + MarkedArgumentBuffer eachArguments; + eachArguments.append(slot.getValue(exec, k)); + eachArguments.append(jsNumber(k)); + eachArguments.append(thisObj); + + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments).toBoolean(exec); + if (!predicateResult) { + result = jsBoolean(false); + break; + } + } + return JSValue::encode(result); } +EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState* exec) +{ + JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + JSValue function = exec->argument(0); + CallData callData; + CallType callType = getCallData(function, callData); + if (callType == CallTypeNone) + return throwVMTypeError(exec); + + JSValue applyThis = exec->argument(1); + + unsigned k = 0; + if (callType == CallTypeJS && isJSArray(thisObj)) { + JSFunction* f = jsCast<JSFunction*>(function); + JSArray* array = asArray(thisObj); + CachedCall cachedCall(exec, f, 3); + for (; k < length && !exec->hadException(); ++k) { + if (UNLIKELY(!array->canGetIndexQuickly(k))) + break; + + cachedCall.setThis(applyThis); + cachedCall.setArgument(0, array->getIndexQuickly(k)); + cachedCall.setArgument(1, jsNumber(k)); + cachedCall.setArgument(2, thisObj); + + cachedCall.call(); + } + } + for (; k < length && !exec->hadException(); ++k) { + PropertySlot slot(thisObj); + if (!thisObj->getPropertySlot(exec, k, slot)) + continue; + + MarkedArgumentBuffer eachArguments; + eachArguments.append(slot.getValue(exec, k)); + eachArguments.append(jsNumber(k)); + eachArguments.append(thisObj); + + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + call(exec, function, callType, callData, applyThis, eachArguments); + } + return JSValue::encode(jsUndefined()); +} + +EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState* exec) +{ + JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + JSValue function = exec->argument(0); + CallData callData; + CallType callType = getCallData(function, callData); + if (callType == CallTypeNone) + return throwVMTypeError(exec); + + JSValue applyThis = exec->argument(1); + + JSValue result = jsBoolean(false); + + unsigned k = 0; + if (callType == CallTypeJS && isJSArray(thisObj)) { + JSFunction* f = jsCast<JSFunction*>(function); + JSArray* array = asArray(thisObj); + CachedCall cachedCall(exec, f, 3); + for (; k < length && !exec->hadException(); ++k) { + if (UNLIKELY(!array->canGetIndexQuickly(k))) + break; + + cachedCall.setThis(applyThis); + cachedCall.setArgument(0, array->getIndexQuickly(k)); + cachedCall.setArgument(1, jsNumber(k)); + cachedCall.setArgument(2, thisObj); + JSValue result = cachedCall.call(); + if (result.toBoolean(exec)) + return JSValue::encode(jsBoolean(true)); + } + } + for (; k < length && !exec->hadException(); ++k) { + PropertySlot slot(thisObj); + if (!thisObj->getPropertySlot(exec, k, slot)) + continue; + + MarkedArgumentBuffer eachArguments; + eachArguments.append(slot.getValue(exec, k)); + eachArguments.append(jsNumber(k)); + eachArguments.append(thisObj); + + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments).toBoolean(exec); + if (predicateResult) { + result = jsBoolean(true); + break; + } + } + return JSValue::encode(result); +} + +EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState* exec) +{ + JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + JSValue function = exec->argument(0); + CallData callData; + CallType callType = getCallData(function, callData); + if (callType == CallTypeNone) + return throwVMTypeError(exec); + + unsigned i = 0; + JSValue rv; + if (!length && exec->argumentCount() == 1) + return throwVMTypeError(exec); + + JSArray* array = 0; + if (isJSArray(thisObj)) + array = asArray(thisObj); + + if (exec->argumentCount() >= 2) + rv = exec->uncheckedArgument(1); + else if (array && array->canGetIndexQuickly(0)) { + rv = array->getIndexQuickly(0); + i = 1; + } else { + for (i = 0; i < length; i++) { + rv = getProperty(exec, thisObj, i); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + if (rv) + break; + } + if (!rv) + return throwVMTypeError(exec); + i++; + } + + if (callType == CallTypeJS && array) { + CachedCall cachedCall(exec, jsCast<JSFunction*>(function), 4); + for (; i < length && !exec->hadException(); ++i) { + cachedCall.setThis(jsUndefined()); + cachedCall.setArgument(0, rv); + JSValue v; + if (LIKELY(array->canGetIndexQuickly(i))) + v = array->getIndexQuickly(i); + else + break; // length has been made unsafe while we enumerate fallback to slow path + cachedCall.setArgument(1, v); + cachedCall.setArgument(2, jsNumber(i)); + cachedCall.setArgument(3, array); + rv = cachedCall.call(); + } + if (i == length) // only return if we reached the end of the array + return JSValue::encode(rv); + } + + for (; i < length && !exec->hadException(); ++i) { + JSValue prop = getProperty(exec, thisObj, i); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + if (!prop) + continue; + + MarkedArgumentBuffer eachArguments; + eachArguments.append(rv); + eachArguments.append(prop); + eachArguments.append(jsNumber(i)); + eachArguments.append(thisObj); + + rv = call(exec, function, callType, callData, jsUndefined(), eachArguments); + } + return JSValue::encode(rv); +} + +EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState* exec) +{ + JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + JSValue function = exec->argument(0); + CallData callData; + CallType callType = getCallData(function, callData); + if (callType == CallTypeNone) + return throwVMTypeError(exec); + + unsigned i = 0; + JSValue rv; + if (!length && exec->argumentCount() == 1) + return throwVMTypeError(exec); + + JSArray* array = 0; + if (isJSArray(thisObj)) + array = asArray(thisObj); + + if (exec->argumentCount() >= 2) + rv = exec->uncheckedArgument(1); + else if (array && array->canGetIndexQuickly(length - 1)) { + rv = array->getIndexQuickly(length - 1); + i = 1; + } else { + for (i = 0; i < length; i++) { + rv = getProperty(exec, thisObj, length - i - 1); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + if (rv) + break; + } + if (!rv) + return throwVMTypeError(exec); + i++; + } + + if (callType == CallTypeJS && array) { + CachedCall cachedCall(exec, jsCast<JSFunction*>(function), 4); + for (; i < length && !exec->hadException(); ++i) { + unsigned idx = length - i - 1; + cachedCall.setThis(jsUndefined()); + cachedCall.setArgument(0, rv); + if (UNLIKELY(!array->canGetIndexQuickly(idx))) + break; // length has been made unsafe while we enumerate fallback to slow path + cachedCall.setArgument(1, array->getIndexQuickly(idx)); + cachedCall.setArgument(2, jsNumber(idx)); + cachedCall.setArgument(3, array); + rv = cachedCall.call(); + } + if (i == length) // only return if we reached the end of the array + return JSValue::encode(rv); + } + + for (; i < length && !exec->hadException(); ++i) { + unsigned idx = length - i - 1; + JSValue prop = getProperty(exec, thisObj, idx); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + if (!prop) + continue; + + MarkedArgumentBuffer eachArguments; + eachArguments.append(rv); + eachArguments.append(prop); + eachArguments.append(jsNumber(idx)); + eachArguments.append(thisObj); + + rv = call(exec, function, callType, callData, jsUndefined(), eachArguments); + } + return JSValue::encode(rv); +} + EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState* exec) { // 15.4.4.14 - JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = getLength(exec, thisObj); + JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); @@ -864,8 +1305,8 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState* exec) { // 15.4.4.15 - JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = getLength(exec, thisObj); + JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); if (!length) return JSValue::encode(jsNumber(-1)); @@ -899,19 +1340,19 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncValues(ExecState* exec) { - JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec); + JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); return JSValue::encode(JSArrayIterator::create(exec, exec->callee()->globalObject()->arrayIteratorStructure(), ArrayIterateValue, thisObj)); } EncodedJSValue JSC_HOST_CALL arrayProtoFuncEntries(ExecState* exec) { - JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec); + JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); return JSValue::encode(JSArrayIterator::create(exec, exec->callee()->globalObject()->arrayIteratorStructure(), ArrayIterateKeyValue, thisObj)); } EncodedJSValue JSC_HOST_CALL arrayProtoFuncKeys(ExecState* exec) { - JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec); + JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); return JSValue::encode(JSArrayIterator::create(exec, exec->callee()->globalObject()->arrayIteratorStructure(), ArrayIterateKey, thisObj)); } diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.h b/Source/JavaScriptCore/runtime/ArrayPrototype.h index 39412c220..472a1dd9c 100644 --- a/Source/JavaScriptCore/runtime/ArrayPrototype.h +++ b/Source/JavaScriptCore/runtime/ArrayPrototype.h @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2007, 2011, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2011 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 @@ -35,6 +35,8 @@ public: static ArrayPrototype* create(VM&, JSGlobalObject*, Structure*); + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + DECLARE_INFO; static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) @@ -46,8 +48,6 @@ protected: void finishCreation(VM&, JSGlobalObject*); }; -EncodedJSValue JSC_HOST_CALL arrayProtoFuncValues(ExecState*); - } // namespace JSC #endif // ArrayPrototype_h diff --git a/Source/JavaScriptCore/runtime/ArrayStorage.h b/Source/JavaScriptCore/runtime/ArrayStorage.h index c93dc3bfd..a0287c921 100644 --- a/Source/JavaScriptCore/runtime/ArrayStorage.h +++ b/Source/JavaScriptCore/runtime/ArrayStorage.h @@ -32,6 +32,7 @@ #include "SparseArrayValueMap.h" #include "WriteBarrier.h" #include <wtf/Noncopyable.h> +#include <wtf/Platform.h> namespace JSC { @@ -53,10 +54,9 @@ public: Butterfly* butterfly() { return reinterpret_cast<Butterfly*>(this); } IndexingHeader* indexingHeader() { return IndexingHeader::from(this); } - const IndexingHeader* indexingHeader() const { return IndexingHeader::from(this); } // We steal two fields from the indexing header: vectorLength and length. - unsigned length() const { return indexingHeader()->publicLength(); } + unsigned length() { return indexingHeader()->publicLength(); } void setLength(unsigned length) { indexingHeader()->setPublicLength(length); } unsigned vectorLength() { return indexingHeader()->vectorLength(); } void setVectorLength(unsigned length) { indexingHeader()->setVectorLength(length); } @@ -68,11 +68,6 @@ public: m_numValuesInVector = other.m_numValuesInVector; } - bool hasHoles() const - { - return m_numValuesInVector != length(); - } - bool inSparseMode() { return m_sparseMap && m_sparseMap->sparseMode(); diff --git a/Source/JavaScriptCore/runtime/BasicBlockLocation.cpp b/Source/JavaScriptCore/runtime/BasicBlockLocation.cpp deleted file mode 100644 index 33cc39611..000000000 --- a/Source/JavaScriptCore/runtime/BasicBlockLocation.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2014 Apple Inc. All rights reserved. - * Copyright (C) 2014 Saam Barati. <saambarati1@gmail.com> - * - * 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 "BasicBlockLocation.h" - -#include "CCallHelpers.h" -#include <climits> -#include <wtf/DataLog.h> - -namespace JSC { - -BasicBlockLocation::BasicBlockLocation(int startOffset, int endOffset) - : m_startOffset(startOffset) - , m_endOffset(endOffset) - , m_hasExecuted(false) -{ -} - -void BasicBlockLocation::insertGap(int startOffset, int endOffset) -{ - std::pair<int, int> gap(startOffset, endOffset); - if (!m_gaps.contains(gap)) - m_gaps.append(gap); -} - -Vector<std::pair<int, int>> BasicBlockLocation::getExecutedRanges() const -{ - Vector<Gap> result; - Vector<Gap> gaps = m_gaps; - int nextRangeStart = m_startOffset; - while (gaps.size()) { - Gap minGap(INT_MAX, 0); - unsigned minIdx = std::numeric_limits<unsigned>::max(); - for (unsigned idx = 0; idx < gaps.size(); idx++) { - // Because we know that the Gaps inside m_gaps aren't enclosed within one another, it suffices to just check the first element to test ordering. - if (gaps[idx].first < minGap.first) { - minGap = gaps[idx]; - minIdx = idx; - } - } - result.append(Gap(nextRangeStart, minGap.first - 1)); - nextRangeStart = minGap.second + 1; - gaps.remove(minIdx); - } - - result.append(Gap(nextRangeStart, m_endOffset)); - return result; -} - -void BasicBlockLocation::dumpData() const -{ - Vector<Gap> executedRanges = getExecutedRanges(); - for (Gap gap : executedRanges) - dataLogF("\tBasicBlock: [%d, %d] hasExecuted: %s\n", gap.first, gap.second, hasExecuted() ? "true" : "false"); -} - -#if ENABLE(JIT) -void BasicBlockLocation::emitExecuteCode(CCallHelpers& jit, MacroAssembler::RegisterID ptrReg) const -{ - jit.move(CCallHelpers::TrustedImmPtr(&m_hasExecuted), ptrReg); - jit.store8(CCallHelpers::TrustedImm32(true), CCallHelpers::Address(ptrReg, 0)); -} -#endif // ENABLE(JIT) - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/BasicBlockLocation.h b/Source/JavaScriptCore/runtime/BasicBlockLocation.h deleted file mode 100644 index 49bf51474..000000000 --- a/Source/JavaScriptCore/runtime/BasicBlockLocation.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2014 Apple Inc. All rights reserved. - * Copyright (C) 2014 Saam Barati. <saambarati1@gmail.com> - * - * 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 BasicBlockLocation_h -#define BasicBlockLocation_h - -#include "MacroAssembler.h" -#include <wtf/RefCounted.h> -#include <wtf/RefPtr.h> -#include <wtf/Vector.h> - -namespace JSC { - -class CCallHelpers; -class LLIntOffsetsExtractor; - -class BasicBlockLocation { -public: - typedef std::pair<int, int> Gap; - - BasicBlockLocation(int startOffset = -1, int endOffset = -1); - - int startOffset() const { return m_startOffset; } - int endOffset() const { return m_endOffset; } - void setStartOffset(int startOffset) { m_startOffset = startOffset; } - void setEndOffset(int endOffset) { m_endOffset = endOffset; } - bool hasExecuted() const { return m_hasExecuted; } - void insertGap(int, int); - Vector<Gap> getExecutedRanges() const; - JS_EXPORT_PRIVATE void dumpData() const; -#if ENABLE(JIT) - void emitExecuteCode(CCallHelpers&, MacroAssembler::RegisterID) const; -#endif - -private: - friend class LLIntOffsetsExtractor; - - int m_startOffset; - int m_endOffset; - bool m_hasExecuted; - Vector<Gap> m_gaps; -}; - -} // namespace JSC - -#endif // BasicBlockLocation_h diff --git a/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h b/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h index 951a3286c..76def7138 100644 --- a/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h +++ b/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h @@ -11,10 +11,10 @@ * 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 + * 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 INC. OR + * 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 @@ -38,8 +38,6 @@ public: : m_vm(&vm) , m_object(object) { - if (!m_object->structure(vm)->isDictionary()) - m_object->convertToDictionary(vm); } ~BatchedTransitionOptimizer() diff --git a/Source/JavaScriptCore/runtime/BooleanConstructor.cpp b/Source/JavaScriptCore/runtime/BooleanConstructor.cpp index 0a250760d..09fa26096 100644 --- a/Source/JavaScriptCore/runtime/BooleanConstructor.cpp +++ b/Source/JavaScriptCore/runtime/BooleanConstructor.cpp @@ -23,13 +23,13 @@ #include "BooleanPrototype.h" #include "JSGlobalObject.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(BooleanConstructor); -const ClassInfo BooleanConstructor::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(BooleanConstructor) }; +const ClassInfo BooleanConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(BooleanConstructor) }; BooleanConstructor::BooleanConstructor(VM& vm, Structure* structure) : InternalFunction(vm, structure) diff --git a/Source/JavaScriptCore/runtime/BooleanObject.cpp b/Source/JavaScriptCore/runtime/BooleanObject.cpp index 28cad6ae7..2c6092aa3 100644 --- a/Source/JavaScriptCore/runtime/BooleanObject.cpp +++ b/Source/JavaScriptCore/runtime/BooleanObject.cpp @@ -22,13 +22,13 @@ #include "BooleanObject.h" #include "JSScope.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(BooleanObject); -const ClassInfo BooleanObject::s_info = { "Boolean", &JSWrapperObject::s_info, 0, CREATE_METHOD_TABLE(BooleanObject) }; +const ClassInfo BooleanObject::s_info = { "Boolean", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(BooleanObject) }; BooleanObject::BooleanObject(VM& vm, Structure* structure) : JSWrapperObject(vm, structure) diff --git a/Source/JavaScriptCore/runtime/BooleanPrototype.cpp b/Source/JavaScriptCore/runtime/BooleanPrototype.cpp index be737ae5a..c73ead8be 100644 --- a/Source/JavaScriptCore/runtime/BooleanPrototype.cpp +++ b/Source/JavaScriptCore/runtime/BooleanPrototype.cpp @@ -26,7 +26,7 @@ #include "JSFunction.h" #include "JSString.h" #include "ObjectPrototype.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { @@ -39,7 +39,7 @@ static EncodedJSValue JSC_HOST_CALL booleanProtoFuncValueOf(ExecState*); namespace JSC { -const ClassInfo BooleanPrototype::s_info = { "Boolean", &BooleanObject::s_info, &booleanPrototypeTable, CREATE_METHOD_TABLE(BooleanPrototype) }; +const ClassInfo BooleanPrototype::s_info = { "Boolean", &BooleanObject::s_info, 0, ExecState::booleanPrototypeTable, CREATE_METHOD_TABLE(BooleanPrototype) }; /* Source for BooleanPrototype.lut.h @begin booleanPrototypeTable @@ -65,7 +65,7 @@ void BooleanPrototype::finishCreation(VM& vm, JSGlobalObject*) bool BooleanPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot) { - return getStaticFunctionSlot<BooleanObject>(exec, booleanPrototypeTable, jsCast<BooleanPrototype*>(object), propertyName, slot); + return getStaticFunctionSlot<BooleanObject>(exec, ExecState::booleanPrototypeTable(exec->vm()), jsCast<BooleanPrototype*>(object), propertyName, slot); } // ------------------------------ Functions --------------------------- @@ -73,7 +73,7 @@ bool BooleanPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, Pro EncodedJSValue JSC_HOST_CALL booleanProtoFuncToString(ExecState* exec) { VM* vm = &exec->vm(); - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (thisValue == jsBoolean(false)) return JSValue::encode(vm->smallStrings.falseString()); @@ -92,7 +92,7 @@ EncodedJSValue JSC_HOST_CALL booleanProtoFuncToString(ExecState* exec) EncodedJSValue JSC_HOST_CALL booleanProtoFuncValueOf(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (thisValue.isBoolean()) return JSValue::encode(thisValue); diff --git a/Source/JavaScriptCore/runtime/BooleanPrototype.h b/Source/JavaScriptCore/runtime/BooleanPrototype.h index 6d8fc5e81..35ece4bd3 100644 --- a/Source/JavaScriptCore/runtime/BooleanPrototype.h +++ b/Source/JavaScriptCore/runtime/BooleanPrototype.h @@ -28,7 +28,6 @@ namespace JSC { class BooleanPrototype : public BooleanObject { public: typedef BooleanObject Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; static BooleanPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) { @@ -46,6 +45,7 @@ public: protected: void finishCreation(VM&, JSGlobalObject*); + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | BooleanObject::StructureFlags; private: BooleanPrototype(VM&, Structure*); diff --git a/Source/JavaScriptCore/runtime/BundlePath.h b/Source/JavaScriptCore/runtime/BundlePath.h deleted file mode 100644 index c8c694832..000000000 --- a/Source/JavaScriptCore/runtime/BundlePath.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2013, 2014 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 BundlePath_h -#define BundlePath_h - -#include <string> -#include <wtf/text/CString.h> - -namespace JSC { - -const CString& bundlePath(); - -} // namespace JSC - -#endif // BundlePath_h - diff --git a/Source/JavaScriptCore/runtime/Butterfly.h b/Source/JavaScriptCore/runtime/Butterfly.h index 20dccd9b6..04554ab71 100644 --- a/Source/JavaScriptCore/runtime/Butterfly.h +++ b/Source/JavaScriptCore/runtime/Butterfly.h @@ -30,6 +30,7 @@ #include "PropertyOffset.h" #include "PropertyStorage.h" #include <wtf/Noncopyable.h> +#include <wtf/Platform.h> namespace JSC { @@ -157,7 +158,9 @@ public: // 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. - static Butterfly* createOrGrowPropertyStorage(Butterfly*, VM&, JSCell* intendedOwner, Structure*, size_t oldPropertyCapacity, size_t newPropertyCapacity); + Butterfly* growPropertyStorage(VM&, JSCell* intendedOwner, size_t preCapacity, size_t oldPropertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes, size_t newPropertyCapacity); + Butterfly* growPropertyStorage(VM&, JSCell* intendedOwner, Structure* oldStructure, size_t oldPropertyCapacity, size_t newPropertyCapacity); + Butterfly* growPropertyStorage(VM&, JSCell* intendedOwner, Structure* oldStructure, size_t newPropertyCapacity); Butterfly* growArrayRight(VM&, JSCell* intendedOwner, 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&, JSCell* intendedOwner, Structure*, size_t newIndexingPayloadSizeInBytes); Butterfly* resizeArray(VM&, JSCell* intendedOwner, size_t propertyCapacity, bool oldHasIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader, size_t newIndexingPayloadSizeInBytes); diff --git a/Source/JavaScriptCore/runtime/ButterflyInlines.h b/Source/JavaScriptCore/runtime/ButterflyInlines.h index 3fd8dc139..f5439bb02 100644 --- a/Source/JavaScriptCore/runtime/ButterflyInlines.h +++ b/Source/JavaScriptCore/runtime/ButterflyInlines.h @@ -75,25 +75,39 @@ inline void* Butterfly::base(Structure* structure) return base(indexingHeader()->preCapacity(structure), structure->outOfLineCapacity()); } -inline Butterfly* Butterfly::createOrGrowPropertyStorage( - Butterfly* oldButterfly, VM& vm, JSCell* intendedOwner, Structure* structure, size_t oldPropertyCapacity, size_t newPropertyCapacity) +inline Butterfly* Butterfly::growPropertyStorage( + VM& vm, JSCell* intendedOwner, size_t preCapacity, size_t oldPropertyCapacity, + bool hasIndexingHeader, size_t indexingPayloadSizeInBytes, size_t newPropertyCapacity) { RELEASE_ASSERT(newPropertyCapacity > oldPropertyCapacity); - if (!oldButterfly) - return create(vm, intendedOwner, 0, newPropertyCapacity, false, IndexingHeader(), 0); - - size_t preCapacity = oldButterfly->indexingHeader()->preCapacity(structure); - size_t indexingPayloadSizeInBytes = oldButterfly->indexingHeader()->indexingPayloadSizeInBytes(structure); - bool hasIndexingHeader = structure->hasIndexingHeader(intendedOwner); Butterfly* result = createUninitialized( - vm, intendedOwner, preCapacity, newPropertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); + vm, intendedOwner, preCapacity, newPropertyCapacity, hasIndexingHeader, + indexingPayloadSizeInBytes); memcpy( result->propertyStorage() - oldPropertyCapacity, - oldButterfly->propertyStorage() - oldPropertyCapacity, + propertyStorage() - oldPropertyCapacity, totalSize(0, oldPropertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes)); return result; } +inline Butterfly* Butterfly::growPropertyStorage( + VM& vm, JSCell* intendedOwner, Structure* structure, size_t oldPropertyCapacity, + size_t newPropertyCapacity) +{ + return growPropertyStorage( + vm, intendedOwner, indexingHeader()->preCapacity(structure), oldPropertyCapacity, + structure->hasIndexingHeader(intendedOwner), + indexingHeader()->indexingPayloadSizeInBytes(structure), newPropertyCapacity); +} + +inline Butterfly* Butterfly::growPropertyStorage( + VM& vm, JSCell* intendedOwner, Structure* oldStructure, size_t newPropertyCapacity) +{ + return growPropertyStorage( + vm, intendedOwner, oldStructure, oldStructure->outOfLineCapacity(), + newPropertyCapacity); +} + inline Butterfly* Butterfly::createOrGrowArrayRight( Butterfly* oldButterfly, VM& vm, JSCell* intendedOwner, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, @@ -167,7 +181,7 @@ inline Butterfly* Butterfly::resizeArray( inline Butterfly* Butterfly::unshift(Structure* structure, size_t numberOfSlots) { - ASSERT(hasAnyArrayStorage(structure->indexingType())); + ASSERT(hasArrayStorage(structure->indexingType())); ASSERT(numberOfSlots <= indexingHeader()->preCapacity(structure)); unsigned propertyCapacity = structure->outOfLineCapacity(); // FIXME: It would probably be wise to rewrite this as a loop since (1) we know in which @@ -186,7 +200,7 @@ inline Butterfly* Butterfly::unshift(Structure* structure, size_t numberOfSlots) inline Butterfly* Butterfly::shift(Structure* structure, size_t numberOfSlots) { - ASSERT(hasAnyArrayStorage(structure->indexingType())); + ASSERT(hasArrayStorage(structure->indexingType())); unsigned propertyCapacity = structure->outOfLineCapacity(); // FIXME: See comment in unshift(), above. memmove( diff --git a/Source/JavaScriptCore/runtime/CallData.cpp b/Source/JavaScriptCore/runtime/CallData.cpp index 31c28c336..cf0ba7992 100644 --- a/Source/JavaScriptCore/runtime/CallData.cpp +++ b/Source/JavaScriptCore/runtime/CallData.cpp @@ -29,7 +29,7 @@ #include "Executable.h" #include "Interpreter.h" #include "JSFunction.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { @@ -39,16 +39,4 @@ JSValue call(ExecState* exec, JSValue functionObject, CallType callType, const C return exec->interpreter()->executeCall(exec, asObject(functionObject), callType, callData, thisValue, args); } -JSValue call(ExecState* exec, JSValue functionObject, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args, NakedPtr<Exception>& returnedException) -{ - JSValue result = call(exec, functionObject, callType, callData, thisValue, args); - if (exec->hadException()) { - returnedException = exec->exception(); - exec->clearException(); - return jsUndefined(); - } - RELEASE_ASSERT(result); - return result; -} - } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/CallData.h b/Source/JavaScriptCore/runtime/CallData.h index e4a918dec..3bbac734f 100644 --- a/Source/JavaScriptCore/runtime/CallData.h +++ b/Source/JavaScriptCore/runtime/CallData.h @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -30,12 +30,10 @@ #define CallData_h #include "JSCJSValue.h" -#include <wtf/NakedPtr.h> namespace JSC { class ArgList; -class Exception; class ExecState; class FunctionExecutable; class JSObject; @@ -60,7 +58,6 @@ union CallData { }; JS_EXPORT_PRIVATE JSValue call(ExecState*, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&); -JS_EXPORT_PRIVATE JSValue call(ExecState*, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&, NakedPtr<Exception>& returnedException); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ClassInfo.h b/Source/JavaScriptCore/runtime/ClassInfo.h index cb5058c2d..8ff75f4eb 100644 --- a/Source/JavaScriptCore/runtime/ClassInfo.h +++ b/Source/JavaScriptCore/runtime/ClassInfo.h @@ -30,6 +30,7 @@ namespace JSC { +class HashEntry; class JSArrayBufferView; struct HashTable; @@ -82,12 +83,6 @@ struct MethodTable { typedef void (*GetPropertyNamesFunctionPtr)(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); GetPropertyNamesFunctionPtr getPropertyNames; - typedef uint32_t (*GetEnumerableLengthFunctionPtr)(ExecState*, JSObject*); - GetEnumerableLengthFunctionPtr getEnumerableLength; - - GetPropertyNamesFunctionPtr getStructurePropertyNames; - GetPropertyNamesFunctionPtr getGenericPropertyNames; - typedef String (*ClassNameFunctionPtr)(const JSObject*); ClassNameFunctionPtr className; @@ -102,9 +97,6 @@ struct MethodTable { typedef PassRefPtr<ArrayBufferView> (*GetTypedArrayImpl)(JSArrayBufferView*); GetTypedArrayImpl getTypedArrayImpl; - - typedef void (*DumpToStreamFunctionPtr)(const JSCell*, PrintStream&); - DumpToStreamFunctionPtr dumpToStream; }; #define CREATE_MEMBER_CHECKER(member) \ @@ -143,15 +135,11 @@ struct MethodTable { &ClassName::getOwnPropertyNames, \ &ClassName::getOwnNonIndexPropertyNames, \ &ClassName::getPropertyNames, \ - &ClassName::getEnumerableLength, \ - &ClassName::getStructurePropertyNames, \ - &ClassName::getGenericPropertyNames, \ &ClassName::className, \ &ClassName::customHasInstance, \ &ClassName::defineOwnProperty, \ &ClassName::slowDownAndWasteMemory, \ - &ClassName::getTypedArrayImpl, \ - &ClassName::dumpToStream \ + &ClassName::getTypedArrayImpl \ }, \ ClassName::TypedArrayStorageType @@ -163,6 +151,25 @@ struct ClassInfo { // nullptrif there is none. const ClassInfo* parentClass; + // Static hash-table of properties. + // For classes that can be used from multiple threads, it is accessed via a getter function + // that would typically return a pointer to a thread-specific value. + const HashTable* propHashTable(ExecState* exec) const + { + if (classPropHashTableGetterFunction) + return &classPropHashTableGetterFunction(exec->vm()); + + return staticPropHashTable; + } + + const HashTable* propHashTable(VM& vm) const + { + if (classPropHashTableGetterFunction) + return &classPropHashTableGetterFunction(vm); + + return staticPropHashTable; + } + bool isSubClassOf(const ClassInfo* other) const { for (const ClassInfo* ci = this; ci; ci = ci->parentClass) { @@ -175,15 +182,17 @@ struct ClassInfo { bool hasStaticProperties() const { for (const ClassInfo* ci = this; ci; ci = ci->parentClass) { - if (ci->staticPropHashTable) + if (ci->staticPropHashTable || ci->classPropHashTableGetterFunction) return true; } return false; } - bool hasStaticSetterOrReadonlyProperties() const; + bool hasStaticSetterOrReadonlyProperties(VM&) const; const HashTable* staticPropHashTable; + typedef const HashTable& (*ClassPropHashTableGetterFunction)(VM&); + const ClassPropHashTableGetterFunction classPropHashTableGetterFunction; MethodTable methodTable; diff --git a/Source/JavaScriptCore/runtime/ClonedArguments.cpp b/Source/JavaScriptCore/runtime/ClonedArguments.cpp deleted file mode 100644 index 8a740db6d..000000000 --- a/Source/JavaScriptCore/runtime/ClonedArguments.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (C) 2015 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 "ClonedArguments.h" - -#include "GetterSetter.h" -#include "JSCInlines.h" - -namespace JSC { - -STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ClonedArguments); - -const ClassInfo ClonedArguments::s_info = { "Arguments", &Base::s_info, 0, CREATE_METHOD_TABLE(ClonedArguments) }; - -ClonedArguments::ClonedArguments(VM& vm, Structure* structure) - : Base(vm, structure, nullptr) -{ -} - -ClonedArguments* ClonedArguments::createEmpty( - VM& vm, Structure* structure, JSFunction* callee) -{ - ClonedArguments* result = - new (NotNull, allocateCell<ClonedArguments>(vm.heap)) - ClonedArguments(vm, structure); - result->finishCreation(vm); - result->m_callee.set(vm, result, callee); - return result; -} - -ClonedArguments* ClonedArguments::createEmpty(ExecState* exec, JSFunction* callee) -{ - // NB. Some clients might expect that the global object of of this object is the global object - // of the callee. We don't do this for now, but maybe we should. - return createEmpty( - exec->vm(), exec->lexicalGlobalObject()->outOfBandArgumentsStructure(), callee); -} - -ClonedArguments* ClonedArguments::createWithInlineFrame(ExecState* myFrame, ExecState* targetFrame, InlineCallFrame* inlineCallFrame, ArgumentsMode mode) -{ - VM& vm = myFrame->vm(); - - JSFunction* callee; - - if (inlineCallFrame) - callee = jsCast<JSFunction*>(inlineCallFrame->calleeRecovery.recover(targetFrame)); - else - callee = jsCast<JSFunction*>(targetFrame->callee()); - - ClonedArguments* result = createEmpty(myFrame, callee); - - unsigned length = 0; // Initialize because VC needs it. - switch (mode) { - case ArgumentsMode::Cloned: { - if (inlineCallFrame) { - if (inlineCallFrame->argumentCountRegister.isValid()) - length = targetFrame->r(inlineCallFrame->argumentCountRegister).unboxedInt32(); - else - length = inlineCallFrame->arguments.size(); - length--; - - for (unsigned i = length; i--;) - result->putDirectIndex(myFrame, i, inlineCallFrame->arguments[i + 1].recover(targetFrame)); - } else { - length = targetFrame->argumentCount(); - - for (unsigned i = length; i--;) - result->putDirectIndex(myFrame, i, targetFrame->uncheckedArgument(i)); - } - break; - } - - case ArgumentsMode::FakeValues: { - length = 0; - break; - } } - - result->putDirect(vm, vm.propertyNames->length, jsNumber(length), DontEnum); - - return result; -} - -ClonedArguments* ClonedArguments::createWithMachineFrame(ExecState* myFrame, ExecState* targetFrame, ArgumentsMode mode) -{ - return createWithInlineFrame(myFrame, targetFrame, nullptr, mode); -} - -ClonedArguments* ClonedArguments::createByCopyingFrom( - ExecState* exec, Structure* structure, Register* argumentStart, unsigned length, - JSFunction* callee) -{ - VM& vm = exec->vm(); - ClonedArguments* result = createEmpty(vm, structure, callee); - - for (unsigned i = length; i--;) - result->putDirectIndex(exec, i, argumentStart[i].jsValue()); - - result->putDirect(vm, vm.propertyNames->length, jsNumber(length), DontEnum); - return result; -} - -Structure* ClonedArguments::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) -{ - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); -} - -bool ClonedArguments::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName ident, PropertySlot& slot) -{ - ClonedArguments* thisObject = jsCast<ClonedArguments*>(object); - VM& vm = exec->vm(); - - if (ident == vm.propertyNames->callee - || ident == vm.propertyNames->caller - || ident == vm.propertyNames->iteratorSymbol) - thisObject->materializeSpecialsIfNecessary(exec); - - if (Base::getOwnPropertySlot(thisObject, exec, ident, slot)) - return true; - - return false; -} - -void ClonedArguments::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& array, EnumerationMode mode) -{ - ClonedArguments* thisObject = jsCast<ClonedArguments*>(object); - thisObject->materializeSpecialsIfNecessary(exec); - Base::getOwnPropertyNames(thisObject, exec, array, mode); -} - -void ClonedArguments::put(JSCell* cell, ExecState* exec, PropertyName ident, JSValue value, PutPropertySlot& slot) -{ - ClonedArguments* thisObject = jsCast<ClonedArguments*>(cell); - VM& vm = exec->vm(); - - if (ident == vm.propertyNames->callee - || ident == vm.propertyNames->caller - || ident == vm.propertyNames->iteratorSymbol) { - thisObject->materializeSpecialsIfNecessary(exec); - PutPropertySlot dummy = slot; // Shadow the given PutPropertySlot to prevent caching. - Base::put(thisObject, exec, ident, value, dummy); - return; - } - - Base::put(thisObject, exec, ident, value, slot); -} - -bool ClonedArguments::deleteProperty(JSCell* cell, ExecState* exec, PropertyName ident) -{ - ClonedArguments* thisObject = jsCast<ClonedArguments*>(cell); - VM& vm = exec->vm(); - - if (ident == vm.propertyNames->callee - || ident == vm.propertyNames->caller - || ident == vm.propertyNames->iteratorSymbol) - thisObject->materializeSpecialsIfNecessary(exec); - - return Base::deleteProperty(thisObject, exec, ident); -} - -bool ClonedArguments::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName ident, const PropertyDescriptor& descriptor, bool shouldThrow) -{ - ClonedArguments* thisObject = jsCast<ClonedArguments*>(object); - VM& vm = exec->vm(); - - if (ident == vm.propertyNames->callee - || ident == vm.propertyNames->caller - || ident == vm.propertyNames->iteratorSymbol) - thisObject->materializeSpecialsIfNecessary(exec); - - return Base::defineOwnProperty(object, exec, ident, descriptor, shouldThrow); -} - -void ClonedArguments::materializeSpecials(ExecState* exec) -{ - RELEASE_ASSERT(!specialsMaterialized()); - VM& vm = exec->vm(); - - FunctionExecutable* executable = jsCast<FunctionExecutable*>(m_callee->executable()); - bool isStrictMode = executable->isStrictMode(); - - if (isStrictMode) { - putDirectAccessor(exec, vm.propertyNames->callee, globalObject()->throwTypeErrorGetterSetter(vm), DontDelete | DontEnum | Accessor); - putDirectAccessor(exec, vm.propertyNames->caller, globalObject()->throwTypeErrorGetterSetter(vm), DontDelete | DontEnum | Accessor); - } else - putDirect(vm, vm.propertyNames->callee, JSValue(m_callee.get())); - - putDirect(vm, vm.propertyNames->iteratorSymbol, globalObject()->arrayProtoValuesFunction(), DontEnum); - - m_callee.clear(); -} - -void ClonedArguments::materializeSpecialsIfNecessary(ExecState* exec) -{ - if (!specialsMaterialized()) - materializeSpecials(exec); -} - -void ClonedArguments::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - ClonedArguments* thisObject = jsCast<ClonedArguments*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - Base::visitChildren(thisObject, visitor); - visitor.append(&thisObject->m_callee); -} - -} // namespace JSC - diff --git a/Source/JavaScriptCore/runtime/ClonedArguments.h b/Source/JavaScriptCore/runtime/ClonedArguments.h deleted file mode 100644 index 8e713d5c6..000000000 --- a/Source/JavaScriptCore/runtime/ClonedArguments.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2015 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 ClonedArguments_h -#define ClonedArguments_h - -#include "ArgumentsMode.h" -#include "JSObject.h" - -namespace JSC { - -// This is an Arguments-class object that we create when you do function.arguments, or you say -// "arguments" inside a function in strict mode. It behaves almpst entirely like an ordinary -// JavaScript object. All of the arguments values are simply copied from the stack (possibly via -// some sophisticated ValueRecovery's if an optimizing compiler is in play) and the appropriate -// properties of the object are populated. The only reason why we need a special class is to make -// the object claim to be "Arguments" from a toString standpoint, and to avoid materializing the -// caller/callee/@@iterator properties unless someone asks for them. -class ClonedArguments : public JSNonFinalObject { -public: - typedef JSNonFinalObject Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames; - -private: - ClonedArguments(VM&, Structure*); - -public: - static ClonedArguments* createEmpty(VM&, Structure*, JSFunction* callee); - static ClonedArguments* createEmpty(ExecState*, JSFunction* callee); - static ClonedArguments* createWithInlineFrame(ExecState* myFrame, ExecState* targetFrame, InlineCallFrame*, ArgumentsMode); - static ClonedArguments* createWithMachineFrame(ExecState* myFrame, ExecState* targetFrame, ArgumentsMode); - static ClonedArguments* createByCopyingFrom(ExecState*, Structure*, Register* argumentsStart, unsigned length, JSFunction* callee); - - static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype); - - static void visitChildren(JSCell*, SlotVisitor&); - - DECLARE_INFO; - -private: - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); - static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); - static bool deleteProperty(JSCell*, ExecState*, PropertyName); - static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow); - - bool specialsMaterialized() const { return !m_callee; } - void materializeSpecials(ExecState*); - void materializeSpecialsIfNecessary(ExecState*); - - WriteBarrier<JSFunction> m_callee; // Set to nullptr when we materialize all of our special properties. -}; - -} // namespace JSC - -#endif // ClonedArguments_h - diff --git a/Source/JavaScriptCore/runtime/CodeCache.cpp b/Source/JavaScriptCore/runtime/CodeCache.cpp index ab70eabb9..510e383fa 100644 --- a/Source/JavaScriptCore/runtime/CodeCache.cpp +++ b/Source/JavaScriptCore/runtime/CodeCache.cpp @@ -29,7 +29,7 @@ #include "BytecodeGenerator.h" #include "CodeSpecializationKind.h" -#include "JSCInlines.h" +#include "Operations.h" #include "Parser.h" #include "StrongInlines.h" #include "UnlinkedCodeBlock.h" @@ -75,14 +75,13 @@ template <> struct CacheTypes<UnlinkedEvalCodeBlock> { }; template <class UnlinkedCodeBlockType, class ExecutableType> -UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserBuiltinMode builtinMode, - JSParserStrictMode strictMode, ThisTDZMode thisTDZMode, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error, const VariableEnvironment* variablesUnderTDZ) +UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) { - SourceCodeKey key = SourceCodeKey(source, String(), CacheTypes<UnlinkedCodeBlockType>::codeType, builtinMode, strictMode, thisTDZMode); - SourceCodeValue* cache = m_sourceCode.findCacheAndUpdateAge(key); - bool canCache = debuggerMode == DebuggerOff && profilerMode == ProfilerOff && !vm.typeProfiler() && !vm.controlFlowProfiler(); - if (cache && canCache) { - UnlinkedCodeBlockType* unlinkedCodeBlock = jsCast<UnlinkedCodeBlockType*>(cache->cell.get()); + SourceCodeKey key = SourceCodeKey(source, String(), CacheTypes<UnlinkedCodeBlockType>::codeType, strictness); + CodeCacheMap::AddResult addResult = m_sourceCode.add(key, SourceCodeValue()); + bool canCache = debuggerMode == DebuggerOff && profilerMode == ProfilerOff; + if (!addResult.isNewEntry && canCache) { + UnlinkedCodeBlockType* unlinkedCodeBlock = jsCast<UnlinkedCodeBlockType*>(addResult.iterator->value.cell.get()); unsigned firstLine = source.firstLine() + unlinkedCodeBlock->firstLine(); unsigned lineCount = unlinkedCodeBlock->lineCount(); unsigned startColumn = unlinkedCodeBlock->startColumn() + source.startColumn(); @@ -93,91 +92,79 @@ UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* exe } typedef typename CacheTypes<UnlinkedCodeBlockType>::RootNode RootNode; - std::unique_ptr<RootNode> rootNode = parse<RootNode>( - &vm, source, Identifier(), builtinMode, strictMode, - SourceParseMode::ProgramMode, error, nullptr, ConstructorKind::None, thisTDZMode); - if (!rootNode) - return nullptr; - - unsigned lineCount = rootNode->lastLine() - rootNode->firstLine(); + RefPtr<RootNode> rootNode = parse<RootNode>(&vm, source, 0, Identifier(), strictness, JSParseProgramCode, error); + if (!rootNode) { + m_sourceCode.remove(addResult.iterator); + return 0; + } + unsigned lineCount = rootNode->lastLine() - rootNode->lineNo(); unsigned startColumn = rootNode->startColumn() + 1; bool endColumnIsOnStartLine = !lineCount; unsigned unlinkedEndColumn = rootNode->endColumn(); unsigned endColumn = unlinkedEndColumn + (endColumnIsOnStartLine ? startColumn : 1); - executable->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->firstLine(), rootNode->lastLine(), startColumn, endColumn); + executable->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->lineNo(), rootNode->lastLine(), startColumn, endColumn); UnlinkedCodeBlockType* unlinkedCodeBlock = UnlinkedCodeBlockType::create(&vm, executable->executableInfo()); - unlinkedCodeBlock->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->firstLine() - source.firstLine(), lineCount, unlinkedEndColumn); + unlinkedCodeBlock->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->lineNo() - source.firstLine(), lineCount, unlinkedEndColumn); - auto generator = std::make_unique<BytecodeGenerator>(vm, rootNode.get(), unlinkedCodeBlock, debuggerMode, profilerMode, variablesUnderTDZ); + OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(vm, rootNode.get(), unlinkedCodeBlock, debuggerMode, profilerMode))); error = generator->generate(); - if (error.isValid()) - return nullptr; + rootNode->destroyData(); + if (error.m_type != ParserError::ErrorNone) { + m_sourceCode.remove(addResult.iterator); + return 0; + } - if (!canCache) + if (!canCache) { + m_sourceCode.remove(addResult.iterator); return unlinkedCodeBlock; + } - m_sourceCode.addCache(key, SourceCodeValue(vm, unlinkedCodeBlock, m_sourceCode.age())); + addResult.iterator->value = SourceCodeValue(vm, unlinkedCodeBlock, m_sourceCode.age()); return unlinkedCodeBlock; } -UnlinkedProgramCodeBlock* CodeCache::getProgramCodeBlock(VM& vm, ProgramExecutable* executable, const SourceCode& source, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) +UnlinkedProgramCodeBlock* CodeCache::getProgramCodeBlock(VM& vm, ProgramExecutable* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) { - VariableEnvironment emptyParentTDZVariables; - return getGlobalCodeBlock<UnlinkedProgramCodeBlock>(vm, executable, source, builtinMode, strictMode, ThisTDZMode::CheckIfNeeded, debuggerMode, profilerMode, error, &emptyParentTDZVariables); + return getGlobalCodeBlock<UnlinkedProgramCodeBlock>(vm, executable, source, strictness, debuggerMode, profilerMode, error); } -UnlinkedEvalCodeBlock* CodeCache::getEvalCodeBlock(VM& vm, EvalExecutable* executable, const SourceCode& source, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, ThisTDZMode thisTDZMode, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error, const VariableEnvironment* variablesUnderTDZ) +UnlinkedEvalCodeBlock* CodeCache::getEvalCodeBlock(VM& vm, EvalExecutable* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) { - return getGlobalCodeBlock<UnlinkedEvalCodeBlock>(vm, executable, source, builtinMode, strictMode, thisTDZMode, debuggerMode, profilerMode, error, variablesUnderTDZ); + return getGlobalCodeBlock<UnlinkedEvalCodeBlock>(vm, executable, source, strictness, debuggerMode, profilerMode, error); } -// FIXME: There's no need to add the function's name to the key here. It's already in the source code. UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(VM& vm, const Identifier& name, const SourceCode& source, ParserError& error) { - SourceCodeKey key = SourceCodeKey( - source, name.string(), SourceCodeKey::FunctionType, - JSParserBuiltinMode::NotBuiltin, - JSParserStrictMode::NotStrict); - SourceCodeValue* cache = m_sourceCode.findCacheAndUpdateAge(key); - if (cache) - return jsCast<UnlinkedFunctionExecutable*>(cache->cell.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()); JSTextPosition positionBeforeLastNewline; - std::unique_ptr<ProgramNode> program = parse<ProgramNode>( - &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin, - JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, - error, &positionBeforeLastNewline); + RefPtr<ProgramNode> program = parse<ProgramNode>(&vm, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error, &positionBeforeLastNewline); if (!program) { - RELEASE_ASSERT(error.isValid()); - return nullptr; + ASSERT(error.m_type != ParserError::ErrorNone); + m_sourceCode.remove(addResult.iterator); + return 0; } - // This function assumes an input string that would result in a single function declaration. - StatementNode* statement = program->singleStatement(); - ASSERT(statement); - ASSERT(statement->isBlock()); - if (!statement || !statement->isBlock()) - return nullptr; - - StatementNode* funcDecl = static_cast<BlockNode*>(statement)->singleStatement(); - ASSERT(funcDecl); - ASSERT(funcDecl->isFuncDeclNode()); - if (!funcDecl || !funcDecl->isFuncDeclNode()) - return nullptr; - - FunctionMetadataNode* metadata = static_cast<FuncDeclNode*>(funcDecl)->metadata(); - ASSERT(metadata); - if (!metadata) - return nullptr; - - metadata->setEndPosition(positionBeforeLastNewline); - // The Function constructor only has access to global variables, so no variables will be under TDZ. - VariableEnvironment emptyTDZVariables; - UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, UnlinkedNormalFunction, ConstructAbility::CanConstruct, emptyTDZVariables); + // This function assumes an input string that would result in a single anonymous function expression. + StatementNode* exprStatement = program->singleStatement(); + ASSERT(exprStatement); + ASSERT(exprStatement->isExprStatement()); + ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr(); + ASSERT(funcExpr); + RELEASE_ASSERT(funcExpr->isFuncExprNode()); + FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body(); + body->setEndPosition(positionBeforeLastNewline); + ASSERT(body); + ASSERT(body->ident().isNull()); + + UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, body, true); functionExecutable->m_nameValue.set(vm, functionExecutable, jsString(&vm, name.string())); - m_sourceCode.addCache(key, SourceCodeValue(vm, functionExecutable, m_sourceCode.age())); + addResult.iterator->value = SourceCodeValue(vm, functionExecutable, m_sourceCode.age()); return functionExecutable; } diff --git a/Source/JavaScriptCore/runtime/CodeCache.h b/Source/JavaScriptCore/runtime/CodeCache.h index af7dac7e4..f3ff7478d 100644 --- a/Source/JavaScriptCore/runtime/CodeCache.h +++ b/Source/JavaScriptCore/runtime/CodeCache.h @@ -30,20 +30,19 @@ #include "ParserModes.h" #include "SourceCode.h" #include "Strong.h" -#include "VariableEnvironment.h" #include "WeakRandom.h" #include <wtf/CurrentTime.h> #include <wtf/Forward.h> +#include <wtf/PassOwnPtr.h> #include <wtf/RandomNumber.h> #include <wtf/text/WTFString.h> namespace JSC { class EvalExecutable; -class FunctionMetadataNode; +class FunctionBodyNode; class Identifier; class JSScope; -class ParserError; class ProgramExecutable; class UnlinkedCodeBlock; class UnlinkedEvalCodeBlock; @@ -51,6 +50,7 @@ class UnlinkedFunctionCodeBlock; class UnlinkedFunctionExecutable; class UnlinkedProgramCodeBlock; class VM; +struct ParserError; class SourceCode; class SourceProvider; @@ -62,15 +62,10 @@ public: { } - SourceCodeKey(const SourceCode& sourceCode, const String& name, CodeType codeType, JSParserBuiltinMode builtinMode, - JSParserStrictMode strictMode, ThisTDZMode thisTDZMode = ThisTDZMode::CheckIfNeeded) + SourceCodeKey(const SourceCode& sourceCode, const String& name, CodeType codeType, JSParserStrictness jsParserStrictness) : m_sourceCode(sourceCode) , m_name(name) - , m_flags( - (static_cast<unsigned>(codeType) << 3) - | (static_cast<unsigned>(builtinMode) << 2) - | (static_cast<unsigned>(strictMode) << 1) - | static_cast<unsigned>(thisTDZMode)) + , m_flags((codeType << 1) | jsParserStrictness) , m_hash(string().impl()->hash()) { } @@ -150,15 +145,18 @@ public: { } - SourceCodeValue* findCacheAndUpdateAge(const SourceCodeKey& key) + AddResult add(const SourceCodeKey& key, const SourceCodeValue& value) { prune(); - iterator findResult = m_map.find(key); - if (findResult == m_map.end()) - return nullptr; + 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 - findResult->value.age; + 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, @@ -173,20 +171,7 @@ public: m_capacity = m_minCapacity; } - findResult->value.age = m_age; - m_age += key.length(); - - return &findResult->value; - } - - AddResult addCache(const SourceCodeKey& key, const SourceCodeValue& value) - { - prune(); - - AddResult addResult = m_map.add(key, value); - ASSERT(addResult.isNewEntry); - - m_size += key.length(); + addResult.iterator->value.age = m_age; m_age += key.length(); return addResult; } @@ -250,14 +235,13 @@ private: // Caches top-level code such as <script>, eval(), new Function, and JSEvaluateScript(). class CodeCache { - WTF_MAKE_FAST_ALLOCATED; public: - CodeCache(); - ~CodeCache(); + static PassOwnPtr<CodeCache> create() { return adoptPtr(new CodeCache); } - UnlinkedProgramCodeBlock* getProgramCodeBlock(VM&, ProgramExecutable*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, DebuggerMode, ProfilerMode, ParserError&); - UnlinkedEvalCodeBlock* getEvalCodeBlock(VM&, EvalExecutable*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, ThisTDZMode, DebuggerMode, ProfilerMode, ParserError&, const VariableEnvironment*); + UnlinkedProgramCodeBlock* getProgramCodeBlock(VM&, ProgramExecutable*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&); + UnlinkedEvalCodeBlock* getEvalCodeBlock(VM&, EvalExecutable*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&); UnlinkedFunctionExecutable* getFunctionExecutableFromGlobalCode(VM&, const Identifier&, const SourceCode&, ParserError&); + ~CodeCache(); void clear() { @@ -265,8 +249,10 @@ public: } private: + CodeCache(); + template <class UnlinkedCodeBlockType, class ExecutableType> - UnlinkedCodeBlockType* getGlobalCodeBlock(VM&, ExecutableType*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, ThisTDZMode, DebuggerMode, ProfilerMode, ParserError&, const VariableEnvironment*); + UnlinkedCodeBlockType* getGlobalCodeBlock(VM&, ExecutableType*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&); CodeCacheMap m_sourceCode; }; diff --git a/Source/JavaScriptCore/runtime/CommonIdentifiers.cpp b/Source/JavaScriptCore/runtime/CommonIdentifiers.cpp index fc6e62ca0..3f5c645c0 100644 --- a/Source/JavaScriptCore/runtime/CommonIdentifiers.cpp +++ b/Source/JavaScriptCore/runtime/CommonIdentifiers.cpp @@ -21,62 +21,25 @@ #include "config.h" #include "CommonIdentifiers.h" -#include "BuiltinNames.h" -#include "IdentifierInlines.h" -#include "JSCBuiltins.h" #include "PrivateName.h" namespace JSC { -#define INITIALIZE_PROPERTY_NAME(name) , name(Identifier::fromString(vm, #name)) -#define INITIALIZE_KEYWORD(name) , name##Keyword(Identifier::fromString(vm, #name)) -#define INITIALIZE_PRIVATE_NAME(name) , name##PrivateName(m_builtinNames->name##PrivateName()) -#define INITIALIZE_SYMBOL(name) , name##Symbol(m_builtinNames->name##Symbol()) +#define INITIALIZE_PROPERTY_NAME(name) , name(vm, #name) +#define INITIALIZE_KEYWORD(name) , name##Keyword(vm, #name) +#define INITIALIZE_PRIVATE_NAME(name) , name##PrivateName(Identifier::from(PrivateName())) CommonIdentifiers::CommonIdentifiers(VM* vm) : nullIdentifier() , emptyIdentifier(Identifier::EmptyIdentifier) - , underscoreProto(Identifier::fromString(vm, "__proto__")) - , thisIdentifier(Identifier::fromString(vm, "this")) - , useStrictIdentifier(Identifier::fromString(vm, "use strict")) - , timesIdentifier(Identifier::fromString(vm, "*")) - , m_builtinNames(new BuiltinNames(vm, this)) + , underscoreProto(vm, "__proto__") + , thisIdentifier(vm, "this") + , useStrictIdentifier(vm, "use strict") + , hasNextIdentifier(vm, "hasNext") JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(INITIALIZE_KEYWORD) JSC_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PROPERTY_NAME) JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PRIVATE_NAME) - JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(INITIALIZE_SYMBOL) - , m_bytecodeIntrinsicRegistry(*this) { } -CommonIdentifiers::~CommonIdentifiers() -{ -} - -bool CommonIdentifiers::isPrivateName(SymbolImpl& uid) const -{ - return m_builtinNames->isPrivateName(uid); -} - -bool CommonIdentifiers::isPrivateName(UniquedStringImpl& uid) const -{ - return m_builtinNames->isPrivateName(uid); -} - -bool CommonIdentifiers::isPrivateName(const Identifier& ident) const -{ - return m_builtinNames->isPrivateName(ident); -} - -const Identifier* CommonIdentifiers::getPrivateName(const Identifier& ident) const -{ - return m_builtinNames->getPrivateName(ident); -} - -Identifier CommonIdentifiers::getPublicName(const Identifier& ident) const -{ - return m_builtinNames->getPublicName(ident); -} - - } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/CommonIdentifiers.h b/Source/JavaScriptCore/runtime/CommonIdentifiers.h index d7ae07795..e8f9ed82b 100644 --- a/Source/JavaScriptCore/runtime/CommonIdentifiers.h +++ b/Source/JavaScriptCore/runtime/CommonIdentifiers.h @@ -21,62 +21,51 @@ #ifndef CommonIdentifiers_h #define CommonIdentifiers_h -#include "BytecodeIntrinsicRegistry.h" #include "Identifier.h" #include <wtf/Noncopyable.h> // 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(ArgumentsIterator) \ macro(Array) \ macro(ArrayBuffer) \ macro(ArrayIterator) \ macro(BYTES_PER_ELEMENT) \ macro(Boolean) \ - macro(Collator) \ macro(Date) \ - macro(DateTimeFormat) \ macro(Error) \ macro(EvalError) \ macro(Function) \ macro(Infinity) \ - macro(Intl) \ macro(JSON) \ macro(Map)\ macro(MapIterator)\ macro(Math) \ macro(NaN) \ macro(Number) \ - macro(NumberFormat) \ macro(Object) \ macro(Promise) \ macro(RangeError) \ macro(ReferenceError) \ - macro(Reflect) \ macro(RegExp) \ macro(Set)\ macro(SetIterator)\ macro(String) \ - macro(Symbol) \ macro(SyntaxError) \ macro(TypeError) \ macro(URIError) \ macro(UTC) \ macro(WeakMap)\ - macro(WeakSet)\ macro(__defineGetter__) \ macro(__defineSetter__) \ macro(__lookupGetter__) \ macro(__lookupSetter__) \ macro(add) \ - macro(additionalJettisonReason) \ macro(anonymous) \ + macro(apply) \ macro(arguments) \ - macro(as) \ - macro(assign) \ - macro(back) \ macro(bind) \ - macro(blur) \ macro(buffer) \ macro(byteLength) \ macro(byteOffset) \ @@ -84,12 +73,11 @@ macro(bytecodeIndex) \ macro(bytecodes) \ macro(bytecodesID) \ + macro(call) \ macro(callee) \ macro(caller) \ + macro(cast) \ macro(clear) \ - macro(close) \ - macro(closed) \ - macro(column) \ macro(compilationKind) \ macro(compilations) \ macro(compile) \ @@ -97,7 +85,6 @@ macro(constructor) \ macro(count) \ macro(counters) \ - macro(defineProperty) \ macro(description) \ macro(descriptions) \ macro(displayName) \ @@ -109,24 +96,17 @@ macro(exec) \ macro(executionCount) \ macro(exitKind) \ - macro(flags) \ - macro(focus) \ macro(forEach) \ - macro(forward) \ - macro(from) \ macro(fromCharCode) \ macro(get) \ macro(global) \ - macro(go) \ macro(has) \ macro(hasOwnProperty) \ macro(hash) \ macro(header) \ - macro(href) \ macro(id) \ macro(ignoreCase) \ macro(index) \ - macro(indexedDB) \ macro(inferredName) \ macro(input) \ macro(instructionCount) \ @@ -134,12 +114,10 @@ macro(isPrototypeOf) \ macro(isView) \ macro(isWatchpoint) \ - macro(jettisonReason) \ macro(join) \ macro(keys) \ macro(lastIndex) \ macro(length) \ - macro(line) \ macro(message) \ macro(multiline) \ macro(name) \ @@ -154,25 +132,16 @@ macro(osrExitSites) \ macro(osrExits) \ macro(parse) \ - macro(parseInt) \ - macro(postMessage) \ macro(profiledBytecodes) \ macro(propertyIsEnumerable) \ macro(prototype) \ - macro(raw) \ - macro(reload) \ - macro(replace) \ - macro(resolve) \ macro(set) \ - macro(showModalDialog) \ macro(size) \ macro(slice) \ macro(source) \ - macro(sourceURL) \ macro(sourceCode) \ macro(stack) \ macro(subarray) \ - macro(target) \ macro(test) \ macro(then) \ macro(toExponential) \ @@ -183,10 +152,8 @@ macro(toPrecision) \ macro(toString) \ macro(value) \ - macro(valueOf) \ macro(values) \ - macro(webkit) \ - macro(webkitIndexedDB) \ + macro(valueOf) \ macro(window) \ macro(writable) @@ -238,95 +205,34 @@ macro(with) \ macro(yield) -#define JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL_NOT_IMPLEMENTED_YET(macro)\ - macro(hasInstance) \ - macro(isConcatSpreadable) \ - macro(match) \ - macro(replace) \ - macro(search) \ - macro(species) \ - macro(split) \ - macro(toPrimitive) \ - macro(toStringTag) - -#define JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(macro) \ - macro(iterator) \ - macro(unscopables) - -#define JSC_COMMON_BYTECODE_INTRINSICS_EACH_NAME(macro) \ - macro(putByValDirect) \ - macro(toString) - #define JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(macro) \ - JSC_COMMON_BYTECODE_INTRINSICS_EACH_NAME(macro) \ - macro(iteratedObject) \ - macro(arrayIteratorNextIndex) \ - macro(arrayIterationKind) \ - macro(arrayIterationKindKey) \ - macro(arrayIterationKindValue) \ - macro(arrayIterationKindKeyValue) \ - macro(charCodeAt) \ - macro(iteratedString) \ - macro(stringIteratorNextIndex) \ + macro(iterator) \ + macro(iteratorNext) \ + macro(resolve) \ + macro(reject) \ macro(promise) \ macro(fulfillmentHandler) \ macro(rejectionHandler) \ macro(index) \ macro(values) \ macro(deferred) \ - macro(countdownHolder) \ - macro(Object) \ - macro(ownEnumerablePropertyKeys) \ - macro(Number) \ - macro(Array) \ - macro(String) \ - macro(Promise) \ - macro(abs) \ - macro(floor) \ - macro(isFinite) \ - macro(getPrototypeOf) \ - macro(getOwnPropertyNames) \ - macro(TypeError) \ - macro(undefined) \ - macro(BuiltinLog) \ - macro(homeObject) \ - macro(getTemplateObject) \ - macro(enqueueJob) \ - macro(handler) \ - macro(promiseState) \ - macro(promisePending) \ - macro(promiseFulfilled) \ - macro(promiseRejected) \ - macro(promiseFulfillReactions) \ - macro(promiseRejectReactions) \ - macro(promiseResult) \ - macro(capabilities) \ - macro(starDefault) \ - + macro(countdownHolder) namespace JSC { - - class BuiltinNames; - + class CommonIdentifiers { WTF_MAKE_NONCOPYABLE(CommonIdentifiers); WTF_MAKE_FAST_ALLOCATED; private: CommonIdentifiers(VM*); - ~CommonIdentifiers(); friend class VM; - + public: - const BuiltinNames& builtinNames() const { return *m_builtinNames; } const Identifier nullIdentifier; const Identifier emptyIdentifier; const Identifier underscoreProto; const Identifier thisIdentifier; const Identifier useStrictIdentifier; - const Identifier timesIdentifier; - private: - std::unique_ptr<BuiltinNames> m_builtinNames; - - public: + const Identifier hasNextIdentifier; #define JSC_IDENTIFIER_DECLARE_KEYWORD_NAME_GLOBAL(name) const Identifier name##Keyword; JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(JSC_IDENTIFIER_DECLARE_KEYWORD_NAME_GLOBAL) @@ -339,22 +245,6 @@ namespace JSC { #define JSC_IDENTIFIER_DECLARE_PRIVATE_PROPERTY_NAME_GLOBAL(name) const Identifier name##PrivateName; JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(JSC_IDENTIFIER_DECLARE_PRIVATE_PROPERTY_NAME_GLOBAL) #undef JSC_IDENTIFIER_DECLARE_PRIVATE_PROPERTY_NAME_GLOBAL - -#define JSC_IDENTIFIER_DECLARE_PRIVATE_WELL_KNOWN_SYMBOL_GLOBAL(name) const Identifier name##Symbol; - JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(JSC_IDENTIFIER_DECLARE_PRIVATE_WELL_KNOWN_SYMBOL_GLOBAL) -#undef JSC_IDENTIFIER_DECLARE_PRIVATE_WELL_KNOWN_SYMBOL_GLOBAL - - bool isPrivateName(SymbolImpl& uid) const; - bool isPrivateName(UniquedStringImpl& uid) const; - bool isPrivateName(const Identifier&) const; - - const Identifier* getPrivateName(const Identifier&) const; - Identifier getPublicName(const Identifier&) const; - - const BytecodeIntrinsicRegistry& bytecodeIntrinsicRegistry() const { return m_bytecodeIntrinsicRegistry; } - - private: - BytecodeIntrinsicRegistry m_bytecodeIntrinsicRegistry; }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp index acbe14629..f6a142e6d 100644 --- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp +++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2015 Apple Inc. All rights reserved. + * Copyright (C) 2011, 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 @@ -25,35 +25,32 @@ #include "config.h" #include "CommonSlowPaths.h" -#include "ArityCheckFailReturnThunks.h" + +#if ENABLE(JIT) || ENABLE(LLINT) + +#include "Arguments.h" #include "ArrayConstructor.h" #include "CallFrame.h" -#include "ClonedArguments.h" #include "CodeProfiling.h" #include "CommonSlowPathsExceptions.h" -#include "DirectArguments.h" -#include "Error.h" -#include "ErrorHandlingScope.h" -#include "ExceptionFuzz.h" #include "GetterSetter.h" #include "HostCallReturnValue.h" #include "Interpreter.h" #include "JIT.h" #include "JITStubs.h" -#include "JSCInlines.h" +#include "JSActivation.h" #include "JSCJSValue.h" #include "JSGlobalObjectFunctions.h" -#include "JSLexicalEnvironment.h" -#include "JSPropertyNameEnumerator.h" +#include "JSNameScope.h" +#include "JSPropertyNameIterator.h" #include "JSString.h" #include "JSWithScope.h" #include "LLIntCommon.h" #include "LLIntExceptions.h" #include "LowLevelInterpreter.h" #include "ObjectConstructor.h" -#include "ScopedArguments.h" +#include "Operations.h" #include "StructureRareDataInlines.h" -#include "TypeProfilerLog.h" #include <wtf/StringPrintStream.h> namespace JSC { @@ -73,7 +70,11 @@ namespace JSC { } while (false) #endif +#if ENABLE(LLINT) #define RETURN_TO_THROW(exec, pc) pc = LLInt::returnToThrow(exec) +#else +#define RETURN_TO_THROW(exec, pc) +#endif #define BEGIN() \ BEGIN_NO_SET_PC(); \ @@ -95,7 +96,6 @@ namespace JSC { } while (false) #define CHECK_EXCEPTION() do { \ - doExceptionFuzzingIfEnabled(exec, "CommonSlowPaths", pc); \ if (UNLIKELY(vm.exception())) { \ RETURN_TO_THROW(exec, pc); \ END_IMPL(); \ @@ -161,67 +161,53 @@ namespace JSC { CALL_END_IMPL(crExec, crCallTarget); \ } while (false) -static CommonSlowPaths::ArityCheckData* setupArityCheckData(VM& vm, int slotsToAdd) -{ - CommonSlowPaths::ArityCheckData* result = vm.arityCheckData.get(); - result->paddedStackSpace = slotsToAdd; -#if ENABLE(JIT) - if (vm.canUseJIT()) { - result->thunkToCall = vm.getCTIStub(arityFixupGenerator).code().executableAddress(); - result->returnPC = vm.arityCheckFailReturnThunks->returnPCFor(vm, slotsToAdd * stackAlignmentRegisters()).executableAddress(); - } else -#endif - { - result->thunkToCall = 0; - result->returnPC = 0; - } - return result; -} - SLOW_PATH_DECL(slow_path_call_arityCheck) { BEGIN(); - int slotsToAdd = CommonSlowPaths::arityCheckFor(exec, &vm.interpreter->stack(), CodeForCall); - if (slotsToAdd < 0) { + int SlotsToAdd = CommonSlowPaths::arityCheckFor(exec, &vm.interpreter->stack(), CodeForCall); + if (SlotsToAdd < 0) { exec = exec->callerFrame(); - ErrorHandlingScope errorScope(exec->vm()); CommonSlowPaths::interpreterThrowInCaller(exec, createStackOverflowError(exec)); RETURN_TWO(bitwise_cast<void*>(static_cast<uintptr_t>(1)), exec); } - RETURN_TWO(0, setupArityCheckData(vm, slotsToAdd)); + RETURN_TWO(0, reinterpret_cast<ExecState*>(SlotsToAdd)); } SLOW_PATH_DECL(slow_path_construct_arityCheck) { BEGIN(); - int slotsToAdd = CommonSlowPaths::arityCheckFor(exec, &vm.interpreter->stack(), CodeForConstruct); - if (slotsToAdd < 0) { + int SlotsToAdd = CommonSlowPaths::arityCheckFor(exec, &vm.interpreter->stack(), CodeForConstruct); + if (SlotsToAdd < 0) { exec = exec->callerFrame(); - ErrorHandlingScope errorScope(exec->vm()); CommonSlowPaths::interpreterThrowInCaller(exec, createStackOverflowError(exec)); RETURN_TWO(bitwise_cast<void*>(static_cast<uintptr_t>(1)), exec); } - RETURN_TWO(0, setupArityCheckData(vm, slotsToAdd)); + RETURN_TWO(0, reinterpret_cast<ExecState*>(SlotsToAdd)); } -SLOW_PATH_DECL(slow_path_create_direct_arguments) +SLOW_PATH_DECL(slow_path_touch_entry) { BEGIN(); - RETURN(DirectArguments::createByCopying(exec)); + exec->codeBlock()->symbolTable()->m_functionEnteredOnce.touch(); + END(); } -SLOW_PATH_DECL(slow_path_create_scoped_arguments) +SLOW_PATH_DECL(slow_path_get_callee) { BEGIN(); - JSLexicalEnvironment* scope = jsCast<JSLexicalEnvironment*>(OP(2).jsValue()); - ScopedArgumentsTable* table = scope->symbolTable()->arguments(); - RETURN(ScopedArguments::createByCopying(exec, table, scope)); + JSFunction* callee = jsCast<JSFunction*>(exec->callee()); + pc[2].u.jsCell.set(exec->vm(), exec->codeBlock()->ownerExecutable(), callee); + RETURN(callee); } -SLOW_PATH_DECL(slow_path_create_out_of_band_arguments) +SLOW_PATH_DECL(slow_path_create_arguments) { BEGIN(); - RETURN(ClonedArguments::createWithMachineFrame(exec, exec, ArgumentsMode::Cloned)); + JSValue arguments = JSValue(Arguments::create(vm, exec)); + CHECK_EXCEPTION(); + exec->uncheckedR(pc[1].u.operand) = arguments; + exec->uncheckedR(unmodifiedArgumentsRegister(VirtualRegister(pc[1].u.operand)).offset()) = arguments; + END(); } SLOW_PATH_DECL(slow_path_create_this) @@ -234,14 +220,8 @@ SLOW_PATH_DECL(slow_path_create_this) ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS); #endif - auto& cacheWriteBarrier = pc[4].u.jsCell; - if (!cacheWriteBarrier) - cacheWriteBarrier.set(exec->vm(), exec->codeBlock()->ownerExecutable(), constructor); - else if (cacheWriteBarrier.unvalidatedGet() != JSCell::seenMultipleCalleeObjects() && cacheWriteBarrier.get() != constructor) - cacheWriteBarrier.setWithoutWriteBarrier(JSCell::seenMultipleCalleeObjects()); - size_t inlineCapacity = pc[3].u.operand; - Structure* structure = constructor->rareData(exec, inlineCapacity)->allocationProfile()->structure(); + Structure* structure = constructor->allocationProfile(exec, inlineCapacity)->structure(); RETURN(constructEmptyObject(exec, structure)); } @@ -249,25 +229,34 @@ SLOW_PATH_DECL(slow_path_to_this) { BEGIN(); JSValue v1 = OP(1).jsValue(); - if (v1.isCell()) { - Structure* myStructure = v1.asCell()->structure(vm); - Structure* otherStructure = pc[2].u.structure.get(); - if (myStructure != otherStructure) { - if (otherStructure) - pc[3].u.toThisStatus = ToThisConflicted; - pc[2].u.structure.set(vm, exec->codeBlock()->ownerExecutable(), myStructure); - } - } else { - pc[3].u.toThisStatus = ToThisConflicted; + if (v1.isCell()) + pc[2].u.structure.set(exec->vm(), exec->codeBlock()->ownerExecutable(), v1.asCell()->structure()); + else pc[2].u.structure.clear(); - } RETURN(v1.toThis(exec, exec->codeBlock()->isStrictMode() ? StrictMode : NotStrictMode)); } -SLOW_PATH_DECL(slow_path_throw_tdz_error) +SLOW_PATH_DECL(slow_path_captured_mov) +{ + BEGIN(); + JSValue value = OP_C(2).jsValue(); + if (VariableWatchpointSet* set = pc[3].u.watchpointSet) + set->notifyWrite(value); + RETURN(value); +} + +SLOW_PATH_DECL(slow_path_new_captured_func) { BEGIN(); - THROW(createTDZError(exec)); + CodeBlock* codeBlock = exec->codeBlock(); + ASSERT( + codeBlock->codeType() != FunctionCode + || !codeBlock->needsFullScopeChain() + || exec->uncheckedR(codeBlock->activationRegister().offset()).jsValue()); + JSValue value = JSFunction::create(vm, codeBlock->functionDecl(pc[2].u.operand), exec->scope()); + if (VariableWatchpointSet* set = pc[3].u.watchpointSet) + set->notifyWrite(value); + RETURN(value); } SLOW_PATH_DECL(slow_path_not) @@ -342,12 +331,6 @@ SLOW_PATH_DECL(slow_path_to_number) RETURN(jsNumber(OP_C(2).jsValue().toNumber(exec))); } -SLOW_PATH_DECL(slow_path_to_string) -{ - BEGIN(); - RETURN(OP_C(2).jsValue().toString(exec)); -} - SLOW_PATH_DECL(slow_path_negate) { BEGIN(); @@ -466,10 +449,10 @@ SLOW_PATH_DECL(slow_path_typeof) RETURN(jsTypeStringForValue(exec, OP_C(2).jsValue())); } -SLOW_PATH_DECL(slow_path_is_object_or_null) +SLOW_PATH_DECL(slow_path_is_object) { BEGIN(); - RETURN(jsBoolean(jsIsObjectTypeOrNull(exec, OP_C(2).jsValue()))); + RETURN(jsBoolean(jsIsObjectType(exec, OP_C(2).jsValue()))); } SLOW_PATH_DECL(slow_path_is_function) @@ -497,9 +480,11 @@ SLOW_PATH_DECL(slow_path_del_by_val) uint32_t i; if (subscript.getUInt32(i)) couldDelete = baseObject->methodTable()->deletePropertyByIndex(baseObject, exec, i); + else if (isName(subscript)) + couldDelete = baseObject->methodTable()->deleteProperty(baseObject, exec, jsCast<NameInstance*>(subscript.asCell())->privateName()); else { CHECK_EXCEPTION(); - auto property = subscript.toPropertyKey(exec); + Identifier property(exec, subscript.toString(exec)->value(exec)); CHECK_EXCEPTION(); couldDelete = baseObject->methodTable()->deleteProperty(baseObject, exec, property); } @@ -530,134 +515,6 @@ SLOW_PATH_DECL(slow_path_enter) END(); } -SLOW_PATH_DECL(slow_path_get_enumerable_length) -{ - BEGIN(); - JSValue enumeratorValue = OP(2).jsValue(); - if (enumeratorValue.isUndefinedOrNull()) - RETURN(jsNumber(0)); - - JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(enumeratorValue.asCell()); - - RETURN(jsNumber(enumerator->indexedLength())); -} - -SLOW_PATH_DECL(slow_path_has_indexed_property) -{ - BEGIN(); - JSObject* base = OP(2).jsValue().toObject(exec); - JSValue property = OP(3).jsValue(); - pc[4].u.arrayProfile->observeStructure(base->structure(vm)); - ASSERT(property.isUInt32()); - RETURN(jsBoolean(base->hasProperty(exec, property.asUInt32()))); -} - -SLOW_PATH_DECL(slow_path_has_structure_property) -{ - BEGIN(); - JSObject* base = OP(2).jsValue().toObject(exec); - JSValue property = OP(3).jsValue(); - ASSERT(property.isString()); - JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(OP(4).jsValue().asCell()); - if (base->structure(vm)->id() == enumerator->cachedStructureID()) - RETURN(jsBoolean(true)); - RETURN(jsBoolean(base->hasProperty(exec, asString(property.asCell())->toIdentifier(exec)))); -} - -SLOW_PATH_DECL(slow_path_has_generic_property) -{ - BEGIN(); - JSObject* base = OP(2).jsValue().toObject(exec); - JSValue property = OP(3).jsValue(); - bool result; - if (property.isString()) - result = base->hasProperty(exec, asString(property.asCell())->toIdentifier(exec)); - else { - ASSERT(property.isUInt32()); - result = base->hasProperty(exec, property.asUInt32()); - } - RETURN(jsBoolean(result)); -} - -SLOW_PATH_DECL(slow_path_get_direct_pname) -{ - BEGIN(); - JSValue baseValue = OP_C(2).jsValue(); - JSValue property = OP(3).jsValue(); - ASSERT(property.isString()); - RETURN(baseValue.get(exec, asString(property)->toIdentifier(exec))); -} - -SLOW_PATH_DECL(slow_path_get_property_enumerator) -{ - BEGIN(); - JSValue baseValue = OP(2).jsValue(); - if (baseValue.isUndefinedOrNull()) - RETURN(JSPropertyNameEnumerator::create(vm)); - - JSObject* base = baseValue.toObject(exec); - - RETURN(propertyNameEnumerator(exec, base)); -} - -SLOW_PATH_DECL(slow_path_next_structure_enumerator_pname) -{ - BEGIN(); - JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(OP(2).jsValue().asCell()); - uint32_t index = OP(3).jsValue().asUInt32(); - - JSString* propertyName = nullptr; - if (index < enumerator->endStructurePropertyIndex()) - propertyName = enumerator->propertyNameAtIndex(index); - RETURN(propertyName ? propertyName : jsNull()); -} - -SLOW_PATH_DECL(slow_path_next_generic_enumerator_pname) -{ - BEGIN(); - JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(OP(2).jsValue().asCell()); - uint32_t index = OP(3).jsValue().asUInt32(); - - JSString* propertyName = nullptr; - if (enumerator->endStructurePropertyIndex() <= index && index < enumerator->endGenericPropertyIndex()) - propertyName = enumerator->propertyNameAtIndex(index); - RETURN(propertyName ? propertyName : jsNull()); -} - -SLOW_PATH_DECL(slow_path_to_index_string) -{ - BEGIN(); - RETURN(jsString(exec, Identifier::from(exec, OP(2).jsValue().asUInt32()).string())); -} - -SLOW_PATH_DECL(slow_path_profile_type_clear_log) -{ - BEGIN(); - vm.typeProfilerLog()->processLogEntries(ASCIILiteral("LLInt log full.")); - END(); -} - -SLOW_PATH_DECL(slow_path_create_lexical_environment) -{ - BEGIN(); - int scopeReg = pc[2].u.operand; - JSScope* currentScope = exec->uncheckedR(scopeReg).Register::scope(); - SymbolTable* symbolTable = jsCast<SymbolTable*>(OP_C(3).jsValue()); - JSValue initialValue = OP_C(4).jsValue(); - ASSERT(initialValue == jsUndefined() || initialValue == jsTDZValue()); - JSScope* newScope = JSLexicalEnvironment::create(vm, exec->lexicalGlobalObject(), currentScope, symbolTable, initialValue); - RETURN(newScope); -} - -SLOW_PATH_DECL(slow_path_push_with_scope) -{ - BEGIN(); - JSObject* newScope = OP_C(2).jsValue().toObject(exec); - CHECK_EXCEPTION(); - - int scopeReg = pc[3].u.operand; - JSScope* currentScope = exec->uncheckedR(scopeReg).Register::scope(); - RETURN(JSWithScope::create(exec, newScope, currentScope)); -} - } // namespace JSC + +#endif // ENABLE(JIT) || ENABLE(LLINT) diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.h b/Source/JavaScriptCore/runtime/CommonSlowPaths.h index 067df0c38..cfc8bdbb7 100644 --- a/Source/JavaScriptCore/runtime/CommonSlowPaths.h +++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2011, 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 @@ -30,11 +30,14 @@ #include "CodeSpecializationKind.h" #include "ExceptionHelpers.h" #include "JSStackInlines.h" +#include "NameInstance.h" #include "StackAlignment.h" -#include "Symbol.h" #include "VM.h" +#include <wtf/Platform.h> #include <wtf/StdLibExtras.h> +#if ENABLE(JIT) || ENABLE(LLINT) + namespace JSC { // The purpose of this namespace is to include slow paths that are shared @@ -46,12 +49,6 @@ namespace JSC { namespace CommonSlowPaths { -struct ArityCheckData { - unsigned paddedStackSpace; - void* thunkToCall; - void* returnPC; -}; - ALWAYS_INLINE int arityCheckFor(ExecState* exec, JSStack* stack, CodeSpecializationKind kind) { JSFunction* callee = jsCast<JSFunction*>(exec->callee()); @@ -61,18 +58,24 @@ ALWAYS_INLINE int arityCheckFor(ExecState* exec, JSStack* stack, CodeSpecializat ASSERT(argumentCountIncludingThis < newCodeBlock->numParameters()); int missingArgumentCount = newCodeBlock->numParameters() - argumentCountIncludingThis; - int neededStackSpace = missingArgumentCount + 1; // Allow space to save the original return PC. - int paddedStackSpace = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), neededStackSpace); + int paddedMissingArgumentCount = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), missingArgumentCount); - if (!stack->ensureCapacityFor(exec->registers() - paddedStackSpace)) +#if USE(SEPARATE_C_AND_JS_STACK) + if (!stack->grow(exec->registers() - paddedMissingArgumentCount)) + return -1; +#else + UNUSED_PARAM(stack); + if (!exec->vm().isSafeToRecurse(paddedMissingArgumentCount * sizeof(Register))) return -1; - return paddedStackSpace / stackAlignmentRegisters(); +#endif // USE(SEPARATE_C_AND_JS_STACK) + + return paddedMissingArgumentCount; } inline bool opIn(ExecState* exec, JSValue propName, JSValue baseVal) { if (!baseVal.isObject()) { - exec->vm().throwException(exec, createInvalidInParameterError(exec, baseVal)); + exec->vm().throwException(exec, createInvalidParameterError(exec, "in", baseVal)); return false; } @@ -82,39 +85,15 @@ inline bool opIn(ExecState* exec, JSValue propName, JSValue baseVal) if (propName.getUInt32(i)) return baseObj->hasProperty(exec, i); - auto property = propName.toPropertyKey(exec); + if (isName(propName)) + return baseObj->hasProperty(exec, jsCast<NameInstance*>(propName.asCell())->privateName()); + + Identifier property(exec, propName.toString(exec)->value(exec)); if (exec->vm().exception()) return false; return baseObj->hasProperty(exec, property); } -inline void tryCachePutToScopeGlobal( - ExecState* exec, CodeBlock* codeBlock, Instruction* pc, JSObject* scope, - ResolveModeAndType modeAndType, PutPropertySlot& slot) -{ - // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time. - - if (modeAndType.type() != GlobalProperty && modeAndType.type() != GlobalPropertyWithVarInjectionChecks) - return; - - if (!slot.isCacheablePut() - || slot.base() != scope - || !scope->structure()->propertyAccessesAreCacheable()) - return; - - if (slot.type() == PutPropertySlot::NewProperty) { - // Don't cache if we've done a transition. We want to detect the first replace so that we - // can invalidate the watchpoint. - return; - } - - scope->structure()->didCachePropertyReplacement(exec->vm(), slot.cachedOffset()); - - ConcurrentJITLocker locker(codeBlock->m_lock); - pc[5].u.structure.set(exec->vm(), codeBlock->ownerExecutable(), scope->structure()); - pc[6].u.operand = slot.cachedOffset(); -} - } // namespace CommonSlowPaths class ExecState; @@ -181,14 +160,14 @@ SLOW_PATH_DECL(name) WTF_INTERNAL SLOW_PATH_HIDDEN_DECL(slow_path_call_arityCheck); SLOW_PATH_HIDDEN_DECL(slow_path_construct_arityCheck); -SLOW_PATH_HIDDEN_DECL(slow_path_create_direct_arguments); -SLOW_PATH_HIDDEN_DECL(slow_path_create_scoped_arguments); -SLOW_PATH_HIDDEN_DECL(slow_path_create_out_of_band_arguments); +SLOW_PATH_HIDDEN_DECL(slow_path_touch_entry); +SLOW_PATH_HIDDEN_DECL(slow_path_create_arguments); SLOW_PATH_HIDDEN_DECL(slow_path_create_this); SLOW_PATH_HIDDEN_DECL(slow_path_enter); SLOW_PATH_HIDDEN_DECL(slow_path_get_callee); SLOW_PATH_HIDDEN_DECL(slow_path_to_this); -SLOW_PATH_HIDDEN_DECL(slow_path_throw_tdz_error); +SLOW_PATH_HIDDEN_DECL(slow_path_captured_mov); +SLOW_PATH_HIDDEN_DECL(slow_path_new_captured_func); SLOW_PATH_HIDDEN_DECL(slow_path_not); SLOW_PATH_HIDDEN_DECL(slow_path_eq); SLOW_PATH_HIDDEN_DECL(slow_path_neq); @@ -201,7 +180,6 @@ SLOW_PATH_HIDDEN_DECL(slow_path_greatereq); SLOW_PATH_HIDDEN_DECL(slow_path_inc); SLOW_PATH_HIDDEN_DECL(slow_path_dec); SLOW_PATH_HIDDEN_DECL(slow_path_to_number); -SLOW_PATH_HIDDEN_DECL(slow_path_to_string); SLOW_PATH_HIDDEN_DECL(slow_path_negate); SLOW_PATH_HIDDEN_DECL(slow_path_add); SLOW_PATH_HIDDEN_DECL(slow_path_mul); @@ -217,25 +195,14 @@ SLOW_PATH_HIDDEN_DECL(slow_path_bitor); SLOW_PATH_HIDDEN_DECL(slow_path_bitxor); SLOW_PATH_HIDDEN_DECL(slow_path_typeof); SLOW_PATH_HIDDEN_DECL(slow_path_is_object); -SLOW_PATH_HIDDEN_DECL(slow_path_is_object_or_null); SLOW_PATH_HIDDEN_DECL(slow_path_is_function); SLOW_PATH_HIDDEN_DECL(slow_path_in); SLOW_PATH_HIDDEN_DECL(slow_path_del_by_val); SLOW_PATH_HIDDEN_DECL(slow_path_strcat); SLOW_PATH_HIDDEN_DECL(slow_path_to_primitive); -SLOW_PATH_HIDDEN_DECL(slow_path_get_enumerable_length); -SLOW_PATH_HIDDEN_DECL(slow_path_has_generic_property); -SLOW_PATH_HIDDEN_DECL(slow_path_has_structure_property); -SLOW_PATH_HIDDEN_DECL(slow_path_has_indexed_property); -SLOW_PATH_HIDDEN_DECL(slow_path_get_direct_pname); -SLOW_PATH_HIDDEN_DECL(slow_path_get_property_enumerator); -SLOW_PATH_HIDDEN_DECL(slow_path_next_structure_enumerator_pname); -SLOW_PATH_HIDDEN_DECL(slow_path_next_generic_enumerator_pname); -SLOW_PATH_HIDDEN_DECL(slow_path_to_index_string); -SLOW_PATH_HIDDEN_DECL(slow_path_profile_type_clear_log); -SLOW_PATH_HIDDEN_DECL(slow_path_create_lexical_environment); -SLOW_PATH_HIDDEN_DECL(slow_path_push_with_scope); } // namespace JSC +#endif // ENABLE(JIT) || ENABLE(LLINT) + #endif // CommonSlowPaths_h diff --git a/Source/JavaScriptCore/runtime/CommonSlowPathsExceptions.cpp b/Source/JavaScriptCore/runtime/CommonSlowPathsExceptions.cpp index f586ed089..55334be2f 100644 --- a/Source/JavaScriptCore/runtime/CommonSlowPathsExceptions.cpp +++ b/Source/JavaScriptCore/runtime/CommonSlowPathsExceptions.cpp @@ -30,7 +30,6 @@ #include "CodeBlock.h" #include "JITExceptions.h" #include "LLIntCommon.h" -#include "JSCInlines.h" namespace JSC { namespace CommonSlowPaths { diff --git a/Source/JavaScriptCore/runtime/CommonSlowPathsExceptions.h b/Source/JavaScriptCore/runtime/CommonSlowPathsExceptions.h index adcbfd47d..25d683c11 100644 --- a/Source/JavaScriptCore/runtime/CommonSlowPathsExceptions.h +++ b/Source/JavaScriptCore/runtime/CommonSlowPathsExceptions.h @@ -26,6 +26,8 @@ #ifndef CommonSlowPathExceptions_h #define CommonSlowPathExceptions_h +#include <wtf/Platform.h> + #include "MacroAssemblerCodeRef.h" namespace JSC { diff --git a/Source/JavaScriptCore/runtime/Completion.cpp b/Source/JavaScriptCore/runtime/Completion.cpp index a3daee603..9d7fd1a74 100644 --- a/Source/JavaScriptCore/runtime/Completion.cpp +++ b/Source/JavaScriptCore/runtime/Completion.cpp @@ -26,13 +26,10 @@ #include "CallFrame.h" #include "CodeProfiling.h" #include "Debugger.h" -#include "Exception.h" #include "Interpreter.h" #include "JSGlobalObject.h" #include "JSLock.h" -#include "JSCInlines.h" -#include "ModuleAnalyzer.h" -#include "ModuleRecord.h" +#include "Operations.h" #include "Parser.h" #include <wtf/WTFThreadData.h> @@ -41,7 +38,7 @@ namespace JSC { bool checkSyntax(ExecState* exec, const SourceCode& source, JSValue* returnedException) { JSLockHolder lock(exec); - RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable()); + RELEASE_ASSERT(exec->vm().identifierTable == wtfThreadData().currentIdentifierTable()); ProgramExecutable* program = ProgramExecutable::create(exec, source); JSObject* error = program->checkSyntax(exec); @@ -57,38 +54,24 @@ bool checkSyntax(ExecState* exec, const SourceCode& source, JSValue* returnedExc bool checkSyntax(VM& vm, const SourceCode& source, ParserError& error) { JSLockHolder lock(vm); - RELEASE_ASSERT(vm.atomicStringTable() == wtfThreadData().atomicStringTable()); - return !!parse<ProgramNode>( - &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin, - JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, error); + RELEASE_ASSERT(vm.identifierTable == wtfThreadData().currentIdentifierTable()); + RefPtr<ProgramNode> programNode = parse<ProgramNode>(&vm, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error); + return programNode; } -bool checkModuleSyntax(VM& vm, const SourceCode& source, ParserError& error) -{ - JSLockHolder lock(vm); - RELEASE_ASSERT(vm.atomicStringTable() == wtfThreadData().atomicStringTable()); - std::unique_ptr<ModuleProgramNode> moduleProgramNode = parse<ModuleProgramNode>( - &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin, - JSParserStrictMode::Strict, SourceParseMode::ModuleAnalyzeMode, error); - if (!moduleProgramNode) - return false; - - ModuleAnalyzer moduleAnalyzer(vm, moduleProgramNode->varDeclarations(), moduleProgramNode->lexicalVariables()); - moduleAnalyzer.analyze(*moduleProgramNode); - return true; -} - -JSValue evaluate(ExecState* exec, const SourceCode& source, JSValue thisValue, NakedPtr<Exception>& returnedException) +JSValue evaluate(ExecState* exec, const SourceCode& source, JSValue thisValue, JSValue* returnedException) { JSLockHolder lock(exec); - RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable()); + RELEASE_ASSERT(exec->vm().identifierTable == wtfThreadData().currentIdentifierTable()); RELEASE_ASSERT(!exec->vm().isCollectorBusy()); CodeProfiling profile(source); ProgramExecutable* program = ProgramExecutable::create(exec, source); if (!program) { - returnedException = exec->vm().exception(); + if (returnedException) + *returnedException = exec->vm().exception(); + exec->vm().clearException(); return jsUndefined(); } @@ -99,7 +82,9 @@ JSValue evaluate(ExecState* exec, const SourceCode& source, JSValue thisValue, N JSValue result = exec->interpreter()->execute(program, exec, thisObj); if (exec->hadException()) { - returnedException = exec->exception(); + if (returnedException) + *returnedException = exec->exception(); + exec->clearException(); return jsUndefined(); } diff --git a/Source/JavaScriptCore/runtime/Completion.h b/Source/JavaScriptCore/runtime/Completion.h index 702ed9fab..78f8ac795 100644 --- a/Source/JavaScriptCore/runtime/Completion.h +++ b/Source/JavaScriptCore/runtime/Completion.h @@ -24,26 +24,18 @@ #define Completion_h #include "JSCJSValue.h" -#include <wtf/NakedPtr.h> namespace JSC { + + struct ParserError; + class ExecState; + class JSScope; + class SourceCode; + class VM; -class Exception; -class ExecState; -class JSScope; -class ParserError; -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 bool checkModuleSyntax(VM&, const SourceCode&, ParserError&); -JS_EXPORT_PRIVATE JSValue evaluate(ExecState*, const SourceCode&, JSValue thisValue, NakedPtr<Exception>& returnedException); -inline JSValue evaluate(ExecState* exec, const SourceCode& sourceCode, JSValue thisValue = JSValue()) -{ - NakedPtr<Exception> unused; - return evaluate(exec, sourceCode, thisValue, unused); -} + 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); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ConcurrentJITLock.h b/Source/JavaScriptCore/runtime/ConcurrentJITLock.h index 9a26876fc..84233d035 100644 --- a/Source/JavaScriptCore/runtime/ConcurrentJITLock.h +++ b/Source/JavaScriptCore/runtime/ConcurrentJITLock.h @@ -27,14 +27,14 @@ #define ConcurrentJITLock_h #include "DeferGC.h" -#include <wtf/Lock.h> +#include <wtf/ByteSpinLock.h> #include <wtf/NoLock.h> namespace JSC { #if ENABLE(CONCURRENT_JIT) -typedef Lock ConcurrentJITLock; -typedef LockHolder ConcurrentJITLockerImpl; +typedef ByteSpinLock ConcurrentJITLock; +typedef ByteSpinLocker ConcurrentJITLockerImpl; #else typedef NoLock ConcurrentJITLock; typedef NoLockLocker ConcurrentJITLockerImpl; diff --git a/Source/JavaScriptCore/runtime/ConsoleClient.cpp b/Source/JavaScriptCore/runtime/ConsoleClient.cpp deleted file mode 100644 index b255aa208..000000000 --- a/Source/JavaScriptCore/runtime/ConsoleClient.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (C) 2013, 2014 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 "ConsoleClient.h" - -#include "ScriptArguments.h" -#include "ScriptCallStack.h" -#include "ScriptCallStackFactory.h" -#include "ScriptValue.h" -#include <wtf/Assertions.h> -#include <wtf/text/CString.h> -#include <wtf/text/StringBuilder.h> -#include <wtf/text/WTFString.h> - -using namespace Inspector; - -namespace JSC { - -static void appendURLAndPosition(StringBuilder& builder, const String& url, unsigned lineNumber, unsigned columnNumber) -{ - if (url.isEmpty()) - return; - - builder.append(url); - - if (lineNumber > 0) { - builder.append(':'); - builder.appendNumber(lineNumber); - } - - if (columnNumber > 0) { - builder.append(':'); - builder.appendNumber(columnNumber); - } -} - -static void appendMessagePrefix(StringBuilder& builder, MessageSource source, MessageType type, MessageLevel level) -{ - const char* sourceString; - switch (source) { - case MessageSource::XML: - sourceString = "XML"; - break; - case MessageSource::JS: - sourceString = "JS"; - break; - case MessageSource::Network: - sourceString = "NETWORK"; - break; - case MessageSource::ConsoleAPI: - sourceString = "CONSOLE"; - break; - case MessageSource::Storage: - sourceString = "STORAGE"; - break; - case MessageSource::AppCache: - sourceString = "APPCACHE"; - break; - case MessageSource::Rendering: - sourceString = "RENDERING"; - break; - case MessageSource::CSS: - sourceString = "CSS"; - break; - case MessageSource::Security: - sourceString = "SECURITY"; - break; - case MessageSource::Other: - sourceString = "OTHER"; - break; - default: - ASSERT_NOT_REACHED(); - sourceString = "UNKNOWN"; - break; - } - - const char* levelString; - switch (level) { - case MessageLevel::Debug: - levelString = "DEBUG"; - break; - case MessageLevel::Log: - levelString = "LOG"; - break; - case MessageLevel::Info: - levelString = "INFO"; - break; - case MessageLevel::Warning: - levelString = "WARN"; - break; - case MessageLevel::Error: - levelString = "ERROR"; - break; - default: - ASSERT_NOT_REACHED(); - levelString = "UNKNOWN"; - break; - } - - if (type == MessageType::Trace) - levelString = "TRACE"; - else if (type == MessageType::Table) - levelString = "TABLE"; - - builder.append(sourceString); - builder.append(' '); - builder.append(levelString); -} - -void ConsoleClient::printConsoleMessage(MessageSource source, MessageType type, MessageLevel level, const String& message, const String& url, unsigned lineNumber, unsigned columnNumber) -{ - StringBuilder builder; - - if (!url.isEmpty()) { - appendURLAndPosition(builder, url, lineNumber, columnNumber); - builder.appendLiteral(": "); - } - - appendMessagePrefix(builder, source, type, level); - builder.append(' '); - builder.append(message); - - WTFLogAlways("%s", builder.toString().utf8().data()); -} - -void ConsoleClient::printConsoleMessageWithArguments(MessageSource source, MessageType type, MessageLevel level, JSC::ExecState* exec, RefPtr<ScriptArguments>&& arguments) -{ - bool isTraceMessage = type == MessageType::Trace; - size_t stackSize = isTraceMessage ? ScriptCallStack::maxCallStackSizeToCapture : 1; - RefPtr<ScriptCallStack> callStack(createScriptCallStackForConsole(exec, stackSize)); - const ScriptCallFrame& lastCaller = callStack->at(0); - - StringBuilder builder; - - if (!lastCaller.sourceURL().isEmpty()) { - appendURLAndPosition(builder, lastCaller.sourceURL(), lastCaller.lineNumber(), lastCaller.columnNumber()); - builder.appendLiteral(": "); - } - - appendMessagePrefix(builder, source, type, level); - for (size_t i = 0; i < arguments->argumentCount(); ++i) { - String argAsString = arguments->argumentAt(i).toString(arguments->globalState()); - builder.append(' '); - builder.append(argAsString.utf8().data()); - } - - WTFLogAlways("%s", builder.toString().utf8().data()); - - if (isTraceMessage) { - for (size_t i = 0; i < callStack->size(); ++i) { - const ScriptCallFrame& callFrame = callStack->at(i); - String functionName = String(callFrame.functionName()); - if (functionName.isEmpty()) - functionName = ASCIILiteral("(unknown)"); - - StringBuilder callFrameBuilder; - callFrameBuilder.appendNumber(static_cast<unsigned long>(i)); - callFrameBuilder.appendLiteral(": "); - callFrameBuilder.append(functionName); - callFrameBuilder.append('('); - appendURLAndPosition(callFrameBuilder, callFrame.sourceURL(), callFrame.lineNumber(), callFrame.columnNumber()); - callFrameBuilder.append(')'); - - WTFLogAlways("%s", callFrameBuilder.toString().utf8().data()); - } - } -} - -void ConsoleClient::internalMessageWithTypeAndLevel(MessageType type, MessageLevel level, JSC::ExecState* exec, RefPtr<ScriptArguments>&& arguments, ArgumentRequirement argumentRequirement) -{ - if (argumentRequirement == ArgumentRequired && !arguments->argumentCount()) - return; - - messageWithTypeAndLevel(type, level, exec, WTF::move(arguments)); -} - -void ConsoleClient::logWithLevel(ExecState* exec, RefPtr<ScriptArguments>&& arguments, MessageLevel level) -{ - internalMessageWithTypeAndLevel(MessageType::Log, level, exec, WTF::move(arguments), ArgumentRequired); -} - -void ConsoleClient::clear(ExecState* exec, RefPtr<ScriptArguments>&& arguments) -{ - internalMessageWithTypeAndLevel(MessageType::Clear, MessageLevel::Log, exec, WTF::move(arguments), ArgumentNotRequired); -} - -void ConsoleClient::dir(ExecState* exec, RefPtr<ScriptArguments>&& arguments) -{ - internalMessageWithTypeAndLevel(MessageType::Dir, MessageLevel::Log, exec, WTF::move(arguments), ArgumentRequired); -} - -void ConsoleClient::dirXML(ExecState* exec, RefPtr<ScriptArguments>&& arguments) -{ - internalMessageWithTypeAndLevel(MessageType::DirXML, MessageLevel::Log, exec, WTF::move(arguments), ArgumentRequired); -} - -void ConsoleClient::table(ExecState* exec, RefPtr<ScriptArguments>&& arguments) -{ - internalMessageWithTypeAndLevel(MessageType::Table, MessageLevel::Log, exec, WTF::move(arguments), ArgumentRequired); -} - -void ConsoleClient::trace(ExecState* exec, RefPtr<ScriptArguments>&& arguments) -{ - internalMessageWithTypeAndLevel(MessageType::Trace, MessageLevel::Log, exec, WTF::move(arguments), ArgumentNotRequired); -} - -void ConsoleClient::assertCondition(ExecState* exec, RefPtr<ScriptArguments>&& arguments, bool condition) -{ - if (condition) - return; - - internalMessageWithTypeAndLevel(MessageType::Assert, MessageLevel::Error, exec, WTF::move(arguments), ArgumentNotRequired); -} - -void ConsoleClient::group(ExecState* exec, RefPtr<ScriptArguments>&& arguments) -{ - internalMessageWithTypeAndLevel(MessageType::StartGroup, MessageLevel::Log, exec, WTF::move(arguments), ArgumentNotRequired); -} - -void ConsoleClient::groupCollapsed(ExecState* exec, RefPtr<ScriptArguments>&& arguments) -{ - internalMessageWithTypeAndLevel(MessageType::StartGroupCollapsed, MessageLevel::Log, exec, WTF::move(arguments), ArgumentNotRequired); -} - -void ConsoleClient::groupEnd(ExecState* exec, RefPtr<ScriptArguments>&& arguments) -{ - internalMessageWithTypeAndLevel(MessageType::EndGroup, MessageLevel::Log, exec, WTF::move(arguments), ArgumentNotRequired); -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ConsoleClient.h b/Source/JavaScriptCore/runtime/ConsoleClient.h deleted file mode 100644 index a16b85bb4..000000000 --- a/Source/JavaScriptCore/runtime/ConsoleClient.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2014 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 ConsoleClient_h -#define ConsoleClient_h - -#include "ConsoleTypes.h" -#include <wtf/Forward.h> - -namespace Inspector { -class ScriptArguments; -} - -namespace JSC { - -class ExecState; - -class ConsoleClient { -public: - virtual ~ConsoleClient() { } - - JS_EXPORT_PRIVATE static void printConsoleMessage(MessageSource, MessageType, MessageLevel, const String& message, const String& url, unsigned lineNumber, unsigned columnNumber); - JS_EXPORT_PRIVATE static void printConsoleMessageWithArguments(MessageSource, MessageType, MessageLevel, JSC::ExecState*, RefPtr<Inspector::ScriptArguments>&&); - - void logWithLevel(ExecState*, RefPtr<Inspector::ScriptArguments>&&, MessageLevel); - void clear(ExecState*, RefPtr<Inspector::ScriptArguments>&&); - void dir(ExecState*, RefPtr<Inspector::ScriptArguments>&&); - void dirXML(ExecState*, RefPtr<Inspector::ScriptArguments>&&); - void table(ExecState*, RefPtr<Inspector::ScriptArguments>&&); - void trace(ExecState*, RefPtr<Inspector::ScriptArguments>&&); - void assertCondition(ExecState*, RefPtr<Inspector::ScriptArguments>&&, bool condition); - void group(ExecState*, RefPtr<Inspector::ScriptArguments>&&); - void groupCollapsed(ExecState*, RefPtr<Inspector::ScriptArguments>&&); - void groupEnd(ExecState*, RefPtr<Inspector::ScriptArguments>&&); - - virtual void messageWithTypeAndLevel(MessageType, MessageLevel, JSC::ExecState*, RefPtr<Inspector::ScriptArguments>&&) = 0; - virtual void count(ExecState*, RefPtr<Inspector::ScriptArguments>&&) = 0; - virtual void profile(ExecState*, const String& title) = 0; - virtual void profileEnd(ExecState*, const String& title) = 0; - virtual void time(ExecState*, const String& title) = 0; - virtual void timeEnd(ExecState*, const String& title) = 0; - virtual void timeStamp(ExecState*, RefPtr<Inspector::ScriptArguments>&&) = 0; - -private: - enum ArgumentRequirement { ArgumentRequired, ArgumentNotRequired }; - void internalMessageWithTypeAndLevel(MessageType, MessageLevel, JSC::ExecState*, RefPtr<Inspector::ScriptArguments>&&, ArgumentRequirement); -}; - -} // namespace JSC - -#endif // ConsoleClient_h diff --git a/Source/JavaScriptCore/runtime/ConsolePrototype.cpp b/Source/JavaScriptCore/runtime/ConsolePrototype.cpp deleted file mode 100644 index 7cad2c9de..000000000 --- a/Source/JavaScriptCore/runtime/ConsolePrototype.cpp +++ /dev/null @@ -1,400 +0,0 @@ -/* - * Copyright (C) 2014 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 "ConsolePrototype.h" - -#include "ConsoleClient.h" -#include "Error.h" -#include "ExceptionHelpers.h" -#include "JSCInlines.h" -#include "JSConsole.h" -#include "ScriptArguments.h" -#include "ScriptCallStackFactory.h" - -namespace JSC { - -const ClassInfo ConsolePrototype::s_info = { "ConsolePrototype", &Base::s_info, 0, CREATE_METHOD_TABLE(ConsolePrototype) }; - -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDebug(ExecState*); -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncError(ExecState*); -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncLog(ExecState*); -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncInfo(ExecState*); -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncWarn(ExecState*); -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncClear(ExecState*); -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDir(ExecState*); -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDirXML(ExecState*); -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTable(ExecState*); -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTrace(ExecState*); -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncAssert(ExecState*); -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncCount(ExecState*); -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncProfile(ExecState*); -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncProfileEnd(ExecState*); -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTime(ExecState*); -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTimeEnd(ExecState*); -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTimeStamp(ExecState*); -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroup(ExecState*); -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroupCollapsed(ExecState*); -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroupEnd(ExecState*); - -void ConsolePrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); - vm.prototypeMap.addPrototype(this); - - // For legacy reasons, console properties are enumerable, writable, deleteable, - // and all have a length of 0. This may change if Console is standardized. - - JSC_NATIVE_FUNCTION("debug", consoleProtoFuncDebug, None, 0); - JSC_NATIVE_FUNCTION("error", consoleProtoFuncError, None, 0); - JSC_NATIVE_FUNCTION("log", consoleProtoFuncLog, None, 0); - JSC_NATIVE_FUNCTION("info", consoleProtoFuncInfo, None, 0); - JSC_NATIVE_FUNCTION("warn", consoleProtoFuncWarn, None, 0); - - JSC_NATIVE_FUNCTION("clear", consoleProtoFuncClear, None, 0); - JSC_NATIVE_FUNCTION("dir", consoleProtoFuncDir, None, 0); - JSC_NATIVE_FUNCTION("dirxml", consoleProtoFuncDirXML, None, 0); - JSC_NATIVE_FUNCTION("table", consoleProtoFuncTable, None, 0); - JSC_NATIVE_FUNCTION("trace", consoleProtoFuncTrace, None, 0); - JSC_NATIVE_FUNCTION("assert", consoleProtoFuncAssert, None, 0); - JSC_NATIVE_FUNCTION("count", consoleProtoFuncCount, None, 0); - JSC_NATIVE_FUNCTION("profile", consoleProtoFuncProfile, None, 0); - JSC_NATIVE_FUNCTION("profileEnd", consoleProtoFuncProfileEnd, None, 0); - JSC_NATIVE_FUNCTION("time", consoleProtoFuncTime, None, 0); - JSC_NATIVE_FUNCTION("timeEnd", consoleProtoFuncTimeEnd, None, 0); - JSC_NATIVE_FUNCTION("timeStamp", consoleProtoFuncTimeStamp, None, 0); - JSC_NATIVE_FUNCTION("group", consoleProtoFuncGroup, None, 0); - JSC_NATIVE_FUNCTION("groupCollapsed", consoleProtoFuncGroupCollapsed, None, 0); - JSC_NATIVE_FUNCTION("groupEnd", consoleProtoFuncGroupEnd, None, 0); -} - -static String valueToStringWithUndefinedOrNullCheck(ExecState* exec, JSValue value) -{ - if (value.isUndefinedOrNull()) - return String(); - return value.toString(exec)->value(exec); -} - -static EncodedJSValue consoleLogWithLevel(ExecState* exec, MessageLevel level) -{ - JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue()); - if (!castedThis) - return throwVMTypeError(exec); - ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info()); - ConsoleClient* client = castedThis->globalObject()->consoleClient(); - if (!client) - return JSValue::encode(jsUndefined()); - - RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0)); - client->logWithLevel(exec, arguments.release(), level); - return JSValue::encode(jsUndefined()); -} - -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDebug(ExecState* exec) -{ - return consoleLogWithLevel(exec, MessageLevel::Debug); -} - -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncError(ExecState* exec) -{ - return consoleLogWithLevel(exec, MessageLevel::Error); -} - -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncLog(ExecState* exec) -{ - return consoleLogWithLevel(exec, MessageLevel::Log); -} - -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncInfo(ExecState* exec) -{ - return consoleLogWithLevel(exec, MessageLevel::Info); -} - -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncWarn(ExecState* exec) -{ - return consoleLogWithLevel(exec, MessageLevel::Warning); -} - -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncClear(ExecState* exec) -{ - JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue()); - if (!castedThis) - return throwVMTypeError(exec); - ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info()); - ConsoleClient* client = castedThis->globalObject()->consoleClient(); - if (!client) - return JSValue::encode(jsUndefined()); - - RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0)); - client->clear(exec, arguments.release()); - return JSValue::encode(jsUndefined()); -} - -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDir(ExecState* exec) -{ - JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue()); - if (!castedThis) - return throwVMTypeError(exec); - ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info()); - ConsoleClient* client = castedThis->globalObject()->consoleClient(); - if (!client) - return JSValue::encode(jsUndefined()); - - RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0)); - client->dir(exec, arguments.release()); - return JSValue::encode(jsUndefined()); -} - -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDirXML(ExecState* exec) -{ - JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue()); - if (!castedThis) - return throwVMTypeError(exec); - ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info()); - ConsoleClient* client = castedThis->globalObject()->consoleClient(); - if (!client) - return JSValue::encode(jsUndefined()); - - RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0)); - client->dirXML(exec, arguments.release()); - return JSValue::encode(jsUndefined()); -} - -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTable(ExecState* exec) -{ - JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue()); - if (!castedThis) - return throwVMTypeError(exec); - ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info()); - ConsoleClient* client = castedThis->globalObject()->consoleClient(); - if (!client) - return JSValue::encode(jsUndefined()); - - RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0)); - client->table(exec, arguments.release()); - return JSValue::encode(jsUndefined()); -} - -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTrace(ExecState* exec) -{ - JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue()); - if (!castedThis) - return throwVMTypeError(exec); - ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info()); - ConsoleClient* client = castedThis->globalObject()->consoleClient(); - if (!client) - return JSValue::encode(jsUndefined()); - - RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0)); - client->trace(exec, arguments.release()); - return JSValue::encode(jsUndefined()); -} - -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncAssert(ExecState* exec) -{ - JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue()); - if (!castedThis) - return throwVMTypeError(exec); - ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info()); - ConsoleClient* client = castedThis->globalObject()->consoleClient(); - if (!client) - return JSValue::encode(jsUndefined()); - - bool condition(exec->argument(0).toBoolean(exec)); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 1)); - client->assertCondition(exec, arguments.release(), condition); - return JSValue::encode(jsUndefined()); -} - -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncCount(ExecState* exec) -{ - JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue()); - if (!castedThis) - return throwVMTypeError(exec); - ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info()); - ConsoleClient* client = castedThis->globalObject()->consoleClient(); - if (!client) - return JSValue::encode(jsUndefined()); - - RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0)); - client->count(exec, arguments.release()); - return JSValue::encode(jsUndefined()); -} - -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncProfile(ExecState* exec) -{ - JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue()); - if (!castedThis) - return throwVMTypeError(exec); - ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info()); - ConsoleClient* client = castedThis->globalObject()->consoleClient(); - if (!client) - return JSValue::encode(jsUndefined()); - - size_t argsCount = exec->argumentCount(); - if (argsCount <= 0) { - client->profile(exec, String()); - return JSValue::encode(jsUndefined()); - } - - const String& title(valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0))); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - client->profile(exec, title); - return JSValue::encode(jsUndefined()); -} - -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncProfileEnd(ExecState* exec) -{ - JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue()); - if (!castedThis) - return throwVMTypeError(exec); - ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info()); - ConsoleClient* client = castedThis->globalObject()->consoleClient(); - if (!client) - return JSValue::encode(jsUndefined()); - - size_t argsCount = exec->argumentCount(); - if (argsCount <= 0) { - client->profileEnd(exec, String()); - return JSValue::encode(jsUndefined()); - } - - const String& title(valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0))); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - client->profileEnd(exec, title); - return JSValue::encode(jsUndefined()); -} - -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTime(ExecState* exec) -{ - JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue()); - if (!castedThis) - return throwVMTypeError(exec); - ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info()); - ConsoleClient* client = castedThis->globalObject()->consoleClient(); - if (!client) - return JSValue::encode(jsUndefined()); - - if (exec->argumentCount() < 1) - return throwVMError(exec, createNotEnoughArgumentsError(exec)); - - const String& title(valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0))); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - client->time(exec, title); - return JSValue::encode(jsUndefined()); -} - -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTimeEnd(ExecState* exec) -{ - JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue()); - if (!castedThis) - return throwVMTypeError(exec); - ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info()); - ConsoleClient* client = castedThis->globalObject()->consoleClient(); - if (!client) - return JSValue::encode(jsUndefined()); - - if (exec->argumentCount() < 1) - return throwVMError(exec, createNotEnoughArgumentsError(exec)); - - const String& title(valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0))); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - client->timeEnd(exec, title); - return JSValue::encode(jsUndefined()); -} - -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTimeStamp(ExecState* exec) -{ - JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue()); - if (!castedThis) - return throwVMTypeError(exec); - ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info()); - ConsoleClient* client = castedThis->globalObject()->consoleClient(); - if (!client) - return JSValue::encode(jsUndefined()); - - RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0)); - client->timeStamp(exec, arguments.release()); - return JSValue::encode(jsUndefined()); -} - -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroup(ExecState* exec) -{ - JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue()); - if (!castedThis) - return throwVMTypeError(exec); - ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info()); - ConsoleClient* client = castedThis->globalObject()->consoleClient(); - if (!client) - return JSValue::encode(jsUndefined()); - - RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0)); - client->group(exec, arguments.release()); - return JSValue::encode(jsUndefined()); -} - -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroupCollapsed(ExecState* exec) -{ - JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue()); - if (!castedThis) - return throwVMTypeError(exec); - ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info()); - ConsoleClient* client = castedThis->globalObject()->consoleClient(); - if (!client) - return JSValue::encode(jsUndefined()); - - RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0)); - client->groupCollapsed(exec, arguments.release()); - return JSValue::encode(jsUndefined()); -} - -static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroupEnd(ExecState* exec) -{ - JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue()); - if (!castedThis) - return throwVMTypeError(exec); - ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info()); - ConsoleClient* client = castedThis->globalObject()->consoleClient(); - if (!client) - return JSValue::encode(jsUndefined()); - - RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0)); - client->groupEnd(exec, arguments.release()); - return JSValue::encode(jsUndefined()); -} - -} diff --git a/Source/JavaScriptCore/runtime/ConsoleTypes.h b/Source/JavaScriptCore/runtime/ConsoleTypes.h deleted file mode 100644 index c6ecabda9..000000000 --- a/Source/JavaScriptCore/runtime/ConsoleTypes.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2011 Apple Inc. All rights reserved. - * Copyright (C) 2012 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. - * - * 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 ConsoleTypes_h -#define ConsoleTypes_h - -namespace JSC { - -enum class MessageSource { - XML, - JS, - Network, - ConsoleAPI, - Storage, - AppCache, - Rendering, - CSS, - Security, - ContentBlocker, - Other, -}; - -enum class MessageType { - Log, - Dir, - DirXML, - Table, - Trace, - StartGroup, - StartGroupCollapsed, - EndGroup, - Clear, - Assert, - Timing, - Profile, - ProfileEnd, -}; - -enum class MessageLevel { - Log = 1, - Warning = 2, - Error = 3, - Debug = 4, - Info = 5, -}; - -} // namespace JSC - -using JSC::MessageSource; -using JSC::MessageType; -using JSC::MessageLevel; - -#endif // ConsoleTypes_h diff --git a/Source/JavaScriptCore/runtime/ConstantMode.cpp b/Source/JavaScriptCore/runtime/ConstantMode.cpp deleted file mode 100644 index 58ba79475..000000000 --- a/Source/JavaScriptCore/runtime/ConstantMode.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2015 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 "ConstantMode.h" - -namespace WTF { - -using namespace JSC; - -void printInternal(PrintStream& out, ConstantMode mode) -{ - switch (mode) { - case IsConstant: - out.print("Constant"); - return; - case IsVariable: - out.print("Variable"); - return; - } - RELEASE_ASSERT_NOT_REACHED(); -} - -} // namespace WTF diff --git a/Source/JavaScriptCore/runtime/ConstantMode.h b/Source/JavaScriptCore/runtime/ConstantMode.h index a0496278a..389a074f9 100644 --- a/Source/JavaScriptCore/runtime/ConstantMode.h +++ b/Source/JavaScriptCore/runtime/ConstantMode.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. + * 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 @@ -26,24 +26,11 @@ #ifndef ConstantMode_h #define ConstantMode_h -#include <wtf/PrintStream.h> - namespace JSC { enum ConstantMode { IsConstant, IsVariable }; -inline ConstantMode modeForIsConstant(bool isConstant) -{ - return isConstant ? IsConstant : IsVariable; -} - } // namespace JSC -namespace WTF { - -void printInternal(PrintStream&, JSC::ConstantMode); - -} // namespace WTF - #endif // ConstantMode_h diff --git a/Source/JavaScriptCore/runtime/ConstructAbility.h b/Source/JavaScriptCore/runtime/ConstructAbility.h deleted file mode 100644 index 3af880b60..000000000 --- a/Source/JavaScriptCore/runtime/ConstructAbility.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2015 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 ConstructAbility_h -#define ConstructAbility_h - -namespace JSC { - -enum class ConstructAbility : unsigned { - CanConstruct, - CannotConstruct, -}; - -} - -#endif // ConstructAbility_h diff --git a/Source/JavaScriptCore/runtime/ConstructData.cpp b/Source/JavaScriptCore/runtime/ConstructData.cpp index 6010e6356..3dc46180c 100644 --- a/Source/JavaScriptCore/runtime/ConstructData.cpp +++ b/Source/JavaScriptCore/runtime/ConstructData.cpp @@ -30,14 +30,14 @@ #include "Interpreter.h" #include "JSFunction.h" #include "JSGlobalObject.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { -JSObject* construct(ExecState* exec, JSValue constructorObject, ConstructType constructType, const ConstructData& constructData, const ArgList& args, JSValue newTarget) +JSObject* construct(ExecState* exec, JSValue constructorObject, ConstructType constructType, const ConstructData& constructData, const ArgList& args) { ASSERT(constructType == ConstructTypeJS || constructType == ConstructTypeHost); - return exec->interpreter()->executeConstruct(exec, asObject(constructorObject), constructType, constructData, args, newTarget); + return exec->interpreter()->executeConstruct(exec, asObject(constructorObject), constructType, constructData, args); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ConstructData.h b/Source/JavaScriptCore/runtime/ConstructData.h index 17e1a5dae..10317a2f9 100644 --- a/Source/JavaScriptCore/runtime/ConstructData.h +++ b/Source/JavaScriptCore/runtime/ConstructData.h @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -34,34 +34,29 @@ namespace JSC { -class ArgList; -class ExecState; -class FunctionExecutable; -class JSObject; -class JSScope; - -enum ConstructType { - ConstructTypeNone, - ConstructTypeHost, - ConstructTypeJS -}; - -union ConstructData { - struct { - NativeFunction function; - } native; - struct { - FunctionExecutable* functionExecutable; - JSScope* scope; - } js; -}; - -JS_EXPORT_PRIVATE JSObject* construct(ExecState*, JSValue constructor, ConstructType, const ConstructData&, const ArgList&, JSValue newTarget); - -ALWAYS_INLINE JSObject* construct(ExecState* exec, JSValue constructorObject, ConstructType constructType, const ConstructData& constructData, const ArgList& args) -{ - return construct(exec, constructorObject, constructType, constructData, args, constructorObject); -} + class ArgList; + class ExecState; + class FunctionExecutable; + class JSObject; + class JSScope; + + enum ConstructType { + ConstructTypeNone, + ConstructTypeHost, + ConstructTypeJS + }; + + union ConstructData { + struct { + NativeFunction function; + } native; + struct { + FunctionExecutable* functionExecutable; + JSScope* scope; + } js; + }; + + JS_EXPORT_PRIVATE JSObject* construct(ExecState*, JSValue constructor, ConstructType, const ConstructData&, const ArgList&); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ControlFlowProfiler.cpp b/Source/JavaScriptCore/runtime/ControlFlowProfiler.cpp deleted file mode 100644 index d80e7f3ac..000000000 --- a/Source/JavaScriptCore/runtime/ControlFlowProfiler.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2014 Apple Inc. All rights reserved. - * Copyright (C) 2014 Saam Barati. <saambarati1@gmail.com> - * - * 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 "ControlFlowProfiler.h" - -#include "VM.h" - -namespace JSC { - -ControlFlowProfiler::ControlFlowProfiler() - : m_dummyBasicBlock(BasicBlockLocation(-1, -1)) -{ -} - -ControlFlowProfiler::~ControlFlowProfiler() -{ - for (const BlockLocationCache& cache : m_sourceIDBuckets.values()) { - for (BasicBlockLocation* block : cache.values()) - delete block; - } -} - -BasicBlockLocation* ControlFlowProfiler::getBasicBlockLocation(intptr_t sourceID, int startOffset, int endOffset) -{ - auto addResult = m_sourceIDBuckets.add(sourceID, BlockLocationCache()); - BlockLocationCache& blockLocationCache = addResult.iterator->value; - BasicBlockKey key(startOffset, endOffset); - auto addResultForBasicBlock = blockLocationCache.add(key, nullptr); - if (addResultForBasicBlock.isNewEntry) - addResultForBasicBlock.iterator->value = new BasicBlockLocation(startOffset, endOffset); - return addResultForBasicBlock.iterator->value; -} - -void ControlFlowProfiler::dumpData() const -{ - auto iter = m_sourceIDBuckets.begin(); - auto end = m_sourceIDBuckets.end(); - for (; iter != end; ++iter) { - dataLog("SourceID: ", iter->key, "\n"); - for (const BasicBlockLocation* block : iter->value.values()) - block->dumpData(); - } -} - -Vector<BasicBlockRange> ControlFlowProfiler::getBasicBlocksForSourceID(intptr_t sourceID, VM& vm) const -{ - Vector<BasicBlockRange> result(0); - auto bucketFindResult = m_sourceIDBuckets.find(sourceID); - if (bucketFindResult == m_sourceIDBuckets.end()) - return result; - - const BlockLocationCache& cache = bucketFindResult->value; - for (const BasicBlockLocation* block : cache.values()) { - bool hasExecuted = block->hasExecuted(); - const Vector<BasicBlockLocation::Gap>& blockRanges = block->getExecutedRanges(); - for (BasicBlockLocation::Gap gap : blockRanges) { - BasicBlockRange range; - range.m_hasExecuted = hasExecuted; - range.m_startOffset = gap.first; - range.m_endOffset = gap.second; - result.append(range); - } - } - - const Vector<std::tuple<bool, unsigned, unsigned>>& unexecutedFunctionRanges = vm.functionHasExecutedCache()->getFunctionRanges(sourceID); - for (const auto& functionRange : unexecutedFunctionRanges) { - BasicBlockRange range; - range.m_hasExecuted = std::get<0>(functionRange); - range.m_startOffset = static_cast<int>(std::get<1>(functionRange)); - range.m_endOffset = static_cast<int>(std::get<2>(functionRange)); - result.append(range); - } - - return result; -} - -bool ControlFlowProfiler::hasBasicBlockAtTextOffsetBeenExecuted(int offset, intptr_t sourceID, VM& vm) -{ - const Vector<BasicBlockRange>& blocks = getBasicBlocksForSourceID(sourceID, vm); - int bestDistance = INT_MAX; - BasicBlockRange bestRange; - bestRange.m_startOffset = bestRange.m_endOffset = -1; - bestRange.m_hasExecuted = false; // Suppress MSVC warning. - // Because some ranges may overlap because of function boundaries, make sure to find the smallest range enclosing the offset. - for (BasicBlockRange range : blocks) { - if (range.m_startOffset <= offset && offset <= range.m_endOffset && (range.m_endOffset - range.m_startOffset) < bestDistance) { - RELEASE_ASSERT(range.m_endOffset - range.m_startOffset >= 0); - bestDistance = range.m_endOffset - range.m_startOffset; - bestRange = range; - } - } - - RELEASE_ASSERT(bestRange.m_startOffset != -1 && bestRange.m_endOffset != -1); - return bestRange.m_hasExecuted; -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ControlFlowProfiler.h b/Source/JavaScriptCore/runtime/ControlFlowProfiler.h deleted file mode 100644 index 81749dc37..000000000 --- a/Source/JavaScriptCore/runtime/ControlFlowProfiler.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2014 Apple Inc. All rights reserved. - * Copyright (C) 2014 Saam Barati. <saambarati1@gmail.com> - * - * 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 ControlFlowProfiler_h -#define ControlFlowProfiler_h - -#include "BasicBlockLocation.h" -#include <wtf/HashMap.h> -#include <wtf/HashMethod.h> - -namespace JSC { - -class VM; - -struct BasicBlockKey { - BasicBlockKey() - : m_startOffset(-3) - , m_endOffset(-3) - { } - - BasicBlockKey(int startOffset, int endOffset) - : m_startOffset(startOffset) - , m_endOffset(endOffset) - { } - - BasicBlockKey(WTF::HashTableDeletedValueType) - : m_startOffset(-2) - , m_endOffset(-2) - { } - - bool isHashTableDeletedValue() const { return m_startOffset == -2 && m_endOffset == -2; } - bool operator==(const BasicBlockKey& other) const { return m_startOffset == other.m_startOffset && m_endOffset == other.m_endOffset; } - unsigned hash() const { return m_startOffset + m_endOffset + 1; } - - int m_startOffset; - int m_endOffset; -}; - -struct BasicBlockKeyHash { - static unsigned hash(const BasicBlockKey& key) { return key.hash(); } - static bool equal(const BasicBlockKey& a, const BasicBlockKey& b) { return a == b; } - static const bool safeToCompareToEmptyOrDeleted = true; -}; - -} // namespace JSC - -namespace WTF { - -template<typename T> struct DefaultHash; -template<> struct DefaultHash<JSC::BasicBlockKey> { - typedef JSC::BasicBlockKeyHash Hash; -}; - -template<typename T> struct HashTraits; -template<> struct HashTraits<JSC::BasicBlockKey> : SimpleClassHashTraits<JSC::BasicBlockKey> { - static const bool emptyValueIsZero = false; -}; - -} // namespace WTF - -namespace JSC { - -struct BasicBlockRange { - int m_startOffset; - int m_endOffset; - bool m_hasExecuted; -}; - -class ControlFlowProfiler { - WTF_MAKE_FAST_ALLOCATED; -public: - ControlFlowProfiler(); - ~ControlFlowProfiler(); - BasicBlockLocation* getBasicBlockLocation(intptr_t sourceID, int startOffset, int endOffset); - JS_EXPORT_PRIVATE void dumpData() const; - Vector<BasicBlockRange> getBasicBlocksForSourceID(intptr_t sourceID, VM&) const; - BasicBlockLocation* dummyBasicBlock() { return &m_dummyBasicBlock; } - JS_EXPORT_PRIVATE bool hasBasicBlockAtTextOffsetBeenExecuted(int, intptr_t, VM&); // This function exists for testing. - -private: - typedef HashMap<BasicBlockKey, BasicBlockLocation*> BlockLocationCache; - typedef HashMap<intptr_t, BlockLocationCache> SourceIDBuckets; - - SourceIDBuckets m_sourceIDBuckets; - BasicBlockLocation m_dummyBasicBlock; -}; - -} // namespace JSC - -#endif // ControlFlowProfiler_h diff --git a/Source/JavaScriptCore/runtime/CustomGetterSetter.cpp b/Source/JavaScriptCore/runtime/CustomGetterSetter.cpp deleted file mode 100644 index 0f9e1afa9..000000000 --- a/Source/JavaScriptCore/runtime/CustomGetterSetter.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2014 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 "CustomGetterSetter.h" - -#include "JSCJSValueInlines.h" -#include "SlotVisitorInlines.h" -#include <wtf/Assertions.h> - -namespace JSC { - -STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(CustomGetterSetter); - -const ClassInfo CustomGetterSetter::s_info = { "CustomGetterSetter", 0, 0, CREATE_METHOD_TABLE(CustomGetterSetter) }; - -void callCustomSetter(ExecState* exec, JSValue customGetterSetter, JSObject* base, JSValue thisValue, JSValue value) -{ - CustomGetterSetter::CustomSetter setter = jsCast<CustomGetterSetter*>(customGetterSetter)->setter(); - if (!setter) - return; - setter(exec, base, JSValue::encode(thisValue), JSValue::encode(value)); -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/CustomGetterSetter.h b/Source/JavaScriptCore/runtime/CustomGetterSetter.h deleted file mode 100644 index 54519eba3..000000000 --- a/Source/JavaScriptCore/runtime/CustomGetterSetter.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2014 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 CustomGetterSetter_h -#define CustomGetterSetter_h - -#include "JSCell.h" -#include "PropertySlot.h" -#include "PutPropertySlot.h" -#include "Structure.h" - -namespace JSC { - -class CustomGetterSetter final : public JSCell { -public: - typedef JSCell Base; - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; - - typedef PropertySlot::GetValueFunc CustomGetter; - typedef PutPropertySlot::PutValueFunc CustomSetter; - - static CustomGetterSetter* create(VM& vm, CustomGetter customGetter, CustomSetter customSetter) - { - CustomGetterSetter* customGetterSetter = new (NotNull, allocateCell<CustomGetterSetter>(vm.heap)) CustomGetterSetter(vm, customGetter, customSetter); - customGetterSetter->finishCreation(vm); - return customGetterSetter; - } - - CustomGetterSetter::CustomGetter getter() const { return m_getter; } - CustomGetterSetter::CustomSetter setter() const { return m_setter; } - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(CustomGetterSetterType, StructureFlags), info()); - } - - DECLARE_EXPORT_INFO; - -private: - CustomGetterSetter(VM& vm, CustomGetter getter, CustomSetter setter) - : JSCell(vm, vm.customGetterSetterStructure.get()) - , m_getter(getter) - , m_setter(setter) - { - } - - CustomGetter m_getter; - CustomSetter m_setter; -}; - -void callCustomSetter(ExecState*, JSValue customGetterSetter, JSObject* base, JSValue thisValue, JSValue value); - -} // namespace JSC - -#endif // CustomGetterSetter_h diff --git a/Source/JavaScriptCore/runtime/DataView.cpp b/Source/JavaScriptCore/runtime/DataView.cpp index 78e743fc1..0c83d6e95 100644 --- a/Source/JavaScriptCore/runtime/DataView.cpp +++ b/Source/JavaScriptCore/runtime/DataView.cpp @@ -37,13 +37,13 @@ DataView::DataView(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned { } -Ref<DataView> DataView::create( +PassRefPtr<DataView> DataView::create( PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned byteLength) { - return adoptRef(*new DataView(buffer, byteOffset, byteLength)); + return adoptRef(new DataView(buffer, byteOffset, byteLength)); } -Ref<DataView> DataView::create(PassRefPtr<ArrayBuffer> passedBuffer) +PassRefPtr<DataView> DataView::create(PassRefPtr<ArrayBuffer> passedBuffer) { RefPtr<ArrayBuffer> buffer = passedBuffer; return create(buffer, 0, buffer->byteLength()); diff --git a/Source/JavaScriptCore/runtime/DataView.h b/Source/JavaScriptCore/runtime/DataView.h index a01d13506..4a8aa9258 100644 --- a/Source/JavaScriptCore/runtime/DataView.h +++ b/Source/JavaScriptCore/runtime/DataView.h @@ -37,8 +37,8 @@ protected: DataView(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned byteLength); public: - JS_EXPORT_PRIVATE static Ref<DataView> create(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length); - static Ref<DataView> create(PassRefPtr<ArrayBuffer>); + JS_EXPORT_PRIVATE static PassRefPtr<DataView> create(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length); + static PassRefPtr<DataView> create(PassRefPtr<ArrayBuffer>); virtual unsigned byteLength() const override { diff --git a/Source/JavaScriptCore/runtime/DateConstructor.cpp b/Source/JavaScriptCore/runtime/DateConstructor.cpp index ee656a309..7cbea6407 100644 --- a/Source/JavaScriptCore/runtime/DateConstructor.cpp +++ b/Source/JavaScriptCore/runtime/DateConstructor.cpp @@ -29,15 +29,15 @@ #include "JSFunction.h" #include "JSGlobalObject.h" #include "JSString.h" +#include "JSStringBuilder.h" #include "ObjectPrototype.h" -#include "JSCInlines.h" +#include "Operations.h" #include <math.h> #include <time.h> #include <wtf/MathExtras.h> -#if ENABLE(WEB_REPLAY) -#include "InputCursor.h" -#include "JSReplayInputs.h" +#if OS(WINCE) +extern "C" time_t time(time_t* timer); // Provided by libce. #endif #if HAVE(SYS_TIME_H) @@ -52,8 +52,9 @@ using namespace WTF; namespace JSC { -EncodedJSValue JSC_HOST_CALL dateParse(ExecState*); -EncodedJSValue JSC_HOST_CALL dateUTC(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateParse(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateNow(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateUTC(ExecState*); } @@ -61,7 +62,7 @@ EncodedJSValue JSC_HOST_CALL dateUTC(ExecState*); namespace JSC { -const ClassInfo DateConstructor::s_info = { "Function", &InternalFunction::s_info, &dateConstructorTable, CREATE_METHOD_TABLE(DateConstructor) }; +const ClassInfo DateConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::dateConstructorTable, CREATE_METHOD_TABLE(DateConstructor) }; /* Source for DateConstructor.lut.h @begin dateConstructorTable @@ -71,28 +72,6 @@ const ClassInfo DateConstructor::s_info = { "Function", &InternalFunction::s_inf @end */ -#if ENABLE(WEB_REPLAY) -static double deterministicCurrentTime(JSGlobalObject* globalObject) -{ - double currentTime = jsCurrentTime(); - InputCursor& cursor = globalObject->inputCursor(); - if (cursor.isCapturing()) - cursor.appendInput<GetCurrentTime>(currentTime); - - if (cursor.isReplaying()) { - if (GetCurrentTime* input = cursor.fetchInput<GetCurrentTime>()) - currentTime = input->currentTime(); - } - return currentTime; -} -#endif - -#if ENABLE(WEB_REPLAY) -#define NORMAL_OR_DETERMINISTIC_FUNCTION(a, b) (b) -#else -#define NORMAL_OR_DETERMINISTIC_FUNCTION(a, b) (a) -#endif - STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(DateConstructor); DateConstructor::DateConstructor(VM& vm, Structure* structure) @@ -109,7 +88,7 @@ void DateConstructor::finishCreation(VM& vm, DatePrototype* datePrototype) bool DateConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot) { - return getStaticFunctionSlot<InternalFunction>(exec, dateConstructorTable, jsCast<DateConstructor*>(object), propertyName, slot); + return getStaticFunctionSlot<InternalFunction>(exec, ExecState::dateConstructorTable(exec->vm()), jsCast<DateConstructor*>(object), propertyName, slot); } // ECMA 15.9.3 @@ -121,7 +100,7 @@ JSObject* constructDate(ExecState* exec, JSGlobalObject* globalObject, const Arg double value; if (numArgs == 0) // new Date() ECMA 15.9.3.3 - value = NORMAL_OR_DETERMINISTIC_FUNCTION(jsCurrentTime(), deterministicCurrentTime(globalObject)); + value = jsCurrentTime(); else if (numArgs == 1) { if (args.at(0).inherits(DateInstance::info())) value = asDateInstance(args.at(0))->internalNumber(); @@ -142,14 +121,14 @@ JSObject* constructDate(ExecState* exec, JSGlobalObject* globalObject, const Arg args.at(5).toNumber(exec), args.at(6).toNumber(exec) }; - if ((!std::isfinite(doubleArguments[0]) || (doubleArguments[0] > INT_MAX) || (doubleArguments[0] < INT_MIN)) - || (!std::isfinite(doubleArguments[1]) || (doubleArguments[1] > INT_MAX) || (doubleArguments[1] < INT_MIN)) - || (numArgs >= 3 && (!std::isfinite(doubleArguments[2]) || (doubleArguments[2] > INT_MAX) || (doubleArguments[2] < INT_MIN))) - || (numArgs >= 4 && (!std::isfinite(doubleArguments[3]) || (doubleArguments[3] > INT_MAX) || (doubleArguments[3] < INT_MIN))) - || (numArgs >= 5 && (!std::isfinite(doubleArguments[4]) || (doubleArguments[4] > INT_MAX) || (doubleArguments[4] < INT_MIN))) - || (numArgs >= 6 && (!std::isfinite(doubleArguments[5]) || (doubleArguments[5] > INT_MAX) || (doubleArguments[5] < INT_MIN))) - || (numArgs >= 7 && (!std::isfinite(doubleArguments[6]) || (doubleArguments[6] > INT_MAX) || (doubleArguments[6] < INT_MIN)))) - value = PNaN; + 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; int year = JSC::toInt32(doubleArguments[0]); @@ -195,21 +174,17 @@ CallType DateConstructor::getCallData(JSCell*, CallData& callData) return CallTypeHost; } -EncodedJSValue JSC_HOST_CALL dateParse(ExecState* exec) +static EncodedJSValue JSC_HOST_CALL dateParse(ExecState* exec) { return JSValue::encode(jsNumber(parseDate(exec->vm(), exec->argument(0).toString(exec)->value(exec)))); } -EncodedJSValue JSC_HOST_CALL dateNow(ExecState* exec) +static EncodedJSValue JSC_HOST_CALL dateNow(ExecState*) { -#if !ENABLE(WEB_REPLAY) - UNUSED_PARAM(exec); -#endif - - return JSValue::encode(jsNumber(NORMAL_OR_DETERMINISTIC_FUNCTION(jsCurrentTime(), deterministicCurrentTime(exec->lexicalGlobalObject())))); + return JSValue::encode(jsNumber(jsCurrentTime())); } -EncodedJSValue JSC_HOST_CALL dateUTC(ExecState* exec) +static EncodedJSValue JSC_HOST_CALL dateUTC(ExecState* exec) { double doubleArguments[7] = { exec->argument(0).toNumber(exec), @@ -221,13 +196,13 @@ EncodedJSValue JSC_HOST_CALL dateUTC(ExecState* exec) exec->argument(6).toNumber(exec) }; int n = exec->argumentCount(); - if ((std::isnan(doubleArguments[0]) || (doubleArguments[0] > INT_MAX) || (doubleArguments[0] < INT_MIN)) - || (std::isnan(doubleArguments[1]) || (doubleArguments[1] > INT_MAX) || (doubleArguments[1] < INT_MIN)) - || (n >= 3 && (std::isnan(doubleArguments[2]) || (doubleArguments[2] > INT_MAX) || (doubleArguments[2] < INT_MIN))) - || (n >= 4 && (std::isnan(doubleArguments[3]) || (doubleArguments[3] > INT_MAX) || (doubleArguments[3] < INT_MIN))) - || (n >= 5 && (std::isnan(doubleArguments[4]) || (doubleArguments[4] > INT_MAX) || (doubleArguments[4] < INT_MIN))) - || (n >= 6 && (std::isnan(doubleArguments[5]) || (doubleArguments[5] > INT_MAX) || (doubleArguments[5] < INT_MIN))) - || (n >= 7 && (std::isnan(doubleArguments[6]) || (doubleArguments[6] > INT_MAX) || (doubleArguments[6] < INT_MIN)))) + 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 cdac97d31..383e6f1b3 100644 --- a/Source/JavaScriptCore/runtime/DateConstructor.h +++ b/Source/JavaScriptCore/runtime/DateConstructor.h @@ -25,41 +25,39 @@ namespace JSC { -class DatePrototype; + class DatePrototype; -class DateConstructor : public InternalFunction { -public: - typedef InternalFunction Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; + class DateConstructor : public InternalFunction { + public: + typedef InternalFunction Base; - static DateConstructor* create(VM& vm, Structure* structure, DatePrototype* datePrototype) - { - DateConstructor* constructor = new (NotNull, allocateCell<DateConstructor>(vm.heap)) DateConstructor(vm, structure); - constructor->finishCreation(vm, datePrototype); - return constructor; - } + static DateConstructor* create(VM& vm, Structure* structure, DatePrototype* datePrototype) + { + DateConstructor* constructor = new (NotNull, allocateCell<DateConstructor>(vm.heap)) DateConstructor(vm, structure); + constructor->finishCreation(vm, datePrototype); + return constructor; + } - DECLARE_INFO; + DECLARE_INFO; - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } -protected: - void finishCreation(VM&, DatePrototype*); + protected: + void finishCreation(VM&, DatePrototype*); + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags; -private: - DateConstructor(VM&, Structure*); - static ConstructType getConstructData(JSCell*, ConstructData&); - static CallType getCallData(JSCell*, CallData&); + private: + DateConstructor(VM&, Structure*); + static ConstructType getConstructData(JSCell*, ConstructData&); + static CallType getCallData(JSCell*, CallData&); - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); -}; + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + }; -JSObject* constructDate(ExecState*, JSGlobalObject*, const ArgList&); - -EncodedJSValue JSC_HOST_CALL dateNow(ExecState*); + JSObject* constructDate(ExecState*, JSGlobalObject*, const ArgList&); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/DateConversion.h b/Source/JavaScriptCore/runtime/DateConversion.h index 80a29c823..8ea4c17ad 100644 --- a/Source/JavaScriptCore/runtime/DateConversion.h +++ b/Source/JavaScriptCore/runtime/DateConversion.h @@ -39,7 +39,7 @@ enum DateTimeFormat { DateTimeFormatDateAndTime = DateTimeFormatDate | DateTimeFormatTime }; -JS_EXPORT_PRIVATE WTF::String formatDateTime(const GregorianDateTime&, DateTimeFormat, bool asUTCVariant); +WTF::String formatDateTime(const GregorianDateTime&, DateTimeFormat, bool asUTCVariant); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/DateInstance.cpp b/Source/JavaScriptCore/runtime/DateInstance.cpp index e095f882c..bdb0f0c2d 100644 --- a/Source/JavaScriptCore/runtime/DateInstance.cpp +++ b/Source/JavaScriptCore/runtime/DateInstance.cpp @@ -24,7 +24,7 @@ #include "JSDateMath.h" #include "JSGlobalObject.h" -#include "JSCInlines.h" +#include "Operations.h" #include <math.h> #include <wtf/MathExtras.h> @@ -32,7 +32,7 @@ using namespace WTF; namespace JSC { -const ClassInfo DateInstance::s_info = {"Date", &JSWrapperObject::s_info, 0, CREATE_METHOD_TABLE(DateInstance)}; +const ClassInfo DateInstance::s_info = {"Date", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(DateInstance)}; DateInstance::DateInstance(VM& vm, Structure* structure) : JSWrapperObject(vm, structure) diff --git a/Source/JavaScriptCore/runtime/DateInstance.h b/Source/JavaScriptCore/runtime/DateInstance.h index 000e1a157..193e05421 100644 --- a/Source/JavaScriptCore/runtime/DateInstance.h +++ b/Source/JavaScriptCore/runtime/DateInstance.h @@ -25,69 +25,69 @@ namespace JSC { -class DateInstance : public JSWrapperObject { -protected: - JS_EXPORT_PRIVATE DateInstance(VM&, Structure*); - void finishCreation(VM&); - JS_EXPORT_PRIVATE void finishCreation(VM&, double); - - JS_EXPORT_PRIVATE static void destroy(JSCell*); - -public: - typedef JSWrapperObject Base; - - static DateInstance* create(VM& vm, Structure* structure, double date) - { - DateInstance* instance = new (NotNull, allocateCell<DateInstance>(vm.heap)) DateInstance(vm, structure); - instance->finishCreation(vm, date); - return instance; - } - - static DateInstance* create(VM& vm, Structure* structure) - { - DateInstance* instance = new (NotNull, allocateCell<DateInstance>(vm.heap)) DateInstance(vm, structure); - instance->finishCreation(vm); - return instance; - } - - double internalNumber() const { return internalValue().asNumber(); } - - DECLARE_EXPORT_INFO; - - const GregorianDateTime* gregorianDateTime(ExecState* exec) const + class DateInstance : public JSWrapperObject { + protected: + JS_EXPORT_PRIVATE DateInstance(VM&, Structure*); + void finishCreation(VM&); + JS_EXPORT_PRIVATE void finishCreation(VM&, double); + + static void destroy(JSCell*); + + public: + typedef JSWrapperObject Base; + + static DateInstance* create(VM& vm, Structure* structure, double date) + { + DateInstance* instance = new (NotNull, allocateCell<DateInstance>(vm.heap)) DateInstance(vm, structure); + instance->finishCreation(vm, date); + return instance; + } + + static DateInstance* create(VM& vm, Structure* structure) + { + DateInstance* instance = new (NotNull, allocateCell<DateInstance>(vm.heap)) DateInstance(vm, structure); + instance->finishCreation(vm); + return instance; + } + + double internalNumber() const { return internalValue().asNumber(); } + + DECLARE_EXPORT_INFO; + + const GregorianDateTime* gregorianDateTime(ExecState* exec) const + { + if (m_data && m_data->m_gregorianDateTimeCachedForMS == internalNumber()) + return &m_data->m_cachedGregorianDateTime; + return calculateGregorianDateTime(exec); + } + + const GregorianDateTime* gregorianDateTimeUTC(ExecState* exec) const + { + if (m_data && m_data->m_gregorianDateTimeUTCCachedForMS == internalNumber()) + return &m_data->m_cachedGregorianDateTimeUTC; + return calculateGregorianDateTimeUTC(exec); + } + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } + + private: + const GregorianDateTime* calculateGregorianDateTime(ExecState*) const; + const GregorianDateTime* calculateGregorianDateTimeUTC(ExecState*) const; + + mutable RefPtr<DateInstanceData> m_data; + }; + + DateInstance* asDateInstance(JSValue); + + inline DateInstance* asDateInstance(JSValue value) { - if (m_data && m_data->m_gregorianDateTimeCachedForMS == internalNumber()) - return &m_data->m_cachedGregorianDateTime; - return calculateGregorianDateTime(exec); + ASSERT(asObject(value)->inherits(DateInstance::info())); + return static_cast<DateInstance*>(asObject(value)); } - const GregorianDateTime* gregorianDateTimeUTC(ExecState* exec) const - { - if (m_data && m_data->m_gregorianDateTimeUTCCachedForMS == internalNumber()) - return &m_data->m_cachedGregorianDateTimeUTC; - return calculateGregorianDateTimeUTC(exec); - } - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } - -private: - JS_EXPORT_PRIVATE const GregorianDateTime* calculateGregorianDateTime(ExecState*) const; - JS_EXPORT_PRIVATE const GregorianDateTime* calculateGregorianDateTimeUTC(ExecState*) const; - - mutable RefPtr<DateInstanceData> m_data; -}; - -DateInstance* asDateInstance(JSValue); - -inline DateInstance* asDateInstance(JSValue value) -{ - ASSERT(asObject(value)->inherits(DateInstance::info())); - return static_cast<DateInstance*>(asObject(value)); -} - } // namespace JSC #endif // DateInstance_h diff --git a/Source/JavaScriptCore/runtime/DateInstanceCache.h b/Source/JavaScriptCore/runtime/DateInstanceCache.h index 865ee8ff2..1c8c011ec 100644 --- a/Source/JavaScriptCore/runtime/DateInstanceCache.h +++ b/Source/JavaScriptCore/runtime/DateInstanceCache.h @@ -30,63 +30,64 @@ #include "JSDateMath.h" #include <array> #include <wtf/HashFunctions.h> +#include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> namespace JSC { -class DateInstanceData : public RefCounted<DateInstanceData> { -public: - static Ref<DateInstanceData> create() { return adoptRef(*new DateInstanceData); } - - double m_gregorianDateTimeCachedForMS; - GregorianDateTime m_cachedGregorianDateTime; - double m_gregorianDateTimeUTCCachedForMS; - GregorianDateTime m_cachedGregorianDateTimeUTC; - -private: - DateInstanceData() - : m_gregorianDateTimeCachedForMS(PNaN) - , m_gregorianDateTimeUTCCachedForMS(PNaN) - { - } -}; - -class DateInstanceCache { -public: - DateInstanceCache() - { - reset(); - } - - void reset() - { - for (size_t i = 0; i < cacheSize; ++i) - m_cache[i].key = PNaN; - } + class DateInstanceData : public RefCounted<DateInstanceData> { + public: + static PassRefPtr<DateInstanceData> create() { return adoptRef(new DateInstanceData); } + + double m_gregorianDateTimeCachedForMS; + GregorianDateTime m_cachedGregorianDateTime; + double m_gregorianDateTimeUTCCachedForMS; + GregorianDateTime m_cachedGregorianDateTimeUTC; + + private: + DateInstanceData() + : m_gregorianDateTimeCachedForMS(QNaN) + , m_gregorianDateTimeUTCCachedForMS(QNaN) + { + } + }; - DateInstanceData* add(double d) - { - CacheEntry& entry = lookup(d); - if (d == entry.key) + class DateInstanceCache { + public: + DateInstanceCache() + { + reset(); + } + + void reset() + { + for (size_t i = 0; i < cacheSize; ++i) + m_cache[i].key = QNaN; + } + + DateInstanceData* add(double d) + { + CacheEntry& entry = lookup(d); + if (d == entry.key) + return entry.value.get(); + + entry.key = d; + entry.value = DateInstanceData::create(); return entry.value.get(); + } - entry.key = d; - entry.value = DateInstanceData::create(); - return entry.value.get(); - } - -private: - static const size_t cacheSize = 16; + private: + static const size_t cacheSize = 16; - struct CacheEntry { - double key; - RefPtr<DateInstanceData> value; - }; + struct CacheEntry { + double key; + RefPtr<DateInstanceData> value; + }; - CacheEntry& lookup(double d) { return m_cache[WTF::FloatHash<double>::hash(d) & (cacheSize - 1)]; } + CacheEntry& lookup(double d) { return m_cache[WTF::FloatHash<double>::hash(d) & (cacheSize - 1)]; } - std::array<CacheEntry, cacheSize> m_cache; -}; + std::array<CacheEntry, cacheSize> m_cache; + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/DatePrototype.cpp b/Source/JavaScriptCore/runtime/DatePrototype.cpp index fe8747916..b0675451a 100644 --- a/Source/JavaScriptCore/runtime/DatePrototype.cpp +++ b/Source/JavaScriptCore/runtime/DatePrototype.cpp @@ -30,9 +30,10 @@ #include "JSDateMath.h" #include "JSGlobalObject.h" #include "JSString.h" +#include "JSStringBuilder.h" #include "Lookup.h" #include "ObjectPrototype.h" -#include "JSCInlines.h" +#include "Operations.h" #include <limits.h> #include <locale.h> #include <math.h> @@ -70,51 +71,51 @@ using namespace WTF; namespace JSC { -EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*); -EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*); +static EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState*); } @@ -319,7 +320,7 @@ static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, doubl static EncodedJSValue formateDateInstance(ExecState* exec, DateTimeFormat format, bool asUTCVariant) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -425,7 +426,7 @@ static bool fillStructuresUsingDateArgs(ExecState *exec, int maxArgs, double *ms return ok; } -const ClassInfo DatePrototype::s_info = {"Date", &DateInstance::s_info, &dateTable, CREATE_METHOD_TABLE(DatePrototype)}; +const ClassInfo DatePrototype::s_info = {"Date", &DateInstance::s_info, 0, ExecState::dateTable, CREATE_METHOD_TABLE(DatePrototype)}; /* Source for DatePrototype.lut.h @begin dateTable @@ -495,7 +496,7 @@ void DatePrototype::finishCreation(VM& vm, JSGlobalObject*) bool DatePrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { - return getStaticFunctionSlot<JSObject>(exec, dateTable, jsCast<DatePrototype*>(object), propertyName, slot); + return getStaticFunctionSlot<JSObject>(exec, ExecState::dateTable(exec->vm()), jsCast<DatePrototype*>(object), propertyName, slot); } // Functions @@ -514,7 +515,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -560,7 +561,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -570,7 +571,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -580,7 +581,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -590,7 +591,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -599,7 +600,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -613,7 +614,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -633,7 +634,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -647,7 +648,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -661,7 +662,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -675,7 +676,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -689,7 +690,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -703,7 +704,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -717,7 +718,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -731,7 +732,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -745,7 +746,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -759,7 +760,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -773,7 +774,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -787,7 +788,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -801,7 +802,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -817,7 +818,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -833,7 +834,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -847,7 +848,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -861,7 +862,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec) static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, WTF::TimeType inputTimeType) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -899,7 +900,7 @@ static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, WTF::TimeType inputTimeType) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -940,77 +941,91 @@ static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState* exec) { - return setNewValueFromTimeArgs(exec, 1, WTF::LocalTime); + const WTF::TimeType inputTimeType = WTF::LocalTime; + return setNewValueFromTimeArgs(exec, 1, inputTimeType); } EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState* exec) { - return setNewValueFromTimeArgs(exec, 1, WTF::UTCTime); + const WTF::TimeType inputTimeType = WTF::UTCTime; + return setNewValueFromTimeArgs(exec, 1, inputTimeType); } EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState* exec) { - return setNewValueFromTimeArgs(exec, 2, WTF::LocalTime); + const WTF::TimeType inputTimeType = WTF::LocalTime; + return setNewValueFromTimeArgs(exec, 2, inputTimeType); } EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState* exec) { - return setNewValueFromTimeArgs(exec, 2, WTF::UTCTime); + const WTF::TimeType inputTimeType = WTF::UTCTime; + return setNewValueFromTimeArgs(exec, 2, inputTimeType); } EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState* exec) { - return setNewValueFromTimeArgs(exec, 3, WTF::LocalTime); + const WTF::TimeType inputTimeType = WTF::LocalTime; + return setNewValueFromTimeArgs(exec, 3, inputTimeType); } EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState* exec) { - return setNewValueFromTimeArgs(exec, 3, WTF::UTCTime); + const WTF::TimeType inputTimeType = WTF::UTCTime; + return setNewValueFromTimeArgs(exec, 3, inputTimeType); } EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState* exec) { - return setNewValueFromTimeArgs(exec, 4, WTF::LocalTime); + const WTF::TimeType inputTimeType = WTF::LocalTime; + return setNewValueFromTimeArgs(exec, 4, inputTimeType); } EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState* exec) { - return setNewValueFromTimeArgs(exec, 4, WTF::UTCTime); + const WTF::TimeType inputTimeType = WTF::UTCTime; + return setNewValueFromTimeArgs(exec, 4, inputTimeType); } EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState* exec) { - return setNewValueFromDateArgs(exec, 1, WTF::LocalTime); + const WTF::TimeType inputTimeType = WTF::LocalTime; + return setNewValueFromDateArgs(exec, 1, inputTimeType); } EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState* exec) { - return setNewValueFromDateArgs(exec, 1, WTF::UTCTime); + const WTF::TimeType inputTimeType = WTF::UTCTime; + return setNewValueFromDateArgs(exec, 1, inputTimeType); } EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState* exec) { - return setNewValueFromDateArgs(exec, 2, WTF::LocalTime); + const WTF::TimeType inputTimeType = WTF::LocalTime; + return setNewValueFromDateArgs(exec, 2, inputTimeType); } EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState* exec) { - return setNewValueFromDateArgs(exec, 2, WTF::UTCTime); + const WTF::TimeType inputTimeType = WTF::UTCTime; + return setNewValueFromDateArgs(exec, 2, inputTimeType); } EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState* exec) { - return setNewValueFromDateArgs(exec, 3, WTF::LocalTime); + const WTF::TimeType inputTimeType = WTF::LocalTime; + return setNewValueFromDateArgs(exec, 3, inputTimeType); } EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec) { - return setNewValueFromDateArgs(exec, 3, WTF::UTCTime); + const WTF::TimeType inputTimeType = WTF::UTCTime; + return setNewValueFromDateArgs(exec, 3, inputTimeType); } EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -1052,7 +1067,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); @@ -1068,17 +1083,11 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec) EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); JSObject* object = jsCast<JSObject*>(thisValue.toThis(exec, NotStrictMode)); if (exec->hadException()) return JSValue::encode(jsNull()); - - JSValue timeValue = object->toPrimitive(exec, PreferNumber); - if (exec->hadException()) - return JSValue::encode(jsNull()); - if (timeValue.isNumber() && !(timeValue.isInt32() || std::isfinite(timeValue.asDouble()))) - return JSValue::encode(jsNull()); - + 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 6714d7e36..a9bfbd477 100644 --- a/Source/JavaScriptCore/runtime/DatePrototype.h +++ b/Source/JavaScriptCore/runtime/DatePrototype.h @@ -25,34 +25,34 @@ namespace JSC { -class ObjectPrototype; - -class DatePrototype : public DateInstance { -private: - DatePrototype(VM&, Structure*); - -public: - typedef DateInstance Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; - - static DatePrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) - { - DatePrototype* prototype = new (NotNull, allocateCell<DatePrototype>(vm.heap)) DatePrototype(vm, structure); - prototype->finishCreation(vm, globalObject); - return prototype; - } - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); - - DECLARE_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } - -protected: - void finishCreation(VM&, JSGlobalObject*); -}; + class ObjectPrototype; + + class DatePrototype : public DateInstance { + private: + DatePrototype(VM&, Structure*); + + public: + typedef DateInstance Base; + + static DatePrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) + { + DatePrototype* prototype = new (NotNull, allocateCell<DatePrototype>(vm.heap)) DatePrototype(vm, structure); + prototype->finishCreation(vm, globalObject); + return prototype; + } + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + + DECLARE_INFO; + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } + + protected: + void finishCreation(VM&, JSGlobalObject*); + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | DateInstance::StructureFlags; + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/DirectArguments.cpp b/Source/JavaScriptCore/runtime/DirectArguments.cpp deleted file mode 100644 index bb61e4faf..000000000 --- a/Source/JavaScriptCore/runtime/DirectArguments.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2015 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 "DirectArguments.h" - -#include "CopyVisitorInlines.h" -#include "GenericArgumentsInlines.h" -#include "JSCInlines.h" - -namespace JSC { - -STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(DirectArguments); - -const ClassInfo DirectArguments::s_info = { "Arguments", &Base::s_info, 0, CREATE_METHOD_TABLE(DirectArguments) }; - -DirectArguments::DirectArguments(VM& vm, Structure* structure, unsigned length, unsigned capacity) - : GenericArguments(vm, structure) - , m_length(length) - , m_minCapacity(capacity) -{ - // When we construct the object from C++ code, we expect the capacity to be at least as large as - // length. JIT-allocated DirectArguments objects play evil tricks, though. - ASSERT(capacity >= length); -} - -DirectArguments* DirectArguments::createUninitialized( - VM& vm, Structure* structure, unsigned length, unsigned capacity) -{ - DirectArguments* result = - new (NotNull, allocateCell<DirectArguments>(vm.heap, allocationSize(capacity))) - DirectArguments(vm, structure, length, capacity); - result->finishCreation(vm); - return result; -} - -DirectArguments* DirectArguments::create(VM& vm, Structure* structure, unsigned length, unsigned capacity) -{ - DirectArguments* result = createUninitialized(vm, structure, length, capacity); - - for (unsigned i = capacity; i--;) - result->storage()[i].clear(); - - return result; -} - -DirectArguments* DirectArguments::createByCopying(ExecState* exec) -{ - VM& vm = exec->vm(); - - unsigned length = exec->argumentCount(); - unsigned capacity = std::max(length, static_cast<unsigned>(exec->codeBlock()->numParameters() - 1)); - DirectArguments* result = createUninitialized( - vm, exec->lexicalGlobalObject()->directArgumentsStructure(), length, capacity); - - for (unsigned i = capacity; i--;) - result->storage()[i].set(vm, result, exec->getArgumentUnsafe(i)); - - result->callee().set(vm, result, jsCast<JSFunction*>(exec->callee())); - - return result; -} - -void DirectArguments::visitChildren(JSCell* thisCell, SlotVisitor& visitor) -{ - DirectArguments* thisObject = static_cast<DirectArguments*>(thisCell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - Base::visitChildren(thisObject, visitor); - - visitor.appendValues(thisObject->storage(), std::max(thisObject->m_length, thisObject->m_minCapacity)); - visitor.append(&thisObject->m_callee); - - if (thisObject->m_overrides) { - visitor.copyLater( - thisObject, DirectArgumentsOverridesCopyToken, - thisObject->m_overrides.get(), thisObject->overridesSize()); - } -} - -void DirectArguments::copyBackingStore(JSCell* thisCell, CopyVisitor& visitor, CopyToken token) -{ - DirectArguments* thisObject = static_cast<DirectArguments*>(thisCell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - - RELEASE_ASSERT(token == DirectArgumentsOverridesCopyToken); - - bool* oldOverrides = thisObject->m_overrides.get(); - if (!oldOverrides) - return; - - if (visitor.checkIfShouldCopy(oldOverrides)) { - bool* newOverrides = static_cast<bool*>(visitor.allocateNewSpace(thisObject->overridesSize())); - memcpy(newOverrides, oldOverrides, thisObject->m_length); - thisObject->m_overrides.setWithoutWriteBarrier(newOverrides); - visitor.didCopy(oldOverrides, thisObject->overridesSize()); - } -} - -Structure* DirectArguments::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) -{ - return Structure::create(vm, globalObject, prototype, TypeInfo(DirectArgumentsType, StructureFlags), info()); -} - -void DirectArguments::overrideThings(VM& vm) -{ - RELEASE_ASSERT(!m_overrides); - - putDirect(vm, vm.propertyNames->length, jsNumber(m_length), DontEnum); - putDirect(vm, vm.propertyNames->callee, m_callee.get(), DontEnum); - putDirect(vm, vm.propertyNames->iteratorSymbol, globalObject()->arrayProtoValuesFunction(), DontEnum); - - void* backingStore; - RELEASE_ASSERT(vm.heap.tryAllocateStorage(this, overridesSize(), &backingStore)); - m_overrides.set(vm, this, static_cast<bool*>(backingStore)); - for (unsigned i = m_length; i--;) - m_overrides.get()[i] = false; -} - -void DirectArguments::overrideThingsIfNecessary(VM& vm) -{ - if (!m_overrides) - overrideThings(vm); -} - -void DirectArguments::overrideArgument(VM& vm, unsigned index) -{ - overrideThingsIfNecessary(vm); - m_overrides.get()[index] = true; -} - -void DirectArguments::copyToArguments(ExecState* exec, VirtualRegister firstElementDest, unsigned offset, unsigned length) -{ - if (!m_overrides) { - unsigned limit = std::min(length + offset, m_length); - unsigned i; - VirtualRegister start = firstElementDest - offset; - for (i = offset; i < limit; ++i) - exec->r(start + i) = storage()[i].get(); - for (; i < length; ++i) - exec->r(start + i) = get(exec, i); - return; - } - - GenericArguments::copyToArguments(exec, firstElementDest, offset, length); -} - -unsigned DirectArguments::overridesSize() -{ - // We always allocate something; in the relatively uncommon case of overriding an empty argument we - // still allocate so that m_overrides is non-null. We use that to indicate that the other properties - // (length, etc) are overridden. - return WTF::roundUpToMultipleOf<8>(m_length ? m_length : 1); -} - -} // namespace JSC - diff --git a/Source/JavaScriptCore/runtime/DirectArguments.h b/Source/JavaScriptCore/runtime/DirectArguments.h deleted file mode 100644 index 14bb8bbb3..000000000 --- a/Source/JavaScriptCore/runtime/DirectArguments.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2015 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 DirectArguments_h -#define DirectArguments_h - -#include "DirectArgumentsOffset.h" -#include "GenericArguments.h" - -namespace JSC { - -// This is an Arguments-class object that we create when you say "arguments" inside a function, -// and none of the arguments are captured in the function's activation. The function will copy all -// of its arguments into this object, and all subsequent accesses to the arguments will go through -// this object thereafter. Special support is in place for mischevious events like the arguments -// being deleted (something like "delete arguments[0]") or reconfigured (broadly, we say deletions -// and reconfigurations mean that the respective argument was "overridden"). -// -// To speed allocation, this object will hold all of the arguments in-place. The arguments as well -// as a table of flags saying which arguments were overridden. -class DirectArguments : public GenericArguments<DirectArguments> { -private: - DirectArguments(VM&, Structure*, unsigned length, unsigned capacity); - -public: - // Creates an arguments object but leaves it uninitialized. This is dangerous if we GC right - // after allocation. - static DirectArguments* createUninitialized(VM&, Structure*, unsigned length, unsigned capacity); - - // Creates an arguments object and initializes everything to the empty value. Use this if you - // cannot guarantee that you'll immediately initialize all of the elements. - static DirectArguments* create(VM&, Structure*, unsigned length, unsigned capacity); - - // Creates an arguments object by copying the argumnets from the stack. - static DirectArguments* createByCopying(ExecState*); - - static void visitChildren(JSCell*, SlotVisitor&); - static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken); - - uint32_t internalLength() const - { - return m_length; - } - - uint32_t length(ExecState* exec) const - { - if (UNLIKELY(m_overrides)) - return get(exec, exec->propertyNames().length).toUInt32(exec); - return m_length; - } - - bool canAccessIndexQuickly(uint32_t i) const - { - return i < m_length && (!m_overrides || !m_overrides.get()[i]); - } - - bool canAccessArgumentIndexQuicklyInDFG(uint32_t i) const - { - return i < m_length && !overrodeThings(); - } - - JSValue getIndexQuickly(uint32_t i) const - { - ASSERT_WITH_SECURITY_IMPLICATION(canAccessIndexQuickly(i)); - return const_cast<DirectArguments*>(this)->storage()[i].get(); - } - - void setIndexQuickly(VM& vm, uint32_t i, JSValue value) - { - ASSERT_WITH_SECURITY_IMPLICATION(canAccessIndexQuickly(i)); - storage()[i].set(vm, this, value); - } - - WriteBarrier<JSFunction>& callee() - { - return m_callee; - } - - WriteBarrier<Unknown>& argument(DirectArgumentsOffset offset) - { - ASSERT(offset); - ASSERT_WITH_SECURITY_IMPLICATION(offset.offset() < std::max(m_length, m_minCapacity)); - return storage()[offset.offset()]; - } - - // Methods intended for use by the GenericArguments mixin. - bool overrodeThings() const { return !!m_overrides; } - void overrideThings(VM&); - void overrideThingsIfNecessary(VM&); - void overrideArgument(VM&, unsigned index); - - void copyToArguments(ExecState*, VirtualRegister firstElementDest, unsigned offset, unsigned length); - - DECLARE_INFO; - - static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype); - - static ptrdiff_t offsetOfCallee() { return OBJECT_OFFSETOF(DirectArguments, m_callee); } - static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(DirectArguments, m_length); } - static ptrdiff_t offsetOfMinCapacity() { return OBJECT_OFFSETOF(DirectArguments, m_minCapacity); } - static ptrdiff_t offsetOfOverrides() { return OBJECT_OFFSETOF(DirectArguments, m_overrides); } - - static size_t storageOffset() - { - return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(DirectArguments)); - } - - static size_t offsetOfSlot(uint32_t index) - { - return storageOffset() + sizeof(WriteBarrier<Unknown>) * index; - } - - static size_t allocationSize(uint32_t capacity) - { - return offsetOfSlot(capacity); - } - -private: - WriteBarrier<Unknown>* storage() - { - return bitwise_cast<WriteBarrier<Unknown>*>(bitwise_cast<char*>(this) + storageOffset()); - } - - unsigned overridesSize(); - - WriteBarrier<JSFunction> m_callee; - uint32_t m_length; // Always the actual length of captured arguments and never what was stored into the length property. - uint32_t m_minCapacity; // The max of this and length determines the capacity of this object. It may be the actual capacity, or maybe something smaller. We arrange it this way to be kind to the JITs. - CopyWriteBarrier<bool> m_overrides; // If non-null, it means that length, callee, and caller are fully materialized properties. -}; - -} // namespace JSC - -#endif // DirectArguments_h - diff --git a/Source/JavaScriptCore/runtime/DirectArgumentsOffset.h b/Source/JavaScriptCore/runtime/DirectArgumentsOffset.h deleted file mode 100644 index 88a51874e..000000000 --- a/Source/JavaScriptCore/runtime/DirectArgumentsOffset.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2015 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 DirectArgumentsOffset_h -#define DirectArgumentsOffset_h - -#include "GenericOffset.h" -#include <wtf/PrintStream.h> - -namespace JSC { - -// This is an offset into the special arguments object, which captures the arguments to a -// function. It only comes into play if the arguments aren't also lifted into the activation. -// If they were then accesses to the arguments would resolve to a ScopeOffset and not a -// DirectArgumentsOffset. -class DirectArgumentsOffset : public GenericOffset<DirectArgumentsOffset> { -public: - DirectArgumentsOffset() { } - - explicit DirectArgumentsOffset(unsigned offset) - : GenericOffset(offset) - { - } - - void dump(PrintStream&) const; -}; - -} // namespace JSC - -#endif // DirectArgumentsOffset_h - diff --git a/Source/JavaScriptCore/runtime/DumpContext.cpp b/Source/JavaScriptCore/runtime/DumpContext.cpp index f07c2b25d..0546f4c87 100644 --- a/Source/JavaScriptCore/runtime/DumpContext.cpp +++ b/Source/JavaScriptCore/runtime/DumpContext.cpp @@ -10,10 +10,10 @@ * 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 + * 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 INC. OR + * 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 diff --git a/Source/JavaScriptCore/runtime/DumpContext.h b/Source/JavaScriptCore/runtime/DumpContext.h index ddd6ba06e..9ec931318 100644 --- a/Source/JavaScriptCore/runtime/DumpContext.h +++ b/Source/JavaScriptCore/runtime/DumpContext.h @@ -10,10 +10,10 @@ * 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 + * 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 INC. OR + * 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 diff --git a/Source/JavaScriptCore/runtime/EnumerationMode.h b/Source/JavaScriptCore/runtime/EnumerationMode.h deleted file mode 100644 index 86d53e049..000000000 --- a/Source/JavaScriptCore/runtime/EnumerationMode.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2014 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 EnumerationMode_h -#define EnumerationMode_h - -namespace JSC { - -enum class PropertyNameMode { - Symbols = 1 << 0, - Strings = 1 << 1, - StringsAndSymbols = Symbols | Strings, -}; - -enum class DontEnumPropertiesMode { - Include, - Exclude -}; - -enum class JSObjectPropertiesMode { - Include, - Exclude -}; - -class EnumerationMode { -public: - EnumerationMode(DontEnumPropertiesMode dontEnumPropertiesMode = DontEnumPropertiesMode::Exclude, JSObjectPropertiesMode jsObjectPropertiesMode = JSObjectPropertiesMode::Include) - : m_dontEnumPropertiesMode(dontEnumPropertiesMode) - , m_jsObjectPropertiesMode(jsObjectPropertiesMode) - { - } - - EnumerationMode(const EnumerationMode& mode, JSObjectPropertiesMode jsObjectPropertiesMode) - : m_dontEnumPropertiesMode(mode.m_dontEnumPropertiesMode) - , m_jsObjectPropertiesMode(jsObjectPropertiesMode) - { - } - - // Add other constructors as needed for convenience - - bool includeDontEnumProperties() - { - return m_dontEnumPropertiesMode == DontEnumPropertiesMode::Include; - } - - bool includeJSObjectProperties() - { - return m_jsObjectPropertiesMode == JSObjectPropertiesMode::Include; - } - -private: - DontEnumPropertiesMode m_dontEnumPropertiesMode; - JSObjectPropertiesMode m_jsObjectPropertiesMode; -}; - -} // namespace JSC - -#endif // EnumerationMode_h diff --git a/Source/JavaScriptCore/runtime/Error.cpp b/Source/JavaScriptCore/runtime/Error.cpp index 00285a675..a87be188a 100644 --- a/Source/JavaScriptCore/runtime/Error.cpp +++ b/Source/JavaScriptCore/runtime/Error.cpp @@ -34,7 +34,7 @@ #include "JSObject.h" #include "JSString.h" #include "NativeErrorConstructor.h" -#include "JSCInlines.h" +#include "Operations.h" #include "SourceCode.h" #include <wtf/text/StringBuilder.h> @@ -44,234 +44,123 @@ namespace JSC { static const char* linePropertyName = "line"; static const char* sourceURLPropertyName = "sourceURL"; -JSObject* createError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender) +JSObject* createError(JSGlobalObject* globalObject, const String& message) { ASSERT(!message.isEmpty()); - JSGlobalObject* globalObject = exec->lexicalGlobalObject(); - return ErrorInstance::create(exec, globalObject->vm(), globalObject->errorStructure(), message, appender, TypeNothing, true); + return ErrorInstance::create(globalObject->vm(), globalObject->errorStructure(), message); } -JSObject* createEvalError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender) +JSObject* createEvalError(JSGlobalObject* globalObject, const String& message) { ASSERT(!message.isEmpty()); - JSGlobalObject* globalObject = exec->lexicalGlobalObject(); - return ErrorInstance::create(exec, globalObject->vm(), globalObject->evalErrorConstructor()->errorStructure(), message, appender, TypeNothing, true); + return ErrorInstance::create(globalObject->vm(), globalObject->evalErrorConstructor()->errorStructure(), message); } -JSObject* createRangeError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender) +JSObject* createRangeError(JSGlobalObject* globalObject, const String& message) { ASSERT(!message.isEmpty()); - JSGlobalObject* globalObject = exec->lexicalGlobalObject(); - return ErrorInstance::create(exec, globalObject->vm(), globalObject->rangeErrorConstructor()->errorStructure(), message, appender, TypeNothing, true); + return ErrorInstance::create(globalObject->vm(), globalObject->rangeErrorConstructor()->errorStructure(), message); } -JSObject* createReferenceError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender) +JSObject* createReferenceError(JSGlobalObject* globalObject, const String& message) { ASSERT(!message.isEmpty()); - JSGlobalObject* globalObject = exec->lexicalGlobalObject(); - return ErrorInstance::create(exec, globalObject->vm(), globalObject->referenceErrorConstructor()->errorStructure(), message, appender, TypeNothing, true); + return ErrorInstance::create(globalObject->vm(), globalObject->referenceErrorConstructor()->errorStructure(), message); } -JSObject* createSyntaxError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender) +JSObject* createSyntaxError(JSGlobalObject* globalObject, const String& message) { ASSERT(!message.isEmpty()); - JSGlobalObject* globalObject = exec->lexicalGlobalObject(); - return ErrorInstance::create(exec, globalObject->vm(), globalObject->syntaxErrorConstructor()->errorStructure(), message, appender, TypeNothing, true); + return ErrorInstance::create(globalObject->vm(), globalObject->syntaxErrorConstructor()->errorStructure(), message); } -JSObject* createTypeError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender, RuntimeType type) +JSObject* createTypeError(JSGlobalObject* globalObject, const String& message) { ASSERT(!message.isEmpty()); - JSGlobalObject* globalObject = exec->lexicalGlobalObject(); - return ErrorInstance::create(exec, globalObject->vm(), globalObject->typeErrorConstructor()->errorStructure(), message, appender, type, true); + return ErrorInstance::create(globalObject->vm(), globalObject->typeErrorConstructor()->errorStructure(), message); } -JSObject* createNotEnoughArgumentsError(ExecState* exec, ErrorInstance::SourceAppender appender) +JSObject* createNotEnoughArgumentsError(JSGlobalObject* globalObject) { - return createTypeError(exec, ASCIILiteral("Not enough arguments"), appender, TypeNothing); + return createTypeError(globalObject, ASCIILiteral("Not enough arguments")); } -JSObject* createURIError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender) +JSObject* createURIError(JSGlobalObject* globalObject, const String& message) { ASSERT(!message.isEmpty()); - JSGlobalObject* globalObject = exec->lexicalGlobalObject(); - return ErrorInstance::create(exec, globalObject->vm(), globalObject->URIErrorConstructor()->errorStructure(), message, appender, TypeNothing, true); + return ErrorInstance::create(globalObject->vm(), globalObject->URIErrorConstructor()->errorStructure(), message); } -JSObject* createOutOfMemoryError(ExecState* exec, ErrorInstance::SourceAppender appender) -{ - return createError(exec, ASCIILiteral("Out of memory"), appender); -} - - -class FindFirstCallerFrameWithCodeblockFunctor { -public: - FindFirstCallerFrameWithCodeblockFunctor(CallFrame* startCallFrame) - : m_startCallFrame(startCallFrame) - , m_foundCallFrame(nullptr) - , m_foundStartCallFrame(false) - , m_index(0) - { } - - StackVisitor::Status operator()(StackVisitor& visitor) - { - if (!m_foundStartCallFrame && (visitor->callFrame() == m_startCallFrame)) - m_foundStartCallFrame = true; - - if (m_foundStartCallFrame) { - if (visitor->callFrame()->codeBlock()) { - m_foundCallFrame = visitor->callFrame(); - return StackVisitor::Done; - } - m_index++; - } - - return StackVisitor::Continue; - } - - CallFrame* foundCallFrame() const { return m_foundCallFrame; } - unsigned index() const { return m_index; } - -private: - CallFrame* m_startCallFrame; - CallFrame* m_foundCallFrame; - bool m_foundStartCallFrame; - unsigned m_index; -}; - -bool addErrorInfoAndGetBytecodeOffset(ExecState* exec, VM& vm, JSObject* obj, bool useCurrentFrame, CallFrame*& callFrame, unsigned &bytecodeOffset) -{ - Vector<StackFrame> stackTrace = Vector<StackFrame>(); - - if (exec && stackTrace.isEmpty()) - vm.interpreter->getStackTrace(stackTrace); - - if (!stackTrace.isEmpty()) { - - ASSERT(exec == vm.topCallFrame || exec == exec->lexicalGlobalObject()->globalExec() || exec == exec->vmEntryGlobalObject()->globalExec()); - - StackFrame* stackFrame; - for (unsigned i = 0 ; i < stackTrace.size(); ++i) { - stackFrame = &stackTrace.at(i); - if (stackFrame->bytecodeOffset) - break; - } - - if (bytecodeOffset) { - FindFirstCallerFrameWithCodeblockFunctor functor(exec); - vm.topCallFrame->iterate(functor); - callFrame = functor.foundCallFrame(); - unsigned stackIndex = functor.index(); - bytecodeOffset = stackTrace.at(stackIndex).bytecodeOffset; - } - - unsigned line; - unsigned column; - stackFrame->computeLineAndColumn(line, column); - obj->putDirect(vm, vm.propertyNames->line, jsNumber(line), ReadOnly | DontDelete); - obj->putDirect(vm, vm.propertyNames->column, jsNumber(column), ReadOnly | DontDelete); - - if (!stackFrame->sourceURL.isEmpty()) - obj->putDirect(vm, vm.propertyNames->sourceURL, jsString(&vm, stackFrame->sourceURL), ReadOnly | DontDelete); - - if (!useCurrentFrame) - stackTrace.remove(0); - obj->putDirect(vm, vm.propertyNames->stack, vm.interpreter->stackTraceAsString(vm.topCallFrame, stackTrace), DontEnum); - - return true; - } - return false; -} - -void addErrorInfo(ExecState* exec, JSObject* obj, bool useCurrentFrame) +JSObject* createError(ExecState* exec, const String& message) { - CallFrame* callFrame = nullptr; - unsigned bytecodeOffset = 0; - addErrorInfoAndGetBytecodeOffset(exec, exec->vm(), obj, useCurrentFrame, callFrame, bytecodeOffset); + return createError(exec->lexicalGlobalObject(), message); } -JSObject* addErrorInfo(CallFrame* callFrame, JSObject* error, int line, const SourceCode& source) -{ - VM* vm = &callFrame->vm(); - const String& sourceURL = source.provider()->url(); - - if (line != -1) - error->putDirect(*vm, Identifier::fromString(vm, linePropertyName), jsNumber(line), ReadOnly | DontDelete); - if (!sourceURL.isNull()) - error->putDirect(*vm, Identifier::fromString(vm, sourceURLPropertyName), jsString(vm, sourceURL), ReadOnly | DontDelete); - return error; -} - - -bool hasErrorInfo(ExecState* exec, JSObject* error) +JSObject* createEvalError(ExecState* exec, const String& message) { - return error->hasProperty(exec, Identifier::fromString(exec, linePropertyName)) - || error->hasProperty(exec, Identifier::fromString(exec, sourceURLPropertyName)); + return createEvalError(exec->lexicalGlobalObject(), message); } -JSObject* throwTypeError(ExecState* exec) +JSObject* createRangeError(ExecState* exec, const String& message) { - return exec->vm().throwException(exec, createTypeError(exec)); + return createRangeError(exec->lexicalGlobalObject(), message); } -JSObject* throwSyntaxError(ExecState* exec) +JSObject* createReferenceError(ExecState* exec, const String& message) { - return exec->vm().throwException(exec, createSyntaxError(exec, ASCIILiteral("Syntax error"))); + return createReferenceError(exec->lexicalGlobalObject(), message); } - -JSObject* createError(ExecState* exec, const String& message) +JSObject* createSyntaxError(ExecState* exec, const String& message) { - return createError(exec, message, nullptr); + return createSyntaxError(exec->lexicalGlobalObject(), message); } -JSObject* createEvalError(ExecState* exec, const String& message) +JSObject* createTypeError(ExecState* exec, const String& message) { - return createEvalError(exec, message, nullptr); + return createTypeError(exec->lexicalGlobalObject(), message); } -JSObject* createRangeError(ExecState* exec, const String& message) +JSObject* createNotEnoughArgumentsError(ExecState* exec) { - return createRangeError(exec, message, nullptr); + return createNotEnoughArgumentsError(exec->lexicalGlobalObject()); } -JSObject* createReferenceError(ExecState* exec, const String& message) +JSObject* createURIError(ExecState* exec, const String& message) { - return createReferenceError(exec, message, nullptr); + return createURIError(exec->lexicalGlobalObject(), message); } -JSObject* createSyntaxError(ExecState* exec, const String& message) +JSObject* addErrorInfo(CallFrame* callFrame, JSObject* error, int line, const SourceCode& source) { - return createSyntaxError(exec, message, nullptr); -} + VM* vm = &callFrame->vm(); + const String& sourceURL = source.provider()->url(); -JSObject* createTypeError(ExecState* exec) -{ - return createTypeError(exec, ASCIILiteral("Type error")); + if (line != -1) + error->putDirect(*vm, Identifier(vm, linePropertyName), jsNumber(line), ReadOnly | DontDelete); + if (!sourceURL.isNull()) + error->putDirect(*vm, Identifier(vm, sourceURLPropertyName), jsString(vm, sourceURL), ReadOnly | DontDelete); + return error; } -JSObject* createTypeError(ExecState* exec, const String& message) -{ - return createTypeError(exec, message, nullptr, TypeNothing); -} -JSObject* createNotEnoughArgumentsError(ExecState* exec) +bool hasErrorInfo(ExecState* exec, JSObject* error) { - return createNotEnoughArgumentsError(exec, nullptr); + return error->hasProperty(exec, Identifier(exec, linePropertyName)) + || error->hasProperty(exec, Identifier(exec, sourceURLPropertyName)); } -JSObject* createURIError(ExecState* exec, const String& message) +JSObject* throwTypeError(ExecState* exec) { - return createURIError(exec, message, nullptr); + return exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Type error"))); } -JSObject* createOutOfMemoryError(ExecState* exec) +JSObject* throwSyntaxError(ExecState* exec) { - return createOutOfMemoryError(exec, nullptr); + return exec->vm().throwException(exec, createSyntaxError(exec, ASCIILiteral("Syntax error"))); } - -const ClassInfo StrictModeTypeErrorFunction::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(StrictModeTypeErrorFunction) }; +const ClassInfo StrictModeTypeErrorFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(StrictModeTypeErrorFunction) }; void StrictModeTypeErrorFunction::destroy(JSCell* cell) { diff --git a/Source/JavaScriptCore/runtime/Error.h b/Source/JavaScriptCore/runtime/Error.h index ec30a3dc4..bec5dd756 100644 --- a/Source/JavaScriptCore/runtime/Error.h +++ b/Source/JavaScriptCore/runtime/Error.h @@ -23,120 +23,108 @@ #ifndef Error_h #define Error_h -#include "ErrorInstance.h" #include "InternalFunction.h" #include "Interpreter.h" #include "JSObject.h" #include <stdint.h> - namespace JSC { -class ExecState; -class VM; -class JSGlobalObject; -class JSObject; -class SourceCode; -class Structure; - -// ExecState wrappers. -JSObject* createError(ExecState*, const String&, ErrorInstance::SourceAppender); -JSObject* createEvalError(ExecState*, const String&, ErrorInstance::SourceAppender); -JSObject* createRangeError(ExecState*, const String&, ErrorInstance::SourceAppender); -JSObject* createReferenceError(ExecState*, const String&, ErrorInstance::SourceAppender); -JSObject* createSyntaxError(ExecState*, const String&, ErrorInstance::SourceAppender); -JSObject* createTypeError(ExecState*, const String&, ErrorInstance::SourceAppender, RuntimeType); -JSObject* createNotEnoughArgumentsError(ExecState*, ErrorInstance::SourceAppender); -JSObject* createURIError(ExecState*, const String&, ErrorInstance::SourceAppender); -JSObject* createOutOfMemoryError(ExecState*, ErrorInstance::SourceAppender); - - -JS_EXPORT_PRIVATE JSObject* createError(ExecState*, const String&); -JS_EXPORT_PRIVATE JSObject* createEvalError(ExecState*, const String&); -JS_EXPORT_PRIVATE JSObject* createRangeError(ExecState*, const String&); -JS_EXPORT_PRIVATE JSObject* createReferenceError(ExecState*, const String&); -JS_EXPORT_PRIVATE JSObject* createSyntaxError(ExecState*, const String&); -JS_EXPORT_PRIVATE JSObject* createTypeError(ExecState*); -JS_EXPORT_PRIVATE JSObject* createTypeError(ExecState*, const String&); -JS_EXPORT_PRIVATE JSObject* createNotEnoughArgumentsError(ExecState*); -JS_EXPORT_PRIVATE JSObject* createURIError(ExecState*, const String&); -JS_EXPORT_PRIVATE JSObject* createOutOfMemoryError(ExecState*); - - -bool addErrorInfoAndGetBytecodeOffset(ExecState*, VM&, JSObject*, bool, CallFrame*&, unsigned&); - -bool hasErrorInfo(ExecState*, JSObject* error); -JS_EXPORT_PRIVATE void addErrorInfo(ExecState*, JSObject*, bool); -JSObject* addErrorInfo(ExecState*, JSObject* error, int line, const SourceCode&); - -// Methods to throw Errors. - -// Convenience wrappers, create an throw an exception with a default message. -JS_EXPORT_PRIVATE JSObject* throwTypeError(ExecState*); -JS_EXPORT_PRIVATE JSObject* throwSyntaxError(ExecState*); -inline JSObject* throwRangeError(ExecState* state, const String& errorMessage) { return state->vm().throwException(state, createRangeError(state, errorMessage)); } - -// Convenience wrappers, wrap result as an EncodedJSValue. -inline void throwVMError(ExecState* exec, Exception* exception) { exec->vm().throwException(exec, exception); } -inline EncodedJSValue throwVMError(ExecState* exec, JSValue error) { return JSValue::encode(exec->vm().throwException(exec, error)); } -inline EncodedJSValue throwVMTypeError(ExecState* exec) { return JSValue::encode(throwTypeError(exec)); } -inline EncodedJSValue throwVMTypeError(ExecState* exec, const String& errorMessage) { return JSValue::encode(throwTypeError(exec, errorMessage)); } -inline EncodedJSValue throwVMRangeError(ExecState* state, const String& errorMessage) { return JSValue::encode(throwRangeError(state, errorMessage)); } - -class StrictModeTypeErrorFunction : public InternalFunction { -private: - StrictModeTypeErrorFunction(VM& vm, Structure* structure, const String& message) - : InternalFunction(vm, structure) - , m_message(message) - { - } - - static void destroy(JSCell*); - -public: - typedef InternalFunction Base; - - static StrictModeTypeErrorFunction* create(VM& vm, Structure* structure, const String& message) - { - StrictModeTypeErrorFunction* function = new (NotNull, allocateCell<StrictModeTypeErrorFunction>(vm.heap)) StrictModeTypeErrorFunction(vm, structure, message); - function->finishCreation(vm, String()); - return function; - } - - static EncodedJSValue JSC_HOST_CALL constructThrowTypeError(ExecState* exec) - { - throwTypeError(exec, static_cast<StrictModeTypeErrorFunction*>(exec->callee())->m_message); - return JSValue::encode(jsNull()); - } - - static ConstructType getConstructData(JSCell*, ConstructData& constructData) - { - constructData.native.function = constructThrowTypeError; - return ConstructTypeHost; - } - - static EncodedJSValue JSC_HOST_CALL callThrowTypeError(ExecState* exec) - { - throwTypeError(exec, static_cast<StrictModeTypeErrorFunction*>(exec->callee())->m_message); - return JSValue::encode(jsNull()); - } - - static CallType getCallData(JSCell*, CallData& callData) - { - callData.native.function = callThrowTypeError; - return CallTypeHost; - } - - DECLARE_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } - -private: - String m_message; -}; + class ExecState; + class VM; + class JSGlobalObject; + class JSObject; + class SourceCode; + class Structure; + + // Methods to create a range of internal errors. + JSObject* createError(JSGlobalObject*, const String&); + JSObject* createEvalError(JSGlobalObject*, const String&); + JSObject* createRangeError(JSGlobalObject*, const String&); + JSObject* createReferenceError(JSGlobalObject*, const String&); + JSObject* createSyntaxError(JSGlobalObject*, const String&); + JSObject* createTypeError(JSGlobalObject*, const String&); + JSObject* createNotEnoughArgumentsError(JSGlobalObject*); + JSObject* createURIError(JSGlobalObject*, const String&); + // ExecState wrappers. + JS_EXPORT_PRIVATE JSObject* createError(ExecState*, const String&); + JSObject* createEvalError(ExecState*, const String&); + JS_EXPORT_PRIVATE JSObject* createRangeError(ExecState*, const String&); + JS_EXPORT_PRIVATE JSObject* createReferenceError(ExecState*, const String&); + JS_EXPORT_PRIVATE JSObject* createSyntaxError(ExecState*, const String&); + JS_EXPORT_PRIVATE JSObject* createTypeError(ExecState*, const String&); + JS_EXPORT_PRIVATE JSObject* createNotEnoughArgumentsError(ExecState*); + JSObject* createURIError(ExecState*, const String&); + + // Methods to add + bool hasErrorInfo(ExecState*, JSObject* error); + // ExecState wrappers. + JSObject* addErrorInfo(ExecState*, JSObject* error, int line, const SourceCode&); + + // Methods to throw Errors. + + // Convenience wrappers, create an throw an exception with a default message. + JS_EXPORT_PRIVATE JSObject* throwTypeError(ExecState*); + JS_EXPORT_PRIVATE JSObject* throwSyntaxError(ExecState*); + + // Convenience wrappers, wrap result as an EncodedJSValue. + inline EncodedJSValue throwVMError(ExecState* exec, JSValue error) { return JSValue::encode(exec->vm().throwException(exec, error)); } + inline EncodedJSValue throwVMTypeError(ExecState* exec) { return JSValue::encode(throwTypeError(exec)); } + + class StrictModeTypeErrorFunction : public InternalFunction { + private: + StrictModeTypeErrorFunction(VM& vm, Structure* structure, const String& message) + : InternalFunction(vm, structure) + , m_message(message) + { + } + + static void destroy(JSCell*); + + public: + typedef InternalFunction Base; + + static StrictModeTypeErrorFunction* create(VM& vm, Structure* structure, const String& message) + { + StrictModeTypeErrorFunction* function = new (NotNull, allocateCell<StrictModeTypeErrorFunction>(vm.heap)) StrictModeTypeErrorFunction(vm, structure, message); + function->finishCreation(vm, String()); + return function; + } + + static EncodedJSValue JSC_HOST_CALL constructThrowTypeError(ExecState* exec) + { + throwTypeError(exec, static_cast<StrictModeTypeErrorFunction*>(exec->callee())->m_message); + return JSValue::encode(jsNull()); + } + + static ConstructType getConstructData(JSCell*, ConstructData& constructData) + { + constructData.native.function = constructThrowTypeError; + return ConstructTypeHost; + } + + static EncodedJSValue JSC_HOST_CALL callThrowTypeError(ExecState* exec) + { + throwTypeError(exec, static_cast<StrictModeTypeErrorFunction*>(exec->callee())->m_message); + return JSValue::encode(jsNull()); + } + + static CallType getCallData(JSCell*, CallData& callData) + { + callData.native.function = callThrowTypeError; + return CallTypeHost; + } + + DECLARE_INFO; + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } + + private: + String m_message; + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ErrorConstructor.cpp b/Source/JavaScriptCore/runtime/ErrorConstructor.cpp index 30c4faae5..2e31e7fd5 100644 --- a/Source/JavaScriptCore/runtime/ErrorConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ErrorConstructor.cpp @@ -25,13 +25,13 @@ #include "Interpreter.h" #include "JSGlobalObject.h" #include "JSString.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ErrorConstructor); -const ClassInfo ErrorConstructor::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(ErrorConstructor) }; +const ClassInfo ErrorConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ErrorConstructor) }; ErrorConstructor::ErrorConstructor(VM& vm, Structure* structure) : InternalFunction(vm, structure) @@ -52,7 +52,10 @@ EncodedJSValue JSC_HOST_CALL Interpreter::constructWithErrorConstructor(ExecStat { JSValue message = exec->argumentCount() ? exec->argument(0) : jsUndefined(); Structure* errorStructure = asInternalFunction(exec->callee())->globalObject()->errorStructure(); - return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, nullptr, TypeNothing, false)); + Vector<StackFrame> stackTrace; + exec->vm().interpreter->getStackTrace(stackTrace, std::numeric_limits<size_t>::max()); + stackTrace.remove(0); + return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, stackTrace)); } ConstructType ErrorConstructor::getConstructData(JSCell*, ConstructData& constructData) @@ -65,7 +68,10 @@ EncodedJSValue JSC_HOST_CALL Interpreter::callErrorConstructor(ExecState* exec) { JSValue message = exec->argumentCount() ? exec->argument(0) : jsUndefined(); Structure* errorStructure = asInternalFunction(exec->callee())->globalObject()->errorStructure(); - return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, nullptr, TypeNothing, false)); + Vector<StackFrame> stackTrace; + exec->vm().interpreter->getStackTrace(stackTrace, std::numeric_limits<size_t>::max()); + stackTrace.remove(0); + return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, stackTrace)); } CallType ErrorConstructor::getCallData(JSCell*, CallData& callData) diff --git a/Source/JavaScriptCore/runtime/ErrorConstructor.h b/Source/JavaScriptCore/runtime/ErrorConstructor.h index b11894dbe..29283d01b 100644 --- a/Source/JavaScriptCore/runtime/ErrorConstructor.h +++ b/Source/JavaScriptCore/runtime/ErrorConstructor.h @@ -26,34 +26,34 @@ namespace JSC { -class ErrorPrototype; + class ErrorPrototype; -class ErrorConstructor : public InternalFunction { -public: - typedef InternalFunction Base; + class ErrorConstructor : public InternalFunction { + public: + typedef InternalFunction Base; - static ErrorConstructor* create(VM& vm, Structure* structure, ErrorPrototype* errorPrototype) - { - ErrorConstructor* constructor = new (NotNull, allocateCell<ErrorConstructor>(vm.heap)) ErrorConstructor(vm, structure); - constructor->finishCreation(vm, errorPrototype); - return constructor; - } + static ErrorConstructor* create(VM& vm, Structure* structure, ErrorPrototype* errorPrototype) + { + ErrorConstructor* constructor = new (NotNull, allocateCell<ErrorConstructor>(vm.heap)) ErrorConstructor(vm, structure); + constructor->finishCreation(vm, errorPrototype); + return constructor; + } - DECLARE_INFO; + DECLARE_INFO; - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } -protected: - void finishCreation(VM&, ErrorPrototype*); + protected: + void finishCreation(VM&, ErrorPrototype*); -private: - ErrorConstructor(VM&, Structure*); - static ConstructType getConstructData(JSCell*, ConstructData&); - static CallType getCallData(JSCell*, CallData&); -}; + private: + ErrorConstructor(VM&, Structure*); + static ConstructType getConstructData(JSCell*, ConstructData&); + static CallType getCallData(JSCell*, CallData&); + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ErrorHandlingScope.cpp b/Source/JavaScriptCore/runtime/ErrorHandlingScope.cpp deleted file mode 100644 index beb52a334..000000000 --- a/Source/JavaScriptCore/runtime/ErrorHandlingScope.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2014 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 "ErrorHandlingScope.h" - -#include "Interpreter.h" -#include "Options.h" -#include "VM.h" - -namespace JSC { - -ErrorHandlingScope::ErrorHandlingScope(VM& vm) - : m_vm(vm) -{ - RELEASE_ASSERT(m_vm.stackPointerAtVMEntry()); - size_t newReservedZoneSize = Options::errorModeReservedZoneSize(); - m_savedReservedZoneSize = m_vm.updateReservedZoneSize(newReservedZoneSize); -#if !ENABLE(JIT) - m_vm.interpreter->stack().setReservedZoneSize(newReservedZoneSize); -#endif -} - -ErrorHandlingScope::~ErrorHandlingScope() -{ - RELEASE_ASSERT(m_vm.stackPointerAtVMEntry()); - m_vm.updateReservedZoneSize(m_savedReservedZoneSize); -#if !ENABLE(JIT) - m_vm.interpreter->stack().setReservedZoneSize(m_savedReservedZoneSize); -#endif -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ErrorHandlingScope.h b/Source/JavaScriptCore/runtime/ErrorHandlingScope.h deleted file mode 100644 index 451b241e4..000000000 --- a/Source/JavaScriptCore/runtime/ErrorHandlingScope.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2014 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 ErrorHandlingScope_h -#define ErrorHandlingScope_h - -namespace JSC { - -class VM; - -class ErrorHandlingScope { -public: - JS_EXPORT_PRIVATE ErrorHandlingScope(VM&); - JS_EXPORT_PRIVATE ~ErrorHandlingScope(); -private: - VM& m_vm; - size_t m_savedReservedZoneSize; -}; - -} // namespace JSC - -#endif // ErrorHandlingScope_h - diff --git a/Source/JavaScriptCore/runtime/ErrorInstance.cpp b/Source/JavaScriptCore/runtime/ErrorInstance.cpp index 2bf1493bd..c831f9183 100644 --- a/Source/JavaScriptCore/runtime/ErrorInstance.cpp +++ b/Source/JavaScriptCore/runtime/ErrorInstance.cpp @@ -22,171 +22,29 @@ #include "ErrorInstance.h" #include "JSScope.h" -#include "JSCInlines.h" -#include "JSGlobalObjectFunctions.h" -#include <wtf/Vector.h> +#include "Operations.h" namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ErrorInstance); -const ClassInfo ErrorInstance::s_info = { "Error", &JSNonFinalObject::s_info, 0, CREATE_METHOD_TABLE(ErrorInstance) }; +const ClassInfo ErrorInstance::s_info = { "Error", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(ErrorInstance) }; ErrorInstance::ErrorInstance(VM& vm, Structure* structure) : JSNonFinalObject(vm, structure) + , m_appendSourceToMessage(false) { } -static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, unsigned bytecodeOffset) -{ - ErrorInstance::SourceAppender appender = exception->sourceAppender(); - exception->clearSourceAppender(); - RuntimeType type = exception->runtimeTypeForCause(); - exception->clearRuntimeTypeForCause(); - - if (!callFrame->codeBlock()->hasExpressionInfo()) - return; - - int startOffset = 0; - int endOffset = 0; - int divotPoint = 0; - unsigned line = 0; - unsigned column = 0; - - CodeBlock* codeBlock = callFrame->codeBlock(); - codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divotPoint, startOffset, endOffset, line, column); - - int expressionStart = divotPoint - startOffset; - int expressionStop = divotPoint + endOffset; - - const String& sourceString = codeBlock->source()->source(); - if (!expressionStop || expressionStart > static_cast<int>(sourceString.length())) - return; - - VM* vm = &callFrame->vm(); - JSValue jsMessage = exception->getDirect(*vm, vm->propertyNames->message); - if (!jsMessage || !jsMessage.isString()) - return; - - String message = asString(jsMessage)->value(callFrame); - if (expressionStart < expressionStop) - message = appender(message, codeBlock->source()->getRange(expressionStart, expressionStop) , type, ErrorInstance::FoundExactSource); - else { - // No range information, so give a few characters of context. - const StringImpl* data = sourceString.impl(); - int dataLength = sourceString.length(); - int start = expressionStart; - int stop = expressionStart; - // Get up to 20 characters of context to the left and right of the divot, clamping to the line. - // Then strip whitespace. - while (start > 0 && (expressionStart - start < 20) && (*data)[start - 1] != '\n') - start--; - while (start < (expressionStart - 1) && isStrWhiteSpace((*data)[start])) - start++; - while (stop < dataLength && (stop - expressionStart < 20) && (*data)[stop] != '\n') - stop++; - while (stop > expressionStart && isStrWhiteSpace((*data)[stop - 1])) - stop--; - message = appender(message, codeBlock->source()->getRange(start, stop), type, ErrorInstance::FoundApproximateSource); - } - exception->putDirect(*vm, vm->propertyNames->message, jsString(vm, message)); - -} - -class FindFirstCallerFrameWithCodeblockFunctor { -public: - FindFirstCallerFrameWithCodeblockFunctor(CallFrame* startCallFrame) - : m_startCallFrame(startCallFrame) - , m_foundCallFrame(nullptr) - , m_foundStartCallFrame(false) - , m_index(0) - { } - - StackVisitor::Status operator()(StackVisitor& visitor) - { - if (!m_foundStartCallFrame && (visitor->callFrame() == m_startCallFrame)) - m_foundStartCallFrame = true; - - if (m_foundStartCallFrame) { - if (visitor->callFrame()->codeBlock()) { - m_foundCallFrame = visitor->callFrame(); - return StackVisitor::Done; - } - m_index++; - } - - return StackVisitor::Continue; - } - - CallFrame* foundCallFrame() const { return m_foundCallFrame; } - unsigned index() const { return m_index; } - -private: - CallFrame* m_startCallFrame; - CallFrame* m_foundCallFrame; - bool m_foundStartCallFrame; - unsigned m_index; -}; - -static bool addErrorInfoAndGetBytecodeOffset(ExecState* exec, VM& vm, JSObject* obj, bool useCurrentFrame, CallFrame*& callFrame, unsigned &bytecodeOffset) -{ - Vector<StackFrame> stackTrace = Vector<StackFrame>(); - - if (exec && stackTrace.isEmpty()) - vm.interpreter->getStackTrace(stackTrace); - - if (!stackTrace.isEmpty()) { - - ASSERT(exec == vm.topCallFrame || exec == exec->lexicalGlobalObject()->globalExec() || exec == exec->vmEntryGlobalObject()->globalExec()); - - StackFrame* stackFrame; - for (unsigned i = 0 ; i < stackTrace.size(); ++i) { - stackFrame = &stackTrace.at(i); - if (stackFrame->bytecodeOffset) - break; - } - - if (bytecodeOffset) { - FindFirstCallerFrameWithCodeblockFunctor functor(exec); - vm.topCallFrame->iterate(functor); - callFrame = functor.foundCallFrame(); - unsigned stackIndex = functor.index(); - bytecodeOffset = stackTrace.at(stackIndex).bytecodeOffset; - } - - unsigned line; - unsigned column; - stackFrame->computeLineAndColumn(line, column); - obj->putDirect(vm, vm.propertyNames->line, jsNumber(line), ReadOnly | DontDelete); - obj->putDirect(vm, vm.propertyNames->column, jsNumber(column), ReadOnly | DontDelete); - - if (!stackFrame->sourceURL.isEmpty()) - obj->putDirect(vm, vm.propertyNames->sourceURL, jsString(&vm, stackFrame->sourceURL), ReadOnly | DontDelete); - - if (!useCurrentFrame) - stackTrace.remove(0); - obj->putDirect(vm, vm.propertyNames->stack, vm.interpreter->stackTraceAsString(vm.topCallFrame, stackTrace), DontEnum); - - return true; - } - return false; -} - -void ErrorInstance::finishCreation(ExecState* exec, VM& vm, const String& message, bool useCurrentFrame) +void ErrorInstance::finishCreation(VM& vm, const String& message, Vector<StackFrame> stackTrace) { Base::finishCreation(vm); ASSERT(inherits(info())); if (!message.isNull()) putDirect(vm, vm.propertyNames->message, jsString(&vm, message), DontEnum); - - unsigned bytecodeOffset = hasSourceAppender(); - CallFrame* callFrame = nullptr; - bool hasTrace = addErrorInfoAndGetBytecodeOffset(exec, vm, this, useCurrentFrame, callFrame, bytecodeOffset); - - if (hasTrace && callFrame && hasSourceAppender()) { - if (callFrame && callFrame->codeBlock()) - appendSourceToError(callFrame, this, bytecodeOffset); - } + + if (!stackTrace.isEmpty()) + putDirect(vm, vm.propertyNames->stack, vm.interpreter->stackTraceAsString(vm.topCallFrame, stackTrace), DontEnum); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ErrorInstance.h b/Source/JavaScriptCore/runtime/ErrorInstance.h index 3f584a99f..91dd7ef0a 100644 --- a/Source/JavaScriptCore/runtime/ErrorInstance.h +++ b/Source/JavaScriptCore/runtime/ErrorInstance.h @@ -22,58 +22,45 @@ #define ErrorInstance_h #include "Interpreter.h" -#include "RuntimeType.h" +#include "JSObject.h" #include "SourceProvider.h" -#include <wtf/Vector.h> namespace JSC { -class ErrorInstance : public JSNonFinalObject { -public: - typedef JSNonFinalObject Base; + class ErrorInstance : public JSNonFinalObject { + public: + typedef JSNonFinalObject Base; - enum SourceTextWhereErrorOccurred { FoundExactSource, FoundApproximateSource }; - typedef String (*SourceAppender) (const String& originalMessage, const String& sourceText, RuntimeType, SourceTextWhereErrorOccurred); + DECLARE_INFO; - DECLARE_INFO; + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ErrorInstanceType, StructureFlags), info()); + } - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ErrorInstanceType, StructureFlags), info()); - } + static ErrorInstance* create(VM& vm, Structure* structure, const String& message, Vector<StackFrame> stackTrace = Vector<StackFrame>()) + { + ErrorInstance* instance = new (NotNull, allocateCell<ErrorInstance>(vm.heap)) ErrorInstance(vm, structure); + instance->finishCreation(vm, message, stackTrace); + return instance; + } - static ErrorInstance* create(ExecState* exec, VM& vm, Structure* structure, const String& message, SourceAppender appender = nullptr, RuntimeType type = TypeNothing, bool useCurrentFrame = true) - { - ErrorInstance* instance = new (NotNull, allocateCell<ErrorInstance>(vm.heap)) ErrorInstance(vm, structure); - instance->m_sourceAppender = appender; - instance->m_runtimeTypeForCause = type; - instance->finishCreation(exec, vm, message, useCurrentFrame); - return instance; - } + static ErrorInstance* create(ExecState* exec, Structure* structure, JSValue message, Vector<StackFrame> stackTrace = Vector<StackFrame>()) + { + return create(exec->vm(), structure, message.isUndefined() ? String() : message.toString(exec)->value(exec), stackTrace); + } - static ErrorInstance* create(ExecState* exec, Structure* structure, JSValue message, SourceAppender appender = nullptr, RuntimeType type = TypeNothing, bool useCurrentFrame = true) - { - return create(exec, exec->vm(), structure, message.isUndefined() ? String() : message.toString(exec)->value(exec), appender, type, useCurrentFrame); - } + bool appendSourceToMessage() { return m_appendSourceToMessage; } + void setAppendSourceToMessage() { m_appendSourceToMessage = true; } + void clearAppendSourceToMessage() { m_appendSourceToMessage = false; } - static void addErrorInfo(ExecState*, VM&, JSObject*, bool = true); + protected: + explicit ErrorInstance(VM&, Structure*); - bool hasSourceAppender() const { return !!m_sourceAppender; } - SourceAppender sourceAppender() const { return m_sourceAppender; } - void setSourceAppender(SourceAppender appender) { m_sourceAppender = appender; } - void clearSourceAppender() { m_sourceAppender = nullptr; } - void setRuntimeTypeForCause(RuntimeType type) { m_runtimeTypeForCause = type; } - RuntimeType runtimeTypeForCause() const { return m_runtimeTypeForCause; } - void clearRuntimeTypeForCause() { m_runtimeTypeForCause = TypeNothing; } + void finishCreation(VM&, const String&, Vector<StackFrame> = Vector<StackFrame>()); -protected: - explicit ErrorInstance(VM&, Structure*); - - void finishCreation(ExecState*, VM&, const String&, bool useCurrentFrame = true); - - SourceAppender m_sourceAppender { nullptr }; - RuntimeType m_runtimeTypeForCause { TypeNothing }; -}; + bool m_appendSourceToMessage; + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ErrorPrototype.cpp b/Source/JavaScriptCore/runtime/ErrorPrototype.cpp index 5bc2ec3c8..55cb03304 100644 --- a/Source/JavaScriptCore/runtime/ErrorPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ErrorPrototype.cpp @@ -26,7 +26,7 @@ #include "JSString.h" #include "JSStringBuilder.h" #include "ObjectPrototype.h" -#include "JSCInlines.h" +#include "Operations.h" #include "StringRecursionChecker.h" namespace JSC { @@ -41,7 +41,7 @@ static EncodedJSValue JSC_HOST_CALL errorProtoFuncToString(ExecState*); namespace JSC { -const ClassInfo ErrorPrototype::s_info = { "Error", &ErrorInstance::s_info, &errorPrototypeTable, CREATE_METHOD_TABLE(ErrorPrototype) }; +const ClassInfo ErrorPrototype::s_info = { "Error", &ErrorInstance::s_info, 0, ExecState::errorPrototypeTable, CREATE_METHOD_TABLE(ErrorPrototype) }; /* Source for ErrorPrototype.lut.h @begin errorPrototypeTable @@ -54,16 +54,16 @@ ErrorPrototype::ErrorPrototype(VM& vm, Structure* structure) { } -void ErrorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) +void ErrorPrototype::finishCreation(VM& vm, JSGlobalObject*) { - Base::finishCreation(globalObject->globalExec(), vm, ""); + Base::finishCreation(vm, ""); ASSERT(inherits(info())); putDirect(vm, vm.propertyNames->name, jsNontrivialString(&vm, String(ASCIILiteral("Error"))), DontEnum); } bool ErrorPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot) { - return getStaticFunctionSlot<ErrorInstance>(exec, errorPrototypeTable, jsCast<ErrorPrototype*>(object), propertyName, slot); + return getStaticFunctionSlot<ErrorInstance>(exec, ExecState::errorPrototypeTable(exec->vm()), jsCast<ErrorPrototype*>(object), propertyName, slot); } // ------------------------------ Functions --------------------------- @@ -72,7 +72,7 @@ bool ErrorPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, Prope EncodedJSValue JSC_HOST_CALL errorProtoFuncToString(ExecState* exec) { // 1. Let O be the this value. - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); // 2. If Type(O) is not Object, throw a TypeError exception. if (!thisValue.isObject()) diff --git a/Source/JavaScriptCore/runtime/ErrorPrototype.h b/Source/JavaScriptCore/runtime/ErrorPrototype.h index 29cd6a948..10707abdb 100644 --- a/Source/JavaScriptCore/runtime/ErrorPrototype.h +++ b/Source/JavaScriptCore/runtime/ErrorPrototype.h @@ -25,34 +25,35 @@ namespace JSC { -class ObjectPrototype; - -class ErrorPrototype : public ErrorInstance { -public: - typedef ErrorInstance Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; - - static ErrorPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) - { - ErrorPrototype* prototype = new (NotNull, allocateCell<ErrorPrototype>(vm.heap)) ErrorPrototype(vm, structure); - prototype->finishCreation(vm, globalObject); - return prototype; - } - - DECLARE_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ErrorInstanceType, StructureFlags), info()); - } - -protected: - ErrorPrototype(VM&, Structure*); - void finishCreation(VM&, JSGlobalObject*); - -private: - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); -}; + class ObjectPrototype; + + class ErrorPrototype : public ErrorInstance { + public: + typedef ErrorInstance Base; + + static ErrorPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) + { + ErrorPrototype* prototype = new (NotNull, allocateCell<ErrorPrototype>(vm.heap)) ErrorPrototype(vm, structure); + prototype->finishCreation(vm, globalObject); + return prototype; + } + + DECLARE_INFO; + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ErrorInstanceType, StructureFlags), info()); + } + + protected: + ErrorPrototype(VM&, Structure*); + void finishCreation(VM&, JSGlobalObject*); + + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | ErrorInstance::StructureFlags; + + private: + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Exception.cpp b/Source/JavaScriptCore/runtime/Exception.cpp deleted file mode 100644 index 4f5fcb981..000000000 --- a/Source/JavaScriptCore/runtime/Exception.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2015 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 "Exception.h" - -#include "JSCInlines.h" - -namespace JSC { - -const ClassInfo Exception::s_info = { "Exception", &Base::s_info, 0, CREATE_METHOD_TABLE(Exception) }; - -Exception* Exception::create(VM& vm, JSValue thrownValue, StackCaptureAction action) -{ - Exception* result = new (NotNull, allocateCell<Exception>(vm.heap)) Exception(vm); - result->finishCreation(vm, thrownValue, action); - return result; -} - -void Exception::destroy(JSCell* cell) -{ - Exception* exception = static_cast<Exception*>(cell); - exception->~Exception(); -} - -Structure* Exception::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) -{ - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); -} - -void Exception::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - Exception* thisObject = jsCast<Exception*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - Base::visitChildren(thisObject, visitor); - - visitor.append(&thisObject->m_value); -} - -Exception::Exception(VM& vm) - : Base(vm, vm.exceptionStructure.get()) -{ -} - -Exception::~Exception() -{ -} - -void Exception::finishCreation(VM& vm, JSValue thrownValue, StackCaptureAction action) -{ - Base::finishCreation(vm); - - m_value.set(vm, this, thrownValue); - - Vector<StackFrame> stackTrace; - if (action == StackCaptureAction::CaptureStack) - vm.interpreter->getStackTrace(stackTrace); - m_stack = RefCountedArray<StackFrame>(stackTrace); -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Exception.h b/Source/JavaScriptCore/runtime/Exception.h deleted file mode 100644 index 491cb4994..000000000 --- a/Source/JavaScriptCore/runtime/Exception.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2015 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 Exception_h -#define Exception_h - -#include "Interpreter.h" -#include <wtf/RefCountedArray.h> - -namespace JSC { - -class Exception : public JSNonFinalObject { -public: - typedef JSNonFinalObject Base; - static const unsigned StructureFlags = StructureIsImmortal | Base::StructureFlags; - - enum StackCaptureAction { - CaptureStack, - DoNotCaptureStack - }; - JS_EXPORT_PRIVATE static Exception* create(VM&, JSValue thrownValue, StackCaptureAction = CaptureStack); - - static const bool needsDestruction = true; - static void destroy(JSCell*); - - static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype); - - static void visitChildren(JSCell*, SlotVisitor&); - - DECLARE_EXPORT_INFO; - - static ptrdiff_t valueOffset() - { - return OBJECT_OFFSETOF(Exception, m_value); - } - - JSValue value() const { return m_value.get(); } - const RefCountedArray<StackFrame>& stack() const { return m_stack; } - - bool didNotifyInspectorOfThrow() const { return m_didNotifyInspectorOfThrow; } - void setDidNotifyInspectorOfThrow() { m_didNotifyInspectorOfThrow = true; } - - ~Exception(); - -private: - Exception(VM&); - void finishCreation(VM&, JSValue thrownValue, StackCaptureAction); - - WriteBarrier<Unknown> m_value; - RefCountedArray<StackFrame> m_stack; - bool m_didNotifyInspectorOfThrow { false }; - - friend class LLIntOffsetsExtractor; -}; - -} // namespace JSC - -#endif // Exception_h diff --git a/Source/JavaScriptCore/runtime/ExceptionFuzz.cpp b/Source/JavaScriptCore/runtime/ExceptionFuzz.cpp deleted file mode 100644 index 744b1a60d..000000000 --- a/Source/JavaScriptCore/runtime/ExceptionFuzz.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2014 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 "ExceptionFuzz.h" - -#include "Error.h" -#include "JSCInlines.h" -#include "TestRunnerUtils.h" - -namespace JSC { - -static unsigned s_numberOfExceptionFuzzChecks; -unsigned numberOfExceptionFuzzChecks() { return s_numberOfExceptionFuzzChecks; } - -// Call this only if you know that exception fuzzing is enabled. -void doExceptionFuzzing(ExecState* exec, const char* where, void* returnPC) -{ - ASSERT(Options::enableExceptionFuzz()); - - DeferGCForAWhile deferGC(exec->vm().heap); - - s_numberOfExceptionFuzzChecks++; - - unsigned fireTarget = Options::fireExceptionFuzzAt(); - if (fireTarget == s_numberOfExceptionFuzzChecks) { - printf("JSC EXCEPTION FUZZ: Throwing fuzz exception with call frame %p, seen in %s and return address %p.\n", exec, where, returnPC); - exec->vm().throwException( - exec, createError(exec, ASCIILiteral("Exception Fuzz"))); - } -} - -} // namespace JSC - - diff --git a/Source/JavaScriptCore/runtime/ExceptionFuzz.h b/Source/JavaScriptCore/runtime/ExceptionFuzz.h deleted file mode 100644 index d9a6b4b82..000000000 --- a/Source/JavaScriptCore/runtime/ExceptionFuzz.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2014 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 ExceptionFuzz_h -#define ExceptionFuzz_h - -#include "Options.h" - -namespace JSC { - -class ExecState; - -// Call this only if you know that exception fuzzing is enabled. -void doExceptionFuzzing(ExecState* exec, const char* where, void* returnPC); - -// This is what you should call if you don't know if fuzzing is enabled. -ALWAYS_INLINE void doExceptionFuzzingIfEnabled(ExecState* exec, const char* where, void* returnPC) -{ - if (LIKELY(!Options::enableExceptionFuzz())) - return; - doExceptionFuzzing(exec, where, returnPC); -} - -} // namespace JSC - -#endif // ExceptionFuzz_h - diff --git a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp index 46c0cef93..8f44248e3 100644 --- a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp +++ b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -31,28 +31,25 @@ #include "CodeBlock.h" #include "CallFrame.h" -#include "ErrorHandlingScope.h" -#include "Exception.h" +#include "ErrorInstance.h" #include "JSGlobalObjectFunctions.h" +#include "JSObject.h" #include "JSNotAnObject.h" #include "Interpreter.h" #include "Nodes.h" -#include "JSCInlines.h" -#include "RuntimeType.h" -#include <wtf/text/StringBuilder.h> -#include <wtf/text/StringView.h> +#include "Operations.h" namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(TerminatedExecutionError); -const ClassInfo TerminatedExecutionError::s_info = { "TerminatedExecutionError", &Base::s_info, 0, CREATE_METHOD_TABLE(TerminatedExecutionError) }; +const ClassInfo TerminatedExecutionError::s_info = { "TerminatedExecutionError", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(TerminatedExecutionError) }; JSValue TerminatedExecutionError::defaultValue(const JSObject*, ExecState* exec, PreferredPrimitiveType hint) { if (hint == PreferString) return jsNontrivialString(exec, String(ASCIILiteral("JavaScript execution terminated."))); - return JSValue(PNaN); + return JSValue(QNaN); } JSObject* createTerminatedExecutionException(VM* vm) @@ -60,235 +57,117 @@ JSObject* createTerminatedExecutionException(VM* vm) return TerminatedExecutionError::create(*vm); } -bool isTerminatedExecutionException(Exception* exception) +bool isTerminatedExecutionException(JSObject* object) { - return exception->value().inherits(TerminatedExecutionError::info()); + return object->inherits(TerminatedExecutionError::info()); } +bool isTerminatedExecutionException(JSValue value) +{ + return value.inherits(TerminatedExecutionError::info()); +} + + JSObject* createStackOverflowError(ExecState* exec) { return createRangeError(exec, ASCIILiteral("Maximum call stack size exceeded.")); } +JSObject* createStackOverflowError(JSGlobalObject* globalObject) +{ + return createRangeError(globalObject, ASCIILiteral("Maximum call stack size exceeded.")); +} + JSObject* createUndefinedVariableError(ExecState* exec, const Identifier& ident) { - if (exec->propertyNames().isPrivateName(ident)) { - String message(makeString("Can't find private variable: @", exec->propertyNames().getPublicName(ident).string())); - return createReferenceError(exec, message); - } String message(makeString("Can't find variable: ", ident.string())); return createReferenceError(exec, message); } 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 jsNontrivialString(exec, makeString('"', asString(v)->value(exec), '"')); + return jsCast<JSString*>(v.asCell()); if (v.isObject()) { CallData callData; JSObject* object = asObject(v); if (object->methodTable()->getCallData(object, callData) != CallTypeNone) - return exec->vm().smallStrings.functionString(); - return jsString(exec, JSObject::calculatedClassName(object)); + return vm.smallStrings.functionString(); + return jsString(exec, object->methodTable()->className(object)); } - return v.toString(exec); -} -static String defaultApproximateSourceError(const String& originalMessage, const String& sourceText) -{ - return makeString(originalMessage, " (near '...", sourceText, "...')"); -} - -static String defaultSourceAppender(const String& originalMessage, const String& sourceText, RuntimeType, ErrorInstance::SourceTextWhereErrorOccurred occurrence) -{ - if (occurrence == ErrorInstance::FoundApproximateSource) - return defaultApproximateSourceError(originalMessage, sourceText); - - ASSERT(occurrence == ErrorInstance::FoundExactSource); - return makeString(originalMessage, " (evaluating '", sourceText, "')"); -} - -static String functionCallBase(const String& sourceText) -{ - // This function retrieves the 'foo.bar' substring from 'foo.bar(baz)'. - // FIXME: This function has simple processing of /* */ style comments. - // It doesn't properly handle embedded comments of string literals that contain - // parenthesis or comment constructs, e.g. foo.bar("/abc\)*/"). - // https://bugs.webkit.org/show_bug.cgi?id=146304 - - unsigned sourceLength = sourceText.length(); - unsigned idx = sourceLength - 1; - if (sourceLength < 2 || sourceText[idx] != ')') { - // For function calls that have many new lines in between their open parenthesis - // and their closing parenthesis, the text range passed into the message appender - // will not inlcude the text in between these parentheses, it will just be the desired - // text that precedes the parentheses. - return sourceText; - } - - unsigned parenStack = 1; - bool isInMultiLineComment = false; - idx -= 1; - // Note that we're scanning text right to left instead of the more common left to right, - // so syntax detection is backwards. - while (parenStack > 0) { - UChar curChar = sourceText[idx]; - if (isInMultiLineComment) { - if (idx > 0 && curChar == '*' && sourceText[idx - 1] == '/') { - isInMultiLineComment = false; - idx -= 1; - } - } else if (curChar == '(') - parenStack -= 1; - else if (curChar == ')') - parenStack += 1; - else if (idx > 0 && curChar == '/' && sourceText[idx - 1] == '*') { - isInMultiLineComment = true; - idx -= 1; - } - - if (!idx) - break; - - idx -= 1; - } - - return sourceText.left(idx + 1); -} - -static String notAFunctionSourceAppender(const String& originalMessage, const String& sourceText, RuntimeType type, ErrorInstance::SourceTextWhereErrorOccurred occurrence) -{ - ASSERT(type != TypeFunction); - - if (occurrence == ErrorInstance::FoundApproximateSource) - return defaultApproximateSourceError(originalMessage, sourceText); - - ASSERT(occurrence == ErrorInstance::FoundExactSource); - auto notAFunctionIndex = originalMessage.reverseFind("is not a function"); - RELEASE_ASSERT(notAFunctionIndex != notFound); - StringView displayValue; - if (originalMessage.is8Bit()) - displayValue = StringView(originalMessage.characters8(), notAFunctionIndex - 1); - else - displayValue = StringView(originalMessage.characters16(), notAFunctionIndex - 1); - - String base = functionCallBase(sourceText); - StringBuilder builder; - builder.append(base); - builder.appendLiteral(" is not a function. (In '"); - builder.append(sourceText); - builder.appendLiteral("', '"); - builder.append(base); - builder.appendLiteral("' is "); - if (type == TypeObject) - builder.appendLiteral("an instance of "); - builder.append(displayValue); - builder.appendLiteral(")"); - - return builder.toString(); -} - -static String invalidParameterInSourceAppender(const String& originalMessage, const String& sourceText, RuntimeType type, ErrorInstance::SourceTextWhereErrorOccurred occurrence) -{ - ASSERT_UNUSED(type, type != TypeObject); - - if (occurrence == ErrorInstance::FoundApproximateSource) - return defaultApproximateSourceError(originalMessage, sourceText); - - ASSERT(occurrence == ErrorInstance::FoundExactSource); - auto inIndex = sourceText.reverseFind("in"); - RELEASE_ASSERT(inIndex != notFound); - if (sourceText.find("in") != inIndex) - return makeString(originalMessage, " (evaluating '", sourceText, "')"); - - static const unsigned inLength = 2; - String rightHandSide = sourceText.substring(inIndex + inLength).simplifyWhiteSpace(); - return makeString(rightHandSide, " is not an Object. (evaluating '", sourceText, "')"); + // The JSValue should never be empty, so this point in the code should never be reached. + ASSERT_NOT_REACHED(); + return vm.smallStrings.emptyString(); } - -static String invalidParameterInstanceofSourceAppender(const String& originalMessage, const String& sourceText, RuntimeType, ErrorInstance::SourceTextWhereErrorOccurred occurrence) -{ - if (occurrence == ErrorInstance::FoundApproximateSource) - return defaultApproximateSourceError(originalMessage, sourceText); - - ASSERT(occurrence == ErrorInstance::FoundExactSource); - auto instanceofIndex = sourceText.reverseFind("instanceof"); - RELEASE_ASSERT(instanceofIndex != notFound); - if (sourceText.find("instanceof") != instanceofIndex) - return makeString(originalMessage, " (evaluating '", sourceText, "')"); - - static const unsigned instanceofLength = 10; - String rightHandSide = sourceText.substring(instanceofIndex + instanceofLength).simplifyWhiteSpace(); - return makeString(rightHandSide, " is not a function. (evaluating '", sourceText, "')"); -} - -JSObject* createError(ExecState* exec, JSValue value, const String& message, ErrorInstance::SourceAppender appender) -{ - String errorMessage = makeString(errorDescriptionForValue(exec, value)->value(exec), ' ', message); - JSObject* exception = createTypeError(exec, errorMessage, appender, runtimeTypeForValue(value)); - ASSERT(exception->isErrorInstance()); - return exception; -} - -JSObject* createInvalidFunctionApplyParameterError(ExecState* exec, JSValue value) + +JSObject* createError(ExecState* exec, ErrorFactory errorFactory, JSValue value, const String& message) { - JSObject* exception = createTypeError(exec, makeString("second argument to Function.prototype.apply must be an Array-like object"), defaultSourceAppender, runtimeTypeForValue(value)); + 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* createInvalidInParameterError(ExecState* exec, JSValue value) -{ - return createError(exec, value, makeString("is not an Object."), invalidParameterInSourceAppender); -} - -JSObject* createInvalidInstanceofParameterError(ExecState* exec, JSValue value) +JSObject* createInvalidParameterError(ExecState* exec, const char* op, JSValue value) { - return createError(exec, value, makeString("is not a function."), invalidParameterInstanceofSourceAppender); + return createError(exec, createTypeError, value, makeString("is not a valid argument for '", op, "'")); } JSObject* createNotAConstructorError(ExecState* exec, JSValue value) { - return createError(exec, value, ASCIILiteral("is not a constructor"), defaultSourceAppender); + return createError(exec, createTypeError, value, "is not a constructor"); } JSObject* createNotAFunctionError(ExecState* exec, JSValue value) { - return createError(exec, value, ASCIILiteral("is not a function"), notAFunctionSourceAppender); + return createError(exec, createTypeError, value, "is not a function"); } JSObject* createNotAnObjectError(ExecState* exec, JSValue value) { - return createError(exec, value, ASCIILiteral("is not an object"), defaultSourceAppender); + return createError(exec, createTypeError, value, "is not an object"); } JSObject* createErrorForInvalidGlobalAssignment(ExecState* exec, const String& propertyName) { - return createReferenceError(exec, makeString("Strict mode forbids implicit creation of global property '", propertyName, '\'')); + return createReferenceError(exec, makeString("Strict mode forbids implicit creation of global property '", propertyName, "'")); } -JSObject* createTDZError(ExecState* exec) +JSObject* createOutOfMemoryError(JSGlobalObject* globalObject) { - return createReferenceError(exec, "Cannot access uninitialized variable."); + return createError(globalObject, ASCIILiteral("Out of memory")); } JSObject* throwOutOfMemoryError(ExecState* exec) { - return exec->vm().throwException(exec, createOutOfMemoryError(exec)); + return exec->vm().throwException(exec, createOutOfMemoryError(exec->lexicalGlobalObject())); } JSObject* throwStackOverflowError(ExecState* exec) { - VM& vm = exec->vm(); - ErrorHandlingScope errorScope(vm); - return vm.throwException(exec, createStackOverflowError(exec)); + Interpreter::ErrorHandlingMode mode(exec); + return exec->vm().throwException(exec, createStackOverflowError(exec)); } JSObject* throwTerminatedExecutionException(ExecState* exec) { - VM& vm = exec->vm(); - ErrorHandlingScope errorScope(vm); - return vm.throwException(exec, createTerminatedExecutionException(&vm)); + Interpreter::ErrorHandlingMode mode(exec); + return exec->vm().throwException(exec, createTerminatedExecutionException(&exec->vm())); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ExceptionHelpers.h b/Source/JavaScriptCore/runtime/ExceptionHelpers.h index c6ba02e3f..0c3fcf2d5 100644 --- a/Source/JavaScriptCore/runtime/ExceptionHelpers.h +++ b/Source/JavaScriptCore/runtime/ExceptionHelpers.h @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -29,37 +29,43 @@ #ifndef ExceptionHelpers_h #define ExceptionHelpers_h -#include "ErrorInstance.h" #include "JSObject.h" namespace JSC { -typedef JSObject* (*ErrorFactory)(ExecState*, const String&, ErrorInstance::SourceAppender); +typedef JSObject* (*ErrorFactory)(ExecState*, const String&); JSObject* createTerminatedExecutionException(VM*); -JS_EXPORT_PRIVATE bool isTerminatedExecutionException(Exception*); -JS_EXPORT_PRIVATE JSObject* createError(ExecState*, JSValue, const String&, ErrorInstance::SourceAppender); +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* createTDZError(ExecState*); JSObject* createNotAnObjectError(ExecState*, JSValue); -JSObject* createInvalidFunctionApplyParameterError(ExecState*, JSValue); -JSObject* createInvalidInParameterError(ExecState*, JSValue); -JSObject* createInvalidInstanceofParameterError(ExecState*, 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); -JS_EXPORT_PRIVATE JSObject* throwOutOfMemoryError(ExecState*); -JS_EXPORT_PRIVATE JSObject* throwStackOverflowError(ExecState*); -JS_EXPORT_PRIVATE JSObject* throwTerminatedExecutionException(ExecState*); +JSObject* throwOutOfMemoryError(ExecState*); +JSObject* throwStackOverflowError(ExecState*); +JSObject* throwTerminatedExecutionException(ExecState*); -class TerminatedExecutionError final : public JSNonFinalObject { +class TerminatedExecutionError : public JSNonFinalObject { +private: + TerminatedExecutionError(VM& vm) + : JSNonFinalObject(vm, vm.terminatedExecutionErrorStructure.get()) + { + } + + static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType); + public: typedef JSNonFinalObject Base; - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; static TerminatedExecutionError* create(VM& vm) { @@ -74,15 +80,6 @@ public: } DECLARE_EXPORT_INFO; - -private: - explicit TerminatedExecutionError(VM& vm) - : JSNonFinalObject(vm, vm.terminatedExecutionErrorStructure.get()) - { - } - - static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType); - }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp index 0ab167211..bbd6ed23e 100644 --- a/Source/JavaScriptCore/runtime/Executable.cpp +++ b/Source/JavaScriptCore/runtime/Executable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2010, 2013, 2015 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 @@ -27,36 +27,34 @@ #include "Executable.h" #include "BatchedTransitionOptimizer.h" +#include "BytecodeGenerator.h" #include "CodeBlock.h" #include "DFGDriver.h" #include "JIT.h" -#include "JSCInlines.h" #include "LLIntEntrypoint.h" +#include "Operations.h" #include "Parser.h" -#include "ProfilerDatabase.h" -#include "TypeProfiler.h" -#include <wtf/CommaPrinter.h> #include <wtf/Vector.h> #include <wtf/text/StringBuilder.h> namespace JSC { -const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, CREATE_METHOD_TABLE(ExecutableBase) }; +const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, 0, CREATE_METHOD_TABLE(ExecutableBase) }; +#if ENABLE(JIT) void ExecutableBase::destroy(JSCell* cell) { static_cast<ExecutableBase*>(cell)->ExecutableBase::~ExecutableBase(); } +#endif void ExecutableBase::clearCode() { #if ENABLE(JIT) - m_jitCodeForCall = nullptr; - m_jitCodeForConstruct = nullptr; + m_jitCodeForCall.clear(); + m_jitCodeForConstruct.clear(); m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr(); m_jitCodeForConstructWithArityCheck = MacroAssemblerCodePtr(); - m_jitCodeForCallWithArityCheckAndPreserveRegs = MacroAssemblerCodePtr(); - m_jitCodeForConstructWithArityCheckAndPreserveRegs = MacroAssemblerCodePtr(); #endif m_numParametersForCall = NUM_PARAMETERS_NOT_COMPILED; m_numParametersForConstruct = NUM_PARAMETERS_NOT_COMPILED; @@ -76,12 +74,14 @@ Intrinsic ExecutableBase::intrinsic() const } #endif -const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, CREATE_METHOD_TABLE(NativeExecutable) }; +const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(NativeExecutable) }; +#if ENABLE(JIT) void NativeExecutable::destroy(JSCell* cell) { static_cast<NativeExecutable*>(cell)->NativeExecutable::~NativeExecutable(); } +#endif #if ENABLE(DFG_JIT) Intrinsic NativeExecutable::intrinsic() const @@ -90,38 +90,20 @@ Intrinsic NativeExecutable::intrinsic() const } #endif -const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, CREATE_METHOD_TABLE(ScriptExecutable) }; - -ScriptExecutable::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_hasCapturedVariables(false) - , m_neverInline(false) - , m_didTryToEnterInLoop(false) - , m_overrideLineNumber(-1) - , m_firstLine(-1) - , m_lastLine(-1) - , m_startColumn(UINT_MAX) - , m_endColumn(UINT_MAX) - , m_typeProfilingStartOffset(UINT_MAX) - , m_typeProfilingEndOffset(UINT_MAX) -{ -} +const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(ScriptExecutable) }; +#if ENABLE(JIT) void ScriptExecutable::destroy(JSCell* cell) { static_cast<ScriptExecutable*>(cell)->ScriptExecutable::~ScriptExecutable(); } +#endif void ScriptExecutable::installCode(CodeBlock* genericCodeBlock) { RELEASE_ASSERT(genericCodeBlock->ownerExecutable() == this); RELEASE_ASSERT(JITCode::isExecutableScript(genericCodeBlock->jitType())); - if (Options::verboseOSR()) - dataLog("Installing ", *genericCodeBlock, "\n"); - VM& vm = *genericCodeBlock->vm(); if (vm.m_perBytecodeProfiler) @@ -136,14 +118,12 @@ void ScriptExecutable::installCode(CodeBlock* genericCodeBlock) switch (kind) { case CodeForCall: m_jitCodeForCall = genericCodeBlock->jitCode(); - m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr(); - m_jitCodeForCallWithArityCheckAndPreserveRegs = MacroAssemblerCodePtr(); + m_jitCodeForCallWithArityCheck = genericCodeBlock->jitCodeWithArityCheck(); m_numParametersForCall = genericCodeBlock->numParameters(); break; case CodeForConstruct: m_jitCodeForConstruct = genericCodeBlock->jitCode(); - m_jitCodeForConstructWithArityCheck = MacroAssemblerCodePtr(); - m_jitCodeForConstructWithArityCheckAndPreserveRegs = MacroAssemblerCodePtr(); + m_jitCodeForConstructWithArityCheck = genericCodeBlock->jitCodeWithArityCheck(); m_numParametersForConstruct = genericCodeBlock->numParameters(); break; } @@ -153,6 +133,7 @@ void ScriptExecutable::installCode(CodeBlock* genericCodeBlock) ProgramExecutable* executable = jsCast<ProgramExecutable*>(this); ProgramCodeBlock* codeBlock = static_cast<ProgramCodeBlock*>(genericCodeBlock); + ASSERT(!codeBlock->jitCodeWithArityCheck()); ASSERT(kind == CodeForCall); oldCodeBlock = executable->m_programCodeBlock; @@ -164,6 +145,7 @@ void ScriptExecutable::installCode(CodeBlock* genericCodeBlock) EvalExecutable* executable = jsCast<EvalExecutable*>(this); EvalCodeBlock* codeBlock = static_cast<EvalCodeBlock*>(genericCodeBlock); + ASSERT(!codeBlock->jitCodeWithArityCheck()); ASSERT(kind == CodeForCall); oldCodeBlock = executable->m_evalCodeBlock; @@ -194,12 +176,10 @@ void ScriptExecutable::installCode(CodeBlock* genericCodeBlock) Debugger* debugger = genericCodeBlock->globalObject()->debugger(); if (debugger) debugger->registerCodeBlock(genericCodeBlock); - - Heap::heap(this)->writeBarrier(this); } -RefPtr<CodeBlock> ScriptExecutable::newCodeBlockFor( - CodeSpecializationKind kind, JSFunction* function, JSScope* scope, JSObject*& exception) +PassRefPtr<CodeBlock> ScriptExecutable::newCodeBlockFor( + CodeSpecializationKind kind, JSScope* scope, JSObject*& exception) { VM* vm = scope->vm(); @@ -211,7 +191,6 @@ RefPtr<CodeBlock> ScriptExecutable::newCodeBlockFor( EvalExecutable* executable = jsCast<EvalExecutable*>(this); RELEASE_ASSERT(kind == CodeForCall); RELEASE_ASSERT(!executable->m_evalCodeBlock); - RELEASE_ASSERT(!function); return adoptRef(new EvalCodeBlock( executable, executable->m_unlinkedEvalCodeBlock.get(), scope, executable->source().provider())); @@ -221,14 +200,12 @@ RefPtr<CodeBlock> ScriptExecutable::newCodeBlockFor( ProgramExecutable* executable = jsCast<ProgramExecutable*>(this); RELEASE_ASSERT(kind == CodeForCall); RELEASE_ASSERT(!executable->m_programCodeBlock); - RELEASE_ASSERT(!function); return adoptRef(new ProgramCodeBlock( executable, executable->m_unlinkedProgramCodeBlock.get(), scope, executable->source().provider(), executable->source().startColumn())); } RELEASE_ASSERT(classInfo() == FunctionExecutable::info()); - RELEASE_ASSERT(function); FunctionExecutable* executable = jsCast<FunctionExecutable*>(this); RELEASE_ASSERT(!executable->codeBlockFor(kind)); JSGlobalObject* globalObject = scope->globalObject(); @@ -238,14 +215,14 @@ RefPtr<CodeBlock> ScriptExecutable::newCodeBlockFor( UnlinkedFunctionCodeBlock* unlinkedCodeBlock = executable->m_unlinkedExecutable->codeBlockFor( *vm, executable->m_source, kind, debuggerMode, profilerMode, error); - recordParse(executable->m_unlinkedExecutable->features(), executable->m_unlinkedExecutable->hasCapturedVariables(), firstLine(), lastLine(), startColumn(), endColumn()); + recordParse(executable->m_unlinkedExecutable->features(), executable->m_unlinkedExecutable->hasCapturedVariables(), lineNo(), lastLine(), startColumn(), endColumn()); if (!unlinkedCodeBlock) { exception = vm->throwException( globalObject->globalExec(), error.toErrorObject(globalObject, executable->m_source)); - return nullptr; + return 0; } - + SourceProvider* provider = executable->source().provider(); unsigned sourceOffset = executable->source().startOffset(); unsigned startColumn = executable->source().startColumn(); @@ -291,7 +268,13 @@ PassRefPtr<CodeBlock> ScriptExecutable::newReplacementCodeBlockFor( static void setupLLInt(VM& vm, CodeBlock* codeBlock) { +#if ENABLE(LLINT) LLInt::setEntrypoint(vm, codeBlock); +#else + UNUSED_PARAM(vm); + UNUSED_PARAM(codeBlock); + UNREACHABLE_FOR_PLATFORM(); +#endif } static void setupJIT(VM& vm, CodeBlock* codeBlock) @@ -307,13 +290,13 @@ static void setupJIT(VM& vm, CodeBlock* codeBlock) } JSObject* ScriptExecutable::prepareForExecutionImpl( - ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind) + ExecState* exec, JSScope* scope, CodeSpecializationKind kind) { VM& vm = exec->vm(); DeferGC deferGC(vm.heap); JSObject* exception = 0; - RefPtr<CodeBlock> codeBlock = newCodeBlockFor(kind, function, scope, exception); + RefPtr<CodeBlock> codeBlock = newCodeBlockFor(kind, scope, exception); if (!codeBlock) { RELEASE_ASSERT(exception); return exception; @@ -322,7 +305,18 @@ JSObject* ScriptExecutable::prepareForExecutionImpl( if (Options::validateBytecode()) codeBlock->validate(); - if (Options::useLLInt()) + bool shouldUseLLInt; +#if !ENABLE(JIT) + // No JIT implies use of the C Loop LLINT. Override the options to reflect this. + Options::useLLInt() = true; + shouldUseLLInt = true; +#elif ENABLE(LLINT) + shouldUseLLInt = Options::useLLInt(); +#else + shouldUseLLInt = false; +#endif + + if (shouldUseLLInt) setupLLInt(vm, codeBlock.get()); else setupJIT(vm, codeBlock.get()); @@ -331,9 +325,9 @@ JSObject* ScriptExecutable::prepareForExecutionImpl( return 0; } -const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(EvalExecutable) }; +const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(EvalExecutable) }; -EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source, bool isInStrictContext, ThisTDZMode thisTDZMode, const VariableEnvironment* variablesUnderTDZ) +EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source, bool isInStrictContext) { JSGlobalObject* globalObject = exec->lexicalGlobalObject(); if (!globalObject->evalEnabled()) { @@ -344,7 +338,7 @@ EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext); executable->finishCreation(exec->vm()); - UnlinkedEvalCodeBlock* unlinkedEvalCode = globalObject->createEvalCodeBlock(exec, executable, thisTDZMode, variablesUnderTDZ); + UnlinkedEvalCodeBlock* unlinkedEvalCode = globalObject->createEvalCodeBlock(exec, executable); if (!unlinkedEvalCode) return 0; @@ -354,7 +348,7 @@ EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source } EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext) - : ScriptExecutable(exec->vm().evalExecutableStructure.get(), exec->vm(), source, inStrictContext) + : ScriptExecutable(exec->vm().evalExecutableStructure.get(), exec, source, inStrictContext) { } @@ -363,15 +357,11 @@ void EvalExecutable::destroy(JSCell* cell) static_cast<EvalExecutable*>(cell)->EvalExecutable::~EvalExecutable(); } -const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(ProgramExecutable) }; +const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(ProgramExecutable) }; ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source) - : ScriptExecutable(exec->vm().programExecutableStructure.get(), exec->vm(), source, false) + : ScriptExecutable(exec->vm().programExecutableStructure.get(), exec, source, false) { - m_typeProfilingStartOffset = 0; - m_typeProfilingEndOffset = source.length() - 1; - if (exec->vm().typeProfiler() || exec->vm().controlFlowProfiler()) - exec->vm().functionHasExecutedCache()->insertUnexecutedRange(sourceID(), m_typeProfilingStartOffset, m_typeProfilingEndOffset); } void ProgramExecutable::destroy(JSCell* cell) @@ -379,13 +369,12 @@ void ProgramExecutable::destroy(JSCell* cell) static_cast<ProgramExecutable*>(cell)->ProgramExecutable::~ProgramExecutable(); } -const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(FunctionExecutable) }; +const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionExecutable) }; -FunctionExecutable::FunctionExecutable(VM& vm, const SourceCode& source, - UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, - unsigned lastLine, unsigned startColumn, unsigned endColumn) +FunctionExecutable::FunctionExecutable(VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine, unsigned startColumn, unsigned endColumn, bool bodyIncludesBraces) : ScriptExecutable(vm.functionExecutableStructure.get(), vm, source, unlinkedExecutable->isInStrictContext()) , m_unlinkedExecutable(vm, this, unlinkedExecutable) + , m_bodyIncludesBraces(bodyIncludesBraces) { RELEASE_ASSERT(!source.isNull()); ASSERT(source.length()); @@ -395,15 +384,6 @@ FunctionExecutable::FunctionExecutable(VM& vm, const SourceCode& source, ASSERT(endColumn != UINT_MAX); m_startColumn = startColumn; m_endColumn = endColumn; - m_parametersStartOffset = unlinkedExecutable->parametersStartOffset(); - m_typeProfilingStartOffset = unlinkedExecutable->typeProfilingStartOffset(); - m_typeProfilingEndOffset = unlinkedExecutable->typeProfilingEndOffset(); -} - -void FunctionExecutable::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - m_singletonFunction.set(vm, this, InferredValue::create(vm)); } void FunctionExecutable::destroy(JSCell* cell) @@ -432,6 +412,8 @@ void EvalExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) { EvalExecutable* thisObject = jsCast<EvalExecutable*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); ScriptExecutable::visitChildren(thisObject, visitor); if (thisObject->m_evalCodeBlock) thisObject->m_evalCodeBlock->visitAggregate(visitor); @@ -450,7 +432,7 @@ void EvalExecutable::unlinkCalls() void EvalExecutable::clearCode() { - m_evalCodeBlock = nullptr; + m_evalCodeBlock.clear(); m_unlinkedEvalCodeBlock.clear(); Base::clearCode(); } @@ -460,12 +442,10 @@ JSObject* ProgramExecutable::checkSyntax(ExecState* exec) ParserError error; VM* vm = &exec->vm(); JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); - std::unique_ptr<ProgramNode> programNode = parse<ProgramNode>( - vm, m_source, Identifier(), JSParserBuiltinMode::NotBuiltin, - JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, error); + RefPtr<ProgramNode> programNode = parse<ProgramNode>(vm, m_source, 0, Identifier(), JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, error); if (programNode) return 0; - ASSERT(error.isValid()); + ASSERT(error.m_type != ParserError::ErrorNone); return error.toErrorObject(lexicalGlobalObject, m_source); } @@ -495,21 +475,20 @@ JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callF BatchedTransitionOptimizer optimizer(vm, globalObject); - for (size_t i = 0, numberOfFunctions = unlinkedCodeBlock->numberOfFunctionDecls(); i < numberOfFunctions; ++i) { - UnlinkedFunctionExecutable* unlinkedFunctionExecutable = unlinkedCodeBlock->functionDecl(i); - ASSERT(!unlinkedFunctionExecutable->name().isEmpty()); - globalObject->addFunction(callFrame, unlinkedFunctionExecutable->name()); - if (vm.typeProfiler() || vm.controlFlowProfiler()) { - vm.functionHasExecutedCache()->insertUnexecutedRange(sourceID(), - unlinkedFunctionExecutable->typeProfilingStartOffset(), - unlinkedFunctionExecutable->typeProfilingEndOffset()); - } + const UnlinkedProgramCodeBlock::VariableDeclations& variableDeclarations = unlinkedCodeBlock->variableDeclarations(); + const UnlinkedProgramCodeBlock::FunctionDeclations& functionDeclarations = unlinkedCodeBlock->functionDeclarations(); + + for (size_t i = 0; i < functionDeclarations.size(); ++i) { + UnlinkedFunctionExecutable* unlinkedFunctionExecutable = functionDeclarations[i].second.get(); + JSValue value = JSFunction::create(vm, unlinkedFunctionExecutable->link(vm, m_source, lineNo(), 0), scope); + globalObject->addFunction(callFrame, functionDeclarations[i].first, value); } - const VariableEnvironment& variableDeclarations = unlinkedCodeBlock->variableDeclarations(); - for (auto& entry : variableDeclarations) { - ASSERT(entry.value.isVar()); - globalObject->addVar(callFrame, Identifier::fromUid(&vm, entry.key.get())); + for (size_t i = 0; i < variableDeclarations.size(); ++i) { + if (variableDeclarations[i].second & DeclarationStacks::IsConstant) + globalObject->addConst(callFrame, variableDeclarations[i].first); + else + globalObject->addVar(callFrame, variableDeclarations[i].first); } return 0; } @@ -518,6 +497,8 @@ void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) { ProgramExecutable* thisObject = jsCast<ProgramExecutable*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); ScriptExecutable::visitChildren(thisObject, visitor); visitor.append(&thisObject->m_unlinkedProgramCodeBlock); if (thisObject->m_programCodeBlock) @@ -526,7 +507,7 @@ void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) void ProgramExecutable::clearCode() { - m_programCodeBlock = nullptr; + m_programCodeBlock.clear(); m_unlinkedProgramCodeBlock.clear(); Base::clearCode(); } @@ -549,24 +530,39 @@ void FunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) { FunctionExecutable* thisObject = jsCast<FunctionExecutable*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); ScriptExecutable::visitChildren(thisObject, visitor); if (thisObject->m_codeBlockForCall) thisObject->m_codeBlockForCall->visitAggregate(visitor); if (thisObject->m_codeBlockForConstruct) thisObject->m_codeBlockForConstruct->visitAggregate(visitor); visitor.append(&thisObject->m_unlinkedExecutable); - visitor.append(&thisObject->m_singletonFunction); } -void FunctionExecutable::clearUnlinkedCodeForRecompilation() +SymbolTable* FunctionExecutable::symbolTable(CodeSpecializationKind kind) +{ + return codeBlockFor(kind)->symbolTable(); +} + +void FunctionExecutable::clearCodeIfNotCompiling() +{ + if (isCompiling()) + return; + clearCode(); +} + +void FunctionExecutable::clearUnlinkedCodeForRecompilationIfNotCompiling() { + if (isCompiling()) + return; m_unlinkedExecutable->clearCodeForRecompilation(); } void FunctionExecutable::clearCode() { - m_codeBlockForCall = nullptr; - m_codeBlockForConstruct = nullptr; + m_codeBlockForCall.clear(); + m_codeBlockForConstruct.clear(); Base::clearCode(); } @@ -584,57 +580,34 @@ void FunctionExecutable::unlinkCalls() #endif } -FunctionExecutable* FunctionExecutable::fromGlobalCode( - const Identifier& name, ExecState& exec, const SourceCode& source, - JSObject*& exception, int overrideLineNumber) +FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& name, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception) { - UnlinkedFunctionExecutable* unlinkedExecutable = - UnlinkedFunctionExecutable::fromGlobalCode( - name, exec, source, exception, overrideLineNumber); + UnlinkedFunctionExecutable* unlinkedExecutable = UnlinkedFunctionExecutable::fromGlobalCode(name, exec, debugger, source, exception); if (!unlinkedExecutable) - return nullptr; + return 0; + unsigned lineCount = unlinkedExecutable->lineCount(); + unsigned firstLine = source.firstLine() + unlinkedExecutable->firstLineOffset(); + unsigned startOffset = source.startOffset() + unlinkedExecutable->startOffset(); + + // We don't have any owner executable. The source string is effectively like a global + // string (like in the handling of eval). Hence, the startColumn is always 1. + unsigned startColumn = 1; + unsigned sourceLength = unlinkedExecutable->sourceLength(); + bool endColumnIsOnStartLine = !lineCount; + // The unlinkedBodyEndColumn is based-0. Hence, we need to add 1 to it. But if the + // endColumn is on the startLine, then we need to subtract back the adjustment for + // the open brace resulting in an adjustment of 0. + unsigned endColumnExcludingBraces = unlinkedExecutable->unlinkedBodyEndColumn() + (endColumnIsOnStartLine ? 0 : 1); + unsigned startOffsetExcludingOpenBrace = startOffset + 1; + unsigned endOffsetExcludingCloseBrace = startOffset + sourceLength - 1; + SourceCode bodySource(source.provider(), startOffsetExcludingOpenBrace, endOffsetExcludingCloseBrace, firstLine, startColumn); - return unlinkedExecutable->link(exec.vm(), source, overrideLineNumber); + return FunctionExecutable::create(exec->vm(), bodySource, unlinkedExecutable, firstLine, firstLine + lineCount, startColumn, endColumnExcludingBraces, false); } -void ExecutableBase::dump(PrintStream& out) const +String FunctionExecutable::paramString() const { - ExecutableBase* realThis = const_cast<ExecutableBase*>(this); - - if (classInfo() == NativeExecutable::info()) { - NativeExecutable* native = jsCast<NativeExecutable*>(realThis); - out.print("NativeExecutable:", RawPointer(bitwise_cast<void*>(native->function())), "/", RawPointer(bitwise_cast<void*>(native->constructor()))); - return; - } - - if (classInfo() == EvalExecutable::info()) { - EvalExecutable* eval = jsCast<EvalExecutable*>(realThis); - if (CodeBlock* codeBlock = eval->codeBlock()) - out.print(*codeBlock); - else - out.print("EvalExecutable w/o CodeBlock"); - return; - } - - if (classInfo() == ProgramExecutable::info()) { - ProgramExecutable* eval = jsCast<ProgramExecutable*>(realThis); - if (CodeBlock* codeBlock = eval->codeBlock()) - out.print(*codeBlock); - else - out.print("ProgramExecutable w/o CodeBlock"); - return; - } - - FunctionExecutable* function = jsCast<FunctionExecutable*>(realThis); - if (!function->eitherCodeBlock()) - out.print("FunctionExecutable w/o CodeBlock"); - else { - CommaPrinter comma("/"); - if (function->codeBlockForCall()) - out.print(comma, *function->codeBlockForCall()); - if (function->codeBlockForConstruct()) - out.print(comma, *function->codeBlockForConstruct()); - } + return m_unlinkedExecutable->paramString(); } CodeBlockHash ExecutableBase::hashFor(CodeSpecializationKind kind) const diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h index bce2428cb..6ff27aee9 100644 --- a/Source/JavaScriptCore/runtime/Executable.h +++ b/Source/JavaScriptCore/runtime/Executable.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2010, 2013-2015 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 @@ -26,23 +26,20 @@ #ifndef Executable_h #define Executable_h -#include "ArityCheckMode.h" #include "CallData.h" #include "CodeBlockHash.h" #include "CodeSpecializationKind.h" #include "CompilationResult.h" #include "DFGPlan.h" -#include "ExecutableInfo.h" #include "HandlerInfo.h" -#include "InferredValue.h" +#include "JSFunction.h" +#include "Interpreter.h" #include "JITCode.h" #include "JSGlobalObject.h" -#include "RegisterPreservationMode.h" #include "SamplingTool.h" #include "SourceCode.h" -#include "TypeSet.h" #include "UnlinkedCodeBlock.h" -#include "UnlinkedFunctionExecutable.h" +#include <wtf/PassOwnPtr.h> namespace JSC { @@ -64,7 +61,8 @@ inline bool isCall(CodeSpecializationKind kind) return false; } -class ExecutableBase : public JSCell { +class ExecutableBase : public JSCell, public DoublyLinkedListNode<ExecutableBase> { + friend class WTF::DoublyLinkedListNode<ExecutableBase>; friend class JIT; protected: @@ -85,24 +83,26 @@ protected: public: typedef JSCell Base; - static const unsigned StructureFlags = Base::StructureFlags; +#if ENABLE(JIT) static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; static void destroy(JSCell*); +#endif CodeBlockHash hashFor(CodeSpecializationKind) const; bool isEvalExecutable() { - return type() == EvalExecutableType; + return structure()->typeInfo().type() == EvalExecutableType; } bool isFunctionExecutable() { - return type() == FunctionExecutableType; + return structure()->typeInfo().type() == FunctionExecutableType; } bool isProgramExecutable() { - return type() == ProgramExecutableType; + return structure()->typeInfo().type() == ProgramExecutableType; } bool isHostFunction() const @@ -111,13 +111,14 @@ public: return m_numParametersForCall == NUM_PARAMETERS_IS_HOST; } - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CellType, StructureFlags), info()); } + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CompoundType, StructureFlags), info()); } void clearCode(); DECLARE_EXPORT_INFO; protected: + static const unsigned StructureFlags = 0; int m_numParametersForCall; int m_numParametersForConstruct; @@ -143,94 +144,37 @@ public: ASSERT(kind == CodeForConstruct); return generatedJITCodeForConstruct(); } - - MacroAssemblerCodePtr entrypointFor( - VM& vm, CodeSpecializationKind kind, ArityCheckMode arity, RegisterPreservationMode registers) - { - // Check if we have a cached result. We only have it for arity check because we use the - // no-arity entrypoint in non-virtual calls, which will "cache" this value directly in - // machine code. - if (arity == MustCheckArity) { - switch (kind) { - case CodeForCall: - switch (registers) { - case RegisterPreservationNotRequired: - if (MacroAssemblerCodePtr result = m_jitCodeForCallWithArityCheck) - return result; - break; - case MustPreserveRegisters: - if (MacroAssemblerCodePtr result = m_jitCodeForCallWithArityCheckAndPreserveRegs) - return result; - break; - } - break; - case CodeForConstruct: - switch (registers) { - case RegisterPreservationNotRequired: - if (MacroAssemblerCodePtr result = m_jitCodeForConstructWithArityCheck) - return result; - break; - case MustPreserveRegisters: - if (MacroAssemblerCodePtr result = m_jitCodeForConstructWithArityCheckAndPreserveRegs) - return result; - break; - } - break; - } - } - MacroAssemblerCodePtr result = - generatedJITCodeFor(kind)->addressForCall(vm, this, arity, registers); - if (arity == MustCheckArity) { - // Cache the result; this is necessary for the JIT's virtual call optimizations. - switch (kind) { - case CodeForCall: - switch (registers) { - case RegisterPreservationNotRequired: - m_jitCodeForCallWithArityCheck = result; - break; - case MustPreserveRegisters: - m_jitCodeForCallWithArityCheckAndPreserveRegs = result; - break; - } - break; - case CodeForConstruct: - switch (registers) { - case RegisterPreservationNotRequired: - m_jitCodeForConstructWithArityCheck = result; - break; - case MustPreserveRegisters: - m_jitCodeForConstructWithArityCheckAndPreserveRegs = result; - break; - } - break; - } - } - return result; - } - - static ptrdiff_t offsetOfJITCodeWithArityCheckFor( - CodeSpecializationKind kind, RegisterPreservationMode registers) - { - switch (kind) { - case CodeForCall: - switch (registers) { - case RegisterPreservationNotRequired: - return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCallWithArityCheck); - case MustPreserveRegisters: - return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCallWithArityCheckAndPreserveRegs); - } - case CodeForConstruct: - switch (registers) { - case RegisterPreservationNotRequired: - return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstructWithArityCheck); - case MustPreserveRegisters: - return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstructWithArityCheckAndPreserveRegs); - } - } - RELEASE_ASSERT_NOT_REACHED(); - return 0; + + MacroAssemblerCodePtr generatedJITCodeForCallWithArityCheck() + { + ASSERT(m_jitCodeForCall); + ASSERT(m_jitCodeForCallWithArityCheck); + return m_jitCodeForCallWithArityCheck; } - + + MacroAssemblerCodePtr generatedJITCodeForConstructWithArityCheck() + { + ASSERT(m_jitCodeForConstruct); + ASSERT(m_jitCodeForConstructWithArityCheck); + return m_jitCodeForConstructWithArityCheck; + } + + MacroAssemblerCodePtr generatedJITCodeWithArityCheckFor(CodeSpecializationKind kind) + { + if (kind == CodeForCall) + return generatedJITCodeForCallWithArityCheck(); + ASSERT(kind == CodeForConstruct); + return generatedJITCodeForConstructWithArityCheck(); + } + + static ptrdiff_t offsetOfJITCodeWithArityCheckFor(CodeSpecializationKind kind) + { + if (kind == CodeForCall) + return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCallWithArityCheck); + ASSERT(kind == CodeForConstruct); + return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstructWithArityCheck); + } + static ptrdiff_t offsetOfNumParametersFor(CodeSpecializationKind kind) { if (kind == CodeForCall) @@ -266,34 +210,52 @@ public: return intrinsic(); return NoIntrinsic; } - - void dump(PrintStream&) const; + MacroAssemblerCodePtr hostCodeEntryFor(CodeSpecializationKind kind) + { + return generatedJITCodeFor(kind)->addressForCall(); + } + + MacroAssemblerCodePtr jsCodeEntryFor(CodeSpecializationKind kind) + { + return generatedJITCodeFor(kind)->addressForCall(); + } + + MacroAssemblerCodePtr jsCodeWithArityCheckEntryFor(CodeSpecializationKind kind) + { + return generatedJITCodeWithArityCheckFor(kind); + } + protected: + ExecutableBase* m_prev; + ExecutableBase* m_next; + RefPtr<JITCode> m_jitCodeForCall; RefPtr<JITCode> m_jitCodeForConstruct; MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck; MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck; - MacroAssemblerCodePtr m_jitCodeForCallWithArityCheckAndPreserveRegs; - MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheckAndPreserveRegs; }; -class NativeExecutable final : public ExecutableBase { +class NativeExecutable : public ExecutableBase { friend class JIT; friend class LLIntOffsetsExtractor; public: typedef ExecutableBase Base; - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; - static NativeExecutable* create(VM& vm, PassRefPtr<JITCode> callThunk, NativeFunction function, PassRefPtr<JITCode> constructThunk, NativeFunction constructor, Intrinsic intrinsic) + static NativeExecutable* create(VM& vm, MacroAssemblerCodeRef callThunk, NativeFunction function, MacroAssemblerCodeRef constructThunk, NativeFunction constructor, Intrinsic intrinsic) { NativeExecutable* executable; executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor); - executable->finishCreation(vm, callThunk, constructThunk, intrinsic); + if (!callThunk) + executable->finishCreation(vm, 0, 0, intrinsic); + else + executable->finishCreation(vm, JITCode::hostFunction(callThunk), JITCode::hostFunction(constructThunk), intrinsic); return executable; } +#if ENABLE(JIT) static void destroy(JSCell*); +#endif CodeBlockHash hashFor(CodeSpecializationKind) const; @@ -316,7 +278,7 @@ public: return OBJECT_OFFSETOF(NativeExecutable, m_constructor); } - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CellType, StructureFlags), info()); } + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(LeafType, StructureFlags), info()); } DECLARE_INFO; @@ -326,6 +288,8 @@ protected: void finishCreation(VM& vm, PassRefPtr<JITCode> callThunk, PassRefPtr<JITCode> constructThunk, Intrinsic intrinsic) { Base::finishCreation(vm); + m_jitCodeForCallWithArityCheck = callThunk ? callThunk->addressForCall() : MacroAssemblerCodePtr(); + m_jitCodeForConstructWithArityCheck = constructThunk ? constructThunk->addressForCall() : MacroAssemblerCodePtr(); m_jitCodeForCall = callThunk; m_jitCodeForConstruct = constructThunk; m_intrinsic = intrinsic; @@ -348,24 +312,40 @@ private: class ScriptExecutable : public ExecutableBase { public: typedef ExecutableBase Base; - static const unsigned StructureFlags = Base::StructureFlags; + 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) + , m_startColumn(UINT_MAX) + , m_endColumn(UINT_MAX) + { + } + + ScriptExecutable(Structure* structure, ExecState* exec, const SourceCode& source, bool isInStrictContext) + : ExecutableBase(exec->vm(), structure, NUM_PARAMETERS_NOT_COMPILED) + , m_source(source) + , m_features(isInStrictContext ? StrictModeFeature : 0) + , m_neverInline(false) + , m_startColumn(UINT_MAX) + , m_endColumn(UINT_MAX) + { + } + +#if ENABLE(JIT) static void destroy(JSCell*); +#endif CodeBlockHash hashFor(CodeSpecializationKind) const; const SourceCode& source() const { return m_source; } intptr_t sourceID() const { return m_source.providerID(); } const String& sourceURL() const { return m_source.provider()->url(); } - int firstLine() const { return m_firstLine; } - void setOverrideLineNumber(int overrideLineNumber) { m_overrideLineNumber = overrideLineNumber; } - bool hasOverrideLineNumber() const { return m_overrideLineNumber != -1; } - int overrideLineNumber() const { return m_overrideLineNumber; } + int lineNo() const { return m_firstLine; } int lastLine() const { return m_lastLine; } unsigned startColumn() const { return m_startColumn; } unsigned endColumn() const { return m_endColumn; } - unsigned typeProfilingStartOffset() const { return m_typeProfilingStartOffset; } - unsigned typeProfilingEndOffset() const { return m_typeProfilingEndOffset; } bool usesEval() const { return m_features & EvalFeature; } bool usesArguments() const { return m_features & ArgumentsFeature; } @@ -374,12 +354,8 @@ public: ECMAMode ecmaMode() const { return isStrictMode() ? StrictMode : NotStrictMode; } void setNeverInline(bool value) { m_neverInline = value; } - void setDidTryToEnterInLoop(bool value) { m_didTryToEnterInLoop = value; } bool neverInline() const { return m_neverInline; } - bool didTryToEnterInLoop() const { return m_didTryToEnterInLoop; } bool isInliningCandidate() const { return !neverInline(); } - - bool* addressOfDidTryToEnterInLoop() { return &m_didTryToEnterInLoop; } void unlinkCalls(); @@ -400,24 +376,20 @@ public: } void installCode(CodeBlock*); - RefPtr<CodeBlock> newCodeBlockFor(CodeSpecializationKind, JSFunction*, JSScope*, JSObject*& exception); + PassRefPtr<CodeBlock> newCodeBlockFor(CodeSpecializationKind, JSScope*, JSObject*& exception); PassRefPtr<CodeBlock> newReplacementCodeBlockFor(CodeSpecializationKind); - JSObject* prepareForExecution(ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind) + JSObject* prepareForExecution(ExecState* exec, JSScope* scope, CodeSpecializationKind kind) { if (hasJITCodeFor(kind)) return 0; - return prepareForExecutionImpl(exec, function, scope, kind); + return prepareForExecutionImpl(exec, scope, kind); } - template <typename Functor> void forEachCodeBlock(Functor&&); - private: - JSObject* prepareForExecutionImpl(ExecState*, JSFunction*, JSScope*, CodeSpecializationKind); + JSObject* prepareForExecutionImpl(ExecState*, JSScope*, CodeSpecializationKind); protected: - ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext); - void finishCreation(VM& vm) { Base::finishCreation(vm); @@ -433,21 +405,16 @@ protected: CodeFeatures m_features; bool m_hasCapturedVariables; bool m_neverInline; - bool m_didTryToEnterInLoop; - int m_overrideLineNumber; int m_firstLine; int m_lastLine; unsigned m_startColumn; unsigned m_endColumn; - unsigned m_typeProfilingStartOffset; - unsigned m_typeProfilingEndOffset; }; -class EvalExecutable final : public ScriptExecutable { +class EvalExecutable : public ScriptExecutable { friend class LLIntOffsetsExtractor; public: typedef ScriptExecutable Base; - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; static void destroy(JSCell*); @@ -456,7 +423,7 @@ public: return m_evalCodeBlock.get(); } - static EvalExecutable* create(ExecState*, const SourceCode&, bool isInStrictContext, ThisTDZMode, const VariableEnvironment*); + static EvalExecutable* create(ExecState*, const SourceCode&, bool isInStrictContext); PassRefPtr<JITCode> generatedJITCode() { @@ -474,13 +441,14 @@ public: void clearCode(); - ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None); } + ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false); } unsigned numVariables() { return m_unlinkedEvalCodeBlock->numVariables(); } unsigned numberOfFunctionDecls() { return m_unlinkedEvalCodeBlock->numberOfFunctionDecls(); } private: friend class ScriptExecutable; + static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; EvalExecutable(ExecState*, const SourceCode&, bool); static void visitChildren(JSCell*, SlotVisitor&); @@ -489,11 +457,10 @@ private: WriteBarrier<UnlinkedEvalCodeBlock> m_unlinkedEvalCodeBlock; }; -class ProgramExecutable final : public ScriptExecutable { +class ProgramExecutable : public ScriptExecutable { friend class LLIntOffsetsExtractor; public: typedef ScriptExecutable Base; - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; static ProgramExecutable* create(ExecState* exec, const SourceCode& source) { @@ -530,10 +497,12 @@ public: void clearCode(); - ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None); } + ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false); } private: friend class ScriptExecutable; + + static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; ProgramExecutable(ExecState*, const SourceCode&); @@ -543,24 +512,19 @@ private: RefPtr<ProgramCodeBlock> m_programCodeBlock; }; -class FunctionExecutable final : public ScriptExecutable { +class FunctionExecutable : public ScriptExecutable { friend class JIT; friend class LLIntOffsetsExtractor; public: typedef ScriptExecutable Base; - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; - static FunctionExecutable* create( - VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, - unsigned firstLine, unsigned lastLine, unsigned startColumn, unsigned endColumn) + static FunctionExecutable* create(VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine, unsigned startColumn, unsigned endColumn, bool bodyIncludesBraces = true) { - FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(vm.heap)) FunctionExecutable(vm, source, unlinkedExecutable, firstLine, lastLine, startColumn, endColumn); + FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(vm.heap)) FunctionExecutable(vm, source, unlinkedExecutable, firstLine, lastLine, startColumn, endColumn, bodyIncludesBraces); executable->finishCreation(vm); return executable; } - static FunctionExecutable* fromGlobalCode( - const Identifier& name, ExecState&, const SourceCode&, - JSObject*& exception, int overrideLineNumber); + static FunctionExecutable* fromGlobalCode(const Identifier& name, ExecState*, Debugger*, const SourceCode&, JSObject** exception); static void destroy(JSCell*); @@ -621,68 +585,64 @@ public: { return baselineCodeBlockFor(kind); } - - RefPtr<TypeSet> returnStatementTypeSet() - { - if (!m_returnStatementTypeSet) - m_returnStatementTypeSet = TypeSet::create(); - - return m_returnStatementTypeSet; - } - FunctionMode functionMode() { return m_unlinkedExecutable->functionMode(); } - bool isBuiltinFunction() const { return m_unlinkedExecutable->isBuiltinFunction(); } - ConstructAbility constructAbility() const { return m_unlinkedExecutable->constructAbility(); } - bool isClassConstructorFunction() const { return m_unlinkedExecutable->isClassConstructorFunction(); } const Identifier& name() { return m_unlinkedExecutable->name(); } const Identifier& inferredName() { return m_unlinkedExecutable->inferredName(); } JSString* nameValue() const { return m_unlinkedExecutable->nameValue(); } size_t parameterCount() const { return m_unlinkedExecutable->parameterCount(); } // Excluding 'this'! + String paramString() const; + SymbolTable* symbolTable(CodeSpecializationKind); - void clearUnlinkedCodeForRecompilation(); + void clearCodeIfNotCompiling(); + void clearUnlinkedCodeForRecompilationIfNotCompiling(); static void visitChildren(JSCell*, SlotVisitor&); static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(FunctionExecutableType, StructureFlags), info()); } - - unsigned parametersStartOffset() const { return m_parametersStartOffset; } - - void overrideParameterAndTypeProfilingStartEndOffsets(unsigned parametersStartOffset, unsigned typeProfilingStartOffset, unsigned typeProfilingEndOffset) - { - m_parametersStartOffset = parametersStartOffset; - m_typeProfilingStartOffset = typeProfilingStartOffset; - m_typeProfilingEndOffset = typeProfilingEndOffset; - } - + DECLARE_INFO; void unlinkCalls(); void clearCode(); - - InferredValue* singletonFunction() { return m_singletonFunction.get(); } + + bool bodyIncludesBraces() const { return m_bodyIncludesBraces; } private: - FunctionExecutable( - VM&, const SourceCode&, UnlinkedFunctionExecutable*, unsigned firstLine, - unsigned lastLine, unsigned startColumn, unsigned endColumn); - - void finishCreation(VM&); + FunctionExecutable(VM&, const SourceCode&, UnlinkedFunctionExecutable*, unsigned firstLine, unsigned lastLine, unsigned startColumn, unsigned endColumn, bool bodyIncludesBraces); + + bool isCompiling() + { +#if ENABLE(JIT) + if (!m_jitCodeForCall && m_codeBlockForCall) + return true; + if (!m_jitCodeForConstruct && m_codeBlockForConstruct) + return true; +#endif + return false; + } friend class ScriptExecutable; - + + static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; WriteBarrier<UnlinkedFunctionExecutable> m_unlinkedExecutable; RefPtr<FunctionCodeBlock> m_codeBlockForCall; RefPtr<FunctionCodeBlock> m_codeBlockForConstruct; - RefPtr<TypeSet> m_returnStatementTypeSet; - unsigned m_parametersStartOffset; - WriteBarrier<InferredValue> m_singletonFunction; + bool m_bodyIncludesBraces; }; +inline bool isHostFunction(JSValue value, NativeFunction nativeFunction) +{ + JSFunction* function = jsCast<JSFunction*>(getJSFunction(value)); + if (!function || !function->isHostFunction()) + return false; + return function->nativeFunction() == nativeFunction; +} + inline void ExecutableBase::clearCodeVirtual(ExecutableBase* executable) { - switch (executable->type()) { + switch (executable->structure()->typeInfo().type()) { case EvalExecutableType: return jsCast<EvalExecutable*>(executable)->clearCode(); case ProgramExecutableType: @@ -696,7 +656,7 @@ inline void ExecutableBase::clearCodeVirtual(ExecutableBase* executable) inline void ScriptExecutable::unlinkCalls() { - switch (type()) { + switch (structure()->typeInfo().type()) { case EvalExecutableType: return jsCast<EvalExecutable*>(this)->unlinkCalls(); case ProgramExecutableType: diff --git a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp index dbe42fa5f..53de63271 100644 --- a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp +++ b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp @@ -29,7 +29,7 @@ #include "JSString.h" #include "Lexer.h" #include "Nodes.h" -#include "JSCInlines.h" +#include "Operations.h" #include "Parser.h" #include <wtf/text/StringBuilder.h> @@ -37,7 +37,7 @@ namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(FunctionConstructor); -const ClassInfo FunctionConstructor::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(FunctionConstructor) }; +const ClassInfo FunctionConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionConstructor) }; FunctionConstructor::FunctionConstructor(VM& vm, Structure* structure) : InternalFunction(vm, structure) @@ -86,37 +86,33 @@ JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const return constructFunctionSkippingEvalEnabledCheck(exec, globalObject, args, functionName, sourceURL, position); } -JSObject* constructFunctionSkippingEvalEnabledCheck( - ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, - const Identifier& functionName, const String& sourceURL, - const TextPosition& position, int overrideLineNumber) +JSObject* constructFunctionSkippingEvalEnabledCheck(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, const Identifier& functionName, const String& sourceURL, const TextPosition& position) { - // How we stringify functions is sometimes important for web compatibility. - // See https://bugs.webkit.org/show_bug.cgi?id=24350. + // Functions need to have a space following the opening { due to for web compatibility + // see https://bugs.webkit.org/show_bug.cgi?id=24350 + // We also need \n before the closing } to handle // comments at the end of the last line String program; if (args.isEmpty()) - program = makeString("{function ", functionName.string(), "() {\n\n}}"); + program = ASCIILiteral("(function() {\n})"); else if (args.size() == 1) - program = makeString("{function ", functionName.string(), "() {\n", args.at(0).toString(exec)->value(exec), "\n}}"); + program = makeString("(function() {", args.at(0).toString(exec)->value(exec), "\n})"); else { StringBuilder builder; - builder.appendLiteral("{function "); - builder.append(functionName.string()); - builder.append('('); - builder.append(args.at(0).toString(exec)->view(exec)); + builder.appendLiteral("(function("); + builder.append(args.at(0).toString(exec)->value(exec)); for (size_t i = 1; i < args.size() - 1; i++) { - builder.appendLiteral(", "); - builder.append(args.at(i).toString(exec)->view(exec)); + builder.append(','); + builder.append(args.at(i).toString(exec)->value(exec)); } - builder.appendLiteral(") {\n"); - builder.append(args.at(args.size() - 1).toString(exec)->view(exec)); - builder.appendLiteral("\n}}"); + builder.appendLiteral(") {"); + builder.append(args.at(args.size() - 1).toString(exec)->value(exec)); + builder.appendLiteral("\n})"); program = builder.toString(); } SourceCode source = makeSource(program, sourceURL, position); - JSObject* exception = nullptr; - FunctionExecutable* function = FunctionExecutable::fromGlobalCode(functionName, *exec, source, exception, overrideLineNumber); + JSObject* exception = 0; + FunctionExecutable* function = FunctionExecutable::fromGlobalCode(functionName, exec, exec->vmEntryGlobalObject()->debugger(), source, &exception); if (!function) { ASSERT(exception); return exec->vm().throwException(exec, exception); diff --git a/Source/JavaScriptCore/runtime/FunctionConstructor.h b/Source/JavaScriptCore/runtime/FunctionConstructor.h index 22ecb57b9..61443e944 100644 --- a/Source/JavaScriptCore/runtime/FunctionConstructor.h +++ b/Source/JavaScriptCore/runtime/FunctionConstructor.h @@ -29,39 +29,37 @@ class TextPosition; namespace JSC { -class FunctionPrototype; + class FunctionPrototype; -class FunctionConstructor : public InternalFunction { -public: - typedef InternalFunction Base; + class FunctionConstructor : public InternalFunction { + public: + typedef InternalFunction Base; - static FunctionConstructor* create(VM& vm, Structure* structure, FunctionPrototype* functionPrototype) - { - FunctionConstructor* constructor = new (NotNull, allocateCell<FunctionConstructor>(vm.heap)) FunctionConstructor(vm, structure); - constructor->finishCreation(vm, functionPrototype); - return constructor; - } + static FunctionConstructor* create(VM& vm, Structure* structure, FunctionPrototype* functionPrototype) + { + FunctionConstructor* constructor = new (NotNull, allocateCell<FunctionConstructor>(vm.heap)) FunctionConstructor(vm, structure); + constructor->finishCreation(vm, functionPrototype); + return constructor; + } - DECLARE_INFO; + DECLARE_INFO; - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } -private: - FunctionConstructor(VM&, Structure*); - void finishCreation(VM&, FunctionPrototype*); - static ConstructType getConstructData(JSCell*, ConstructData&); - static CallType getCallData(JSCell*, CallData&); -}; + private: + FunctionConstructor(VM&, Structure*); + void finishCreation(VM&, FunctionPrototype*); + static ConstructType getConstructData(JSCell*, ConstructData&); + static CallType getCallData(JSCell*, CallData&); + }; -JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&, const Identifier& functionName, const String& sourceURL, const WTF::TextPosition&); -JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&); + JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&, const Identifier& functionName, const String& sourceURL, const WTF::TextPosition&); + JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&); -JS_EXPORT_PRIVATE JSObject* constructFunctionSkippingEvalEnabledCheck( - ExecState*, JSGlobalObject*, const ArgList&, const Identifier&, - const String&, const WTF::TextPosition&, int overrideLineNumber = -1); + JS_EXPORT_PRIVATE JSObject* constructFunctionSkippingEvalEnabledCheck(ExecState*, JSGlobalObject*, const ArgList&, const Identifier&, const String&, const WTF::TextPosition&); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/FunctionExecutableDump.cpp b/Source/JavaScriptCore/runtime/FunctionExecutableDump.cpp index d80a8e701..d0583fc9b 100644 --- a/Source/JavaScriptCore/runtime/FunctionExecutableDump.cpp +++ b/Source/JavaScriptCore/runtime/FunctionExecutableDump.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * 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 @@ -25,7 +25,6 @@ #include "config.h" #include "FunctionExecutableDump.h" -#include "JSCellInlines.h" #include "CodeBlock.h" @@ -35,12 +34,12 @@ void FunctionExecutableDump::dump(PrintStream& out) const { out.print(m_executable->inferredName().string(), "#"); if (m_executable->isGeneratedForCall()) - out.print(m_executable->codeBlockForCall()->hashAsStringIfPossible()); + out.print(m_executable->codeBlockForCall()->hash()); else out.print("<nogen>"); out.print("/"); if (m_executable->isGeneratedForConstruct()) - out.print(m_executable->codeBlockForConstruct()->hashAsStringIfPossible()); + out.print(m_executable->codeBlockForConstruct()->hash()); else out.print("<nogen>"); out.print(":[", RawPointer(m_executable), "]"); diff --git a/Source/JavaScriptCore/runtime/FunctionHasExecutedCache.cpp b/Source/JavaScriptCore/runtime/FunctionHasExecutedCache.cpp deleted file mode 100644 index 3d7e31b2e..000000000 --- a/Source/JavaScriptCore/runtime/FunctionHasExecutedCache.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2014 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 "FunctionHasExecutedCache.h" - -#include <limits.h> - -namespace JSC { - -bool FunctionHasExecutedCache::hasExecutedAtOffset(intptr_t id, unsigned offset) -{ - if (m_rangeMap.find(id) == m_rangeMap.end()) - return false; - - RangeMap& map = m_rangeMap.find(id)->second; - unsigned distance = UINT_MAX; - bool hasExecuted = false; - for (auto iter = map.begin(), end = map.end(); iter != end; ++iter) { - const FunctionRange& range = iter->first; - if (range.m_start <= offset && offset <= range.m_end && range.m_end - range.m_start < distance) { - hasExecuted = iter->second; - distance = range.m_end - range.m_start; - } - } - - return hasExecuted; -} - -void FunctionHasExecutedCache::insertUnexecutedRange(intptr_t id, unsigned start, unsigned end) -{ - if (m_rangeMap.find(id) == m_rangeMap.end()) { - RangeMap map; - m_rangeMap[id] = map; - } - - RangeMap& map = m_rangeMap.find(id)->second; - FunctionRange range; - range.m_start = start; - range.m_end = end; - // Only insert unexecuted ranges once for a given sourceID because we may run into a situation where an executable executes, then is GCed, and then is allocated again, - // and tries to reinsert itself, claiming it has never run, but this is false because it indeed already executed. - if (map.find(range) == map.end()) - map[range] = false; -} - -void FunctionHasExecutedCache::removeUnexecutedRange(intptr_t id, unsigned start, unsigned end) -{ - // FIXME: We should never have an instance where we return here, but currently do in some situations. Find out why. - if (m_rangeMap.find(id) == m_rangeMap.end()) - return; - - RangeMap& map = m_rangeMap.find(id)->second; - - FunctionRange range; - range.m_start = start; - range.m_end = end; - map[range] = true; -} - -Vector<std::tuple<bool, unsigned, unsigned>> FunctionHasExecutedCache::getFunctionRanges(intptr_t id) -{ - Vector<std::tuple<bool, unsigned, unsigned>> ranges(0); - auto findResult = m_rangeMap.find(id); - if (findResult == m_rangeMap.end()) - return ranges; - - RangeMap& map = m_rangeMap.find(id)->second; - for (auto iter = map.begin(), end = map.end(); iter != end; ++iter) { - const FunctionRange& range = iter->first; - bool hasExecuted = iter->second; - ranges.append(std::tuple<bool, unsigned, unsigned>(hasExecuted, range.m_start, range.m_end)); - } - - return ranges; -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/FunctionHasExecutedCache.h b/Source/JavaScriptCore/runtime/FunctionHasExecutedCache.h deleted file mode 100644 index 7f3eb9784..000000000 --- a/Source/JavaScriptCore/runtime/FunctionHasExecutedCache.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2014 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 FunctionHasExecutedCache_h -#define FunctionHasExecutedCache_h - -#include <unordered_map> -#include <wtf/HashMethod.h> -#include <wtf/Vector.h> - -namespace JSC { - -class FunctionHasExecutedCache { -public: - struct FunctionRange { - FunctionRange() {} - bool operator==(const FunctionRange& other) const - { - return m_start == other.m_start && m_end == other.m_end; - } - unsigned hash() const - { - return m_start * m_end; - } - - unsigned m_start; - unsigned m_end; - }; - - bool hasExecutedAtOffset(intptr_t id, unsigned offset); - void insertUnexecutedRange(intptr_t id, unsigned start, unsigned end); - void removeUnexecutedRange(intptr_t id, unsigned start, unsigned end); - Vector<std::tuple<bool, unsigned, unsigned>> getFunctionRanges(intptr_t id); - -private: - typedef std::unordered_map<FunctionRange, bool, HashMethod<FunctionRange>> RangeMap; - typedef std::unordered_map<intptr_t, RangeMap> SourceIDToRangeMap; - SourceIDToRangeMap m_rangeMap; -}; - -} // namespace JSC - -#endif // FunctionHasExecutedCache_h diff --git a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp index d082b12cf..c1b08af2d 100644 --- a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp +++ b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,9 +21,7 @@ #include "config.h" #include "FunctionPrototype.h" -#include "BuiltinExecutables.h" -#include "BuiltinNames.h" -#include "Error.h" +#include "Arguments.h" #include "JSArray.h" #include "JSBoundFunction.h" #include "JSFunction.h" @@ -31,15 +29,17 @@ #include "JSStringBuilder.h" #include "Interpreter.h" #include "Lexer.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(FunctionPrototype); -const ClassInfo FunctionPrototype::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(FunctionPrototype) }; +const ClassInfo FunctionPrototype::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionPrototype) }; static EncodedJSValue JSC_HOST_CALL functionProtoFuncToString(ExecState*); +static EncodedJSValue JSC_HOST_CALL functionProtoFuncApply(ExecState*); +static EncodedJSValue JSC_HOST_CALL functionProtoFuncCall(ExecState*); static EncodedJSValue JSC_HOST_CALL functionProtoFuncBind(ExecState*); FunctionPrototype::FunctionPrototype(VM& vm, Structure* structure) @@ -60,8 +60,11 @@ void FunctionPrototype::addFunctionProperties(ExecState* exec, JSGlobalObject* g JSFunction* toStringFunction = JSFunction::create(vm, globalObject, 0, vm.propertyNames->toString.string(), functionProtoFuncToString); putDirectWithoutTransition(vm, vm.propertyNames->toString, toStringFunction, DontEnum); - *applyFunction = putDirectBuiltinFunctionWithoutTransition(vm, globalObject, vm.propertyNames->builtinNames().applyPublicName(), functionPrototypeApplyCodeGenerator(vm), DontEnum); - *callFunction = putDirectBuiltinFunctionWithoutTransition(vm, globalObject, vm.propertyNames->builtinNames().callPublicName(), functionPrototypeCallCodeGenerator(vm), DontEnum); + *applyFunction = JSFunction::create(vm, globalObject, 2, vm.propertyNames->apply.string(), functionProtoFuncApply); + putDirectWithoutTransition(vm, vm.propertyNames->apply, *applyFunction, DontEnum); + + *callFunction = JSFunction::create(vm, globalObject, 1, vm.propertyNames->call.string(), functionProtoFuncCall); + putDirectWithoutTransition(vm, vm.propertyNames->call, *callFunction, DontEnum); JSFunction* bindFunction = JSFunction::create(vm, globalObject, 1, vm.propertyNames->bind.string(), functionProtoFuncBind); putDirectWithoutTransition(vm, vm.propertyNames->bind, bindFunction, DontEnum); @@ -79,19 +82,38 @@ CallType FunctionPrototype::getCallData(JSCell*, CallData& callData) return CallTypeHost; } +// Functions + +// Compatibility hack for the Optimost JavaScript library. (See <rdar://problem/6595040>.) +static inline void insertSemicolonIfNeeded(String& functionBody, bool bodyIncludesBraces) +{ + if (!bodyIncludesBraces) + functionBody = makeString("{ ", functionBody, "}"); + + ASSERT(functionBody[0] == '{'); + ASSERT(functionBody[functionBody.length() - 1] == '}'); + + for (size_t i = functionBody.length() - 2; i > 0; --i) { + UChar ch = functionBody[i]; + if (!Lexer<UChar>::isWhiteSpace(ch) && !Lexer<UChar>::isLineTerminator(ch)) { + if (ch != ';' && ch != '}') + functionBody = makeString(functionBody.substringSharingImpl(0, i + 1), ";", functionBody.substringSharingImpl(i + 1, functionBody.length() - (i + 1))); + return; + } + } +} + EncodedJSValue JSC_HOST_CALL functionProtoFuncToString(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (thisValue.inherits(JSFunction::info())) { JSFunction* function = jsCast<JSFunction*>(thisValue); - if (function->isHostOrBuiltinFunction()) + if (function->isHostFunction()) return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "() {\n [native code]\n}")); - FunctionExecutable* executable = function->jsExecutable(); - String source = executable->source().provider()->getRange( - executable->parametersStartOffset(), - executable->typeProfilingEndOffset() + 1); // Type profiling end offset is the character before the '}'. - return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), source)); + String sourceString = executable->source().toString(); + insertSemicolonIfNeeded(sourceString, executable->bodyIncludesBraces()); + return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "(", executable->paramString(), ") ", sourceString)); } if (thisValue.inherits(InternalFunction::info())) { @@ -102,13 +124,62 @@ EncodedJSValue JSC_HOST_CALL functionProtoFuncToString(ExecState* exec) return throwVMTypeError(exec); } +EncodedJSValue JSC_HOST_CALL functionProtoFuncApply(ExecState* exec) +{ + JSValue thisValue = exec->hostThisValue(); + CallData callData; + CallType callType = getCallData(thisValue, callData); + if (callType == CallTypeNone) + return throwVMTypeError(exec); + + JSValue array = exec->argument(1); + + MarkedArgumentBuffer applyArgs; + if (!array.isUndefinedOrNull()) { + if (!array.isObject()) + return throwVMTypeError(exec); + if (asObject(array)->classInfo() == Arguments::info()) { + if (asArguments(array)->length(exec) > Arguments::MaxArguments) + return JSValue::encode(throwStackOverflowError(exec)); + asArguments(array)->fillArgList(exec, applyArgs); + } else if (isJSArray(array)) { + if (asArray(array)->length() > Arguments::MaxArguments) + return JSValue::encode(throwStackOverflowError(exec)); + asArray(array)->fillArgList(exec, applyArgs); + } else { + unsigned length = asObject(array)->get(exec, exec->propertyNames().length).toUInt32(exec); + if (length > Arguments::MaxArguments) + return JSValue::encode(throwStackOverflowError(exec)); + + for (unsigned i = 0; i < length; ++i) + applyArgs.append(asObject(array)->get(exec, i)); + } + } + + return JSValue::encode(call(exec, thisValue, callType, callData, exec->argument(0), applyArgs)); +} + +EncodedJSValue JSC_HOST_CALL functionProtoFuncCall(ExecState* exec) +{ + JSValue thisValue = exec->hostThisValue(); + CallData callData; + CallType callType = getCallData(thisValue, callData); + if (callType == CallTypeNone) + return throwVMTypeError(exec); + + ArgList args(exec); + ArgList callArgs; + args.getSlice(1, callArgs); + return JSValue::encode(call(exec, thisValue, callType, callData, exec->argument(0), callArgs)); +} + // 15.3.4.5 Function.prototype.bind (thisArg [, arg1 [, arg2, ...]]) EncodedJSValue JSC_HOST_CALL functionProtoFuncBind(ExecState* exec) { JSGlobalObject* globalObject = exec->callee()->globalObject(); // Let Target be the this value. - JSValue target = exec->thisValue(); + JSValue target = exec->hostThisValue(); // If IsCallable(Target) is false, throw a TypeError exception. CallData callData; diff --git a/Source/JavaScriptCore/runtime/FunctionPrototype.h b/Source/JavaScriptCore/runtime/FunctionPrototype.h index 52ce8f11c..68d2f6a81 100644 --- a/Source/JavaScriptCore/runtime/FunctionPrototype.h +++ b/Source/JavaScriptCore/runtime/FunctionPrototype.h @@ -25,33 +25,33 @@ namespace JSC { -class FunctionPrototype : public InternalFunction { -public: - typedef InternalFunction Base; - - static FunctionPrototype* create(VM& vm, Structure* structure) - { - FunctionPrototype* prototype = new (NotNull, allocateCell<FunctionPrototype>(vm.heap)) FunctionPrototype(vm, structure); - prototype->finishCreation(vm, String()); - return prototype; - } - - void addFunctionProperties(ExecState*, JSGlobalObject*, JSFunction** callFunction, JSFunction** applyFunction); - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) - { - return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info()); - } - - DECLARE_INFO; - -protected: - void finishCreation(VM&, const String& name); - -private: - FunctionPrototype(VM&, Structure*); - static CallType getCallData(JSCell*, CallData&); -}; + class FunctionPrototype : public InternalFunction { + public: + typedef InternalFunction Base; + + static FunctionPrototype* create(VM& vm, Structure* structure) + { + FunctionPrototype* prototype = new (NotNull, allocateCell<FunctionPrototype>(vm.heap)) FunctionPrototype(vm, structure); + prototype->finishCreation(vm, String()); + return prototype; + } + + void addFunctionProperties(ExecState*, JSGlobalObject*, JSFunction** callFunction, JSFunction** applyFunction); + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) + { + return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info()); + } + + DECLARE_INFO; + + protected: + void finishCreation(VM&, const String& name); + + private: + FunctionPrototype(VM&, Structure*); + static CallType getCallData(JSCell*, CallData&); + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/FunctionRareData.cpp b/Source/JavaScriptCore/runtime/FunctionRareData.cpp deleted file mode 100644 index d44c3234c..000000000 --- a/Source/JavaScriptCore/runtime/FunctionRareData.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2015 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 "FunctionRareData.h" - -#include "JSCInlines.h" - -namespace JSC { - -const ClassInfo FunctionRareData::s_info = { "FunctionRareData", 0, 0, CREATE_METHOD_TABLE(FunctionRareData) }; - -FunctionRareData* FunctionRareData::create(VM& vm, JSObject* prototype, size_t inlineCapacity) -{ - FunctionRareData* rareData = new (NotNull, allocateCell<FunctionRareData>(vm.heap)) FunctionRareData(vm); - rareData->finishCreation(vm, prototype, inlineCapacity); - return rareData; -} - -void FunctionRareData::destroy(JSCell* cell) -{ - FunctionRareData* rareData = static_cast<FunctionRareData*>(cell); - rareData->FunctionRareData::~FunctionRareData(); -} - -Structure* FunctionRareData::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) -{ - return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); -} - -void FunctionRareData::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - FunctionRareData* rareData = jsCast<FunctionRareData*>(cell); - - rareData->m_allocationProfile.visitAggregate(visitor); -} - -FunctionRareData::FunctionRareData(VM& vm) - : Base(vm, vm.functionRareDataStructure.get()) - , m_allocationProfile() - // 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 - // 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_allocationProfileWatchpoint(ClearWatchpoint) -{ -} - -FunctionRareData::~FunctionRareData() -{ -} - -void FunctionRareData::finishCreation(VM& vm, JSObject* prototype, size_t inlineCapacity) -{ - Base::finishCreation(vm); - initialize(vm, prototype, inlineCapacity); -} - -void FunctionRareData::initialize(VM& vm, JSObject* prototype, size_t inlineCapacity) -{ - m_allocationProfile.initialize(vm, this, prototype, inlineCapacity); -} - -void FunctionRareData::clear(const char* reason) -{ - m_allocationProfile.clear(); - m_allocationProfileWatchpoint.fireAll(reason); -} - -} diff --git a/Source/JavaScriptCore/runtime/FunctionRareData.h b/Source/JavaScriptCore/runtime/FunctionRareData.h deleted file mode 100644 index f0a2db2da..000000000 --- a/Source/JavaScriptCore/runtime/FunctionRareData.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2015 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 FunctionRareData_h -#define FunctionRareData_h - -#include "JSCell.h" -#include "ObjectAllocationProfile.h" -#include "Watchpoint.h" - -namespace JSC { - -class JSGlobalObject; -class LLIntOffsetsExtractor; -namespace DFG { -class SpeculativeJIT; -class JITCompiler; -} - -class FunctionRareData : public JSCell { - friend class JIT; - friend class DFG::SpeculativeJIT; - friend class DFG::JITCompiler; - friend class VM; - -public: - typedef JSCell Base; - static const unsigned StructureFlags = StructureIsImmortal | Base::StructureFlags; - - static FunctionRareData* create(VM&, JSObject* prototype, size_t inlineCapacity); - - static const bool needsDestruction = true; - static void destroy(JSCell*); - - static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype); - - static void visitChildren(JSCell*, SlotVisitor&); - - DECLARE_INFO; - - static inline ptrdiff_t offsetOfAllocationProfile() - { - return OBJECT_OFFSETOF(FunctionRareData, m_allocationProfile); - } - - ObjectAllocationProfile* allocationProfile() - { - return &m_allocationProfile; - } - - Structure* allocationStructure() { return m_allocationProfile.structure(); } - - InlineWatchpointSet& allocationProfileWatchpointSet() - { - return m_allocationProfileWatchpoint; - } - - void clear(const char* reason); - - void initialize(VM&, JSObject* prototype, size_t inlineCapacity); - - bool isInitialized() { return !m_allocationProfile.isNull(); } - -protected: - FunctionRareData(VM&); - ~FunctionRareData(); - - void finishCreation(VM&, JSObject* prototype, size_t inlineCapacity); - using Base::finishCreation; - -private: - - friend class LLIntOffsetsExtractor; - - ObjectAllocationProfile m_allocationProfile; - InlineWatchpointSet m_allocationProfileWatchpoint; -}; - -} // namespace JSC - -#endif // FunctionRareData_h diff --git a/Source/JavaScriptCore/runtime/GCActivityCallback.cpp b/Source/JavaScriptCore/runtime/GCActivityCallback.cpp new file mode 100644 index 000000000..e1cc98867 --- /dev/null +++ b/Source/JavaScriptCore/runtime/GCActivityCallback.cpp @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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 "GCActivityCallback.h" + +#include "APIShims.h" +#include "Heap.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 { + +bool GCActivityCallback::s_shouldCreateGCTimer = true; + +#if USE(CF) || 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. +const double timerSlop = 2.0; // Fudge factor to avoid performance cost of resetting timer. + +#if !PLATFORM(IOS) +const double pagingTimeOut = 0.1; // Time in seconds to allow opportunistic timer to iterate over all blocks to see if the Heap is paged out. +#endif + +#if !USE(CF) +const double hour = 60 * 60; +#endif + +#if USE(CF) +DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap) + : GCActivityCallback(heap->vm(), CFRunLoopGetCurrent()) + , m_delay(s_decade) +{ +} + +DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap, CFRunLoopRef runLoop) + : GCActivityCallback(heap->vm(), runLoop) + , m_delay(s_decade) +{ +} +#elif PLATFORM(EFL) +DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap) + : GCActivityCallback(heap->vm(), WTF::isMainThread()) + , m_delay(hour) +{ +} +#endif + +void DefaultGCActivityCallback::doWork() +{ + Heap* heap = &m_vm->heap; + if (!isEnabled()) + return; + + APIEntryShim shim(m_vm); +#if !PLATFORM(IOS) + double startTime = WTF::monotonicallyIncreasingTime(); + if (heap->isPagedOut(startTime + pagingTimeOut)) { + heap->activityCallback()->cancel(); + heap->increaseLastGCLength(pagingTimeOut); + return; + } +#endif + heap->collect(); +} + +#if USE(CF) +void DefaultGCActivityCallback::scheduleTimer(double newDelay) +{ + if (newDelay * timerSlop > m_delay) + return; + double delta = m_delay - newDelay; + m_delay = newDelay; + CFRunLoopTimerSetNextFireDate(m_timer.get(), CFRunLoopTimerGetNextFireDate(m_timer.get()) - delta); +} + +void DefaultGCActivityCallback::cancelTimer() +{ + m_delay = s_decade; + CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + s_decade); +} +#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_vm->heap); + double gcTimeSlice = std::min((static_cast<double>(bytes) / MB) * gcTimeSlicePerMB, maxGCTimeSlice); + double newDelay = heap->lastGCLength() / gcTimeSlice; + scheduleTimer(newDelay); +} + +void DefaultGCActivityCallback::willCollect() +{ + cancelTimer(); +} + +void DefaultGCActivityCallback::cancel() +{ + cancelTimer(); +} + +#else + +DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap) + : GCActivityCallback(heap->vm()) +{ +} + +void DefaultGCActivityCallback::doWork() +{ +} + +void DefaultGCActivityCallback::didAllocate(size_t) +{ +} + +void DefaultGCActivityCallback::willCollect() +{ +} + +void DefaultGCActivityCallback::cancel() +{ +} + +#endif + +} + diff --git a/Source/JavaScriptCore/runtime/GCActivityCallback.h b/Source/JavaScriptCore/runtime/GCActivityCallback.h new file mode 100644 index 000000000..0228c2c68 --- /dev/null +++ b/Source/JavaScriptCore/runtime/GCActivityCallback.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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 GCActivityCallback_h +#define GCActivityCallback_h + +#include "HeapTimer.h" +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> + +#if USE(CF) +#include <CoreFoundation/CoreFoundation.h> +#endif + +namespace JSC { + +class Heap; + +class GCActivityCallback : public HeapTimer { + WTF_MAKE_FAST_ALLOCATED; +public: + virtual void didAllocate(size_t) { } + virtual void willCollect() { } + virtual void cancel() { } + bool isEnabled() const { return m_enabled; } + void setEnabled(bool enabled) { m_enabled = enabled; } + + static bool s_shouldCreateGCTimer; + +protected: +#if USE(CF) + 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(VM* vm) + : HeapTimer(vm) + , m_enabled(true) + { + } +#endif + + bool m_enabled; +}; + +class DefaultGCActivityCallback : public GCActivityCallback { +public: + static PassOwnPtr<DefaultGCActivityCallback> create(Heap*); + + DefaultGCActivityCallback(Heap*); + + JS_EXPORT_PRIVATE virtual void didAllocate(size_t) override; + JS_EXPORT_PRIVATE virtual void willCollect() override; + JS_EXPORT_PRIVATE virtual void cancel() override; + + JS_EXPORT_PRIVATE virtual void doWork() override; + +#if USE(CF) +protected: + JS_EXPORT_PRIVATE DefaultGCActivityCallback(Heap*, CFRunLoopRef); +#endif +#if USE(CF) || PLATFORM(EFL) +protected: + void cancelTimer(); + void scheduleTimer(double); + +private: + double m_delay; +#endif +}; + +inline PassOwnPtr<DefaultGCActivityCallback> DefaultGCActivityCallback::create(Heap* heap) +{ + return GCActivityCallback::s_shouldCreateGCTimer ? adoptPtr(new DefaultGCActivityCallback(heap)) : nullptr; +} + +} + +#endif diff --git a/Source/JavaScriptCore/runtime/GenericArguments.h b/Source/JavaScriptCore/runtime/GenericArguments.h deleted file mode 100644 index 67f1b0345..000000000 --- a/Source/JavaScriptCore/runtime/GenericArguments.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2015 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 GenericArguments_h -#define GenericArguments_h - -#include "JSObject.h" - -namespace JSC { - -// This is a mixin for the two kinds of Arguments-class objects that arise when you say -// "arguments" inside a function. This class doesn't show up in the JSCell inheritance hierarchy. -template<typename Type> -class GenericArguments : public JSNonFinalObject { -public: - typedef JSNonFinalObject Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames; - -protected: - GenericArguments(VM& vm, Structure* structure) - : Base(vm, structure) - { - } - - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); - static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&); - static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); - static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); - static bool deleteProperty(JSCell*, ExecState*, PropertyName); - static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); - static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow); - - void copyToArguments(ExecState*, VirtualRegister firstElementDest, unsigned offset, unsigned length); -}; - -} // namespace JSC - -#endif // GenericArguments_h - diff --git a/Source/JavaScriptCore/runtime/GenericArgumentsInlines.h b/Source/JavaScriptCore/runtime/GenericArgumentsInlines.h deleted file mode 100644 index 9b1800185..000000000 --- a/Source/JavaScriptCore/runtime/GenericArgumentsInlines.h +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (C) 2015 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 GenericArgumentsInlines_h -#define GenericArgumentsInlines_h - -#include "GenericArguments.h" -#include "JSCInlines.h" - -namespace JSC { - -template<typename Type> -bool GenericArguments<Type>::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName ident, PropertySlot& slot) -{ - Type* thisObject = jsCast<Type*>(object); - VM& vm = exec->vm(); - - if (!thisObject->overrodeThings()) { - if (ident == vm.propertyNames->length) { - slot.setValue(thisObject, DontEnum, jsNumber(thisObject->internalLength())); - return true; - } - if (ident == vm.propertyNames->callee) { - slot.setValue(thisObject, DontEnum, thisObject->callee().get()); - return true; - } - if (ident == vm.propertyNames->iteratorSymbol) { - slot.setValue(thisObject, DontEnum, thisObject->globalObject()->arrayProtoValuesFunction()); - return true; - } - } - - Optional<uint32_t> index = parseIndex(ident); - if (index && thisObject->canAccessIndexQuickly(index.value())) { - slot.setValue(thisObject, None, thisObject->getIndexQuickly(index.value())); - return true; - } - - return Base::getOwnPropertySlot(thisObject, exec, ident, slot); -} - -template<typename Type> -bool GenericArguments<Type>::getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned index, PropertySlot& slot) -{ - Type* thisObject = jsCast<Type*>(object); - - if (thisObject->canAccessIndexQuickly(index)) { - slot.setValue(thisObject, None, thisObject->getIndexQuickly(index)); - return true; - } - - return Base::getOwnPropertySlotByIndex(object, exec, index, slot); -} - -template<typename Type> -void GenericArguments<Type>::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& array, EnumerationMode mode) -{ - Type* thisObject = jsCast<Type*>(object); - - if (array.includeStringProperties()) { - for (unsigned i = 0; i < thisObject->internalLength(); ++i) { - if (!thisObject->canAccessIndexQuickly(i)) - continue; - array.add(Identifier::from(exec, i)); - } - } - - if (mode.includeDontEnumProperties() && !thisObject->overrodeThings()) { - array.add(exec->propertyNames().length); - array.add(exec->propertyNames().callee); - if (array.includeSymbolProperties()) - array.add(exec->propertyNames().iteratorSymbol); - } - Base::getOwnPropertyNames(thisObject, exec, array, mode); -} - -template<typename Type> -void GenericArguments<Type>::put(JSCell* cell, ExecState* exec, PropertyName ident, JSValue value, PutPropertySlot& slot) -{ - Type* thisObject = jsCast<Type*>(cell); - VM& vm = exec->vm(); - - if (!thisObject->overrodeThings() - && (ident == vm.propertyNames->length - || ident == vm.propertyNames->callee - || ident == vm.propertyNames->iteratorSymbol)) { - thisObject->overrideThings(vm); - PutPropertySlot dummy = slot; // This put is not cacheable, so we shadow the slot that was given to us. - Base::put(thisObject, exec, ident, value, dummy); - return; - } - - Optional<uint32_t> index = parseIndex(ident); - if (index && thisObject->canAccessIndexQuickly(index.value())) { - thisObject->setIndexQuickly(vm, index.value(), value); - return; - } - - Base::put(thisObject, exec, ident, value, slot); -} - -template<typename Type> -void GenericArguments<Type>::putByIndex(JSCell* cell, ExecState* exec, unsigned index, JSValue value, bool shouldThrow) -{ - Type* thisObject = jsCast<Type*>(cell); - VM& vm = exec->vm(); - - if (thisObject->canAccessIndexQuickly(index)) { - thisObject->setIndexQuickly(vm, index, value); - return; - } - - return Base::putByIndex(cell, exec, index, value, shouldThrow); -} - -template<typename Type> -bool GenericArguments<Type>::deleteProperty(JSCell* cell, ExecState* exec, PropertyName ident) -{ - Type* thisObject = jsCast<Type*>(cell); - VM& vm = exec->vm(); - - if (!thisObject->overrodeThings() - && (ident == vm.propertyNames->length - || ident == vm.propertyNames->callee - || ident == vm.propertyNames->iteratorSymbol)) - thisObject->overrideThings(vm); - - Optional<uint32_t> index = parseIndex(ident); - if (index && thisObject->canAccessIndexQuickly(index.value())) { - thisObject->overrideArgument(vm, index.value()); - return true; - } - - return Base::deleteProperty(thisObject, exec, ident); -} - -template<typename Type> -bool GenericArguments<Type>::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned index) -{ - Type* thisObject = jsCast<Type*>(cell); - VM& vm = exec->vm(); - - if (thisObject->canAccessIndexQuickly(index)) { - thisObject->overrideArgument(vm, index); - return true; - } - - return Base::deletePropertyByIndex(cell, exec, index); -} - -template<typename Type> -bool GenericArguments<Type>::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName ident, const PropertyDescriptor& descriptor, bool shouldThrow) -{ - Type* thisObject = jsCast<Type*>(object); - VM& vm = exec->vm(); - - if (ident == vm.propertyNames->length - || ident == vm.propertyNames->callee - || ident == vm.propertyNames->iteratorSymbol) - thisObject->overrideThingsIfNecessary(vm); - else { - Optional<uint32_t> optionalIndex = parseIndex(ident); - if (optionalIndex && thisObject->canAccessIndexQuickly(optionalIndex.value())) { - uint32_t index = optionalIndex.value(); - if (!descriptor.isAccessorDescriptor()) { - // If the property is not deleted and we are using a non-accessor descriptor, then - // make sure that the aliased argument sees the value. - if (descriptor.value()) - thisObject->setIndexQuickly(vm, index, descriptor.value()); - - // If the property is not deleted and we are using a non-accessor, writable - // descriptor, then we are done. The argument continues to be aliased. Note that we - // ignore the request to change enumerability. We appear to have always done so, in - // cases where the argument was still aliased. - // FIXME: https://bugs.webkit.org/show_bug.cgi?id=141952 - if (descriptor.writable()) - return true; - } - - // If the property is a non-deleted argument, then move it into the base object and - // then delete it. - JSValue value = thisObject->getIndexQuickly(index); - ASSERT(value); - object->putDirectMayBeIndex(exec, ident, value); - thisObject->overrideArgument(vm, index); - } - } - - // Now just let the normal object machinery do its thing. - return Base::defineOwnProperty(object, exec, ident, descriptor, shouldThrow); -} - -template<typename Type> -void GenericArguments<Type>::copyToArguments(ExecState* exec, VirtualRegister firstElementDest, unsigned offset, unsigned length) -{ - Type* thisObject = static_cast<Type*>(this); - for (unsigned i = 0; i < length; ++i) { - if (thisObject->canAccessIndexQuickly(i + offset)) - exec->r(firstElementDest + i) = thisObject->getIndexQuickly(i + offset); - else { - exec->r(firstElementDest + i) = get(exec, i + offset); - if (UNLIKELY(exec->vm().exception())) - return; - } - } -} - -} // namespace JSC - -#endif // GenericArgumentsInlines_h - diff --git a/Source/JavaScriptCore/runtime/GenericOffset.h b/Source/JavaScriptCore/runtime/GenericOffset.h deleted file mode 100644 index a6bfe5655..000000000 --- a/Source/JavaScriptCore/runtime/GenericOffset.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2015 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 GenericOffset_h -#define GenericOffset_h - -#include <limits.h> -#include <wtf/Assertions.h> - -namespace JSC { - -// A mixin for creating the various kinds of variable offsets that our engine supports. -template<typename T> -class GenericOffset { -public: - static const unsigned invalidOffset = UINT_MAX; - - GenericOffset() - : m_offset(invalidOffset) - { - } - - explicit GenericOffset(unsigned offset) - : m_offset(offset) - { - } - - bool operator!() const { return m_offset == invalidOffset; } - - unsigned offsetUnchecked() const - { - return m_offset; - } - - unsigned offset() const - { - ASSERT(m_offset != invalidOffset); - return m_offset; - } - - bool operator==(const T& other) const - { - return m_offset == other.offsetUnchecked(); - } - bool operator!=(const T& other) const - { - return m_offset != other.offsetUnchecked(); - } - bool operator<(const T& other) const - { - return m_offset < other.offsetUnchecked(); - } - bool operator>(const T& other) const - { - return m_offset > other.offsetUnchecked(); - } - bool operator<=(const T& other) const - { - return m_offset <= other.offsetUnchecked(); - } - bool operator>=(const T& other) const - { - return m_offset >= other.offsetUnchecked(); - } - - T operator+(int value) const - { - return T(offset() + value); - } - T operator-(int value) const - { - return T(offset() - value); - } - T& operator+=(int value) - { - return *this = *this + value; - } - T& operator-=(int value) - { - return *this = *this - value; - } - -private: - unsigned m_offset; -}; - -} // namespace JSC - -#endif // GenericOffset_h - diff --git a/Source/JavaScriptCore/runtime/GenericTypedArrayView.h b/Source/JavaScriptCore/runtime/GenericTypedArrayView.h index 36e37ca32..0069b386d 100644 --- a/Source/JavaScriptCore/runtime/GenericTypedArrayView.h +++ b/Source/JavaScriptCore/runtime/GenericTypedArrayView.h @@ -37,11 +37,11 @@ protected: GenericTypedArrayView(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length); public: - static RefPtr<GenericTypedArrayView> create(unsigned length); - static RefPtr<GenericTypedArrayView> create(const typename Adaptor::Type* array, unsigned length); - static RefPtr<GenericTypedArrayView> create(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length); + static PassRefPtr<GenericTypedArrayView> create(unsigned length); + static PassRefPtr<GenericTypedArrayView> create(const typename Adaptor::Type* array, unsigned length); + static PassRefPtr<GenericTypedArrayView> create(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length); - static RefPtr<GenericTypedArrayView> createUninitialized(unsigned length); + static PassRefPtr<GenericTypedArrayView> createUninitialized(unsigned length); typename Adaptor::Type* data() const { return static_cast<typename Adaptor::Type*>(baseAddress()); } @@ -98,8 +98,8 @@ public: && offset + pos >= offset); } - RefPtr<GenericTypedArrayView> subarray(int start) const; - RefPtr<GenericTypedArrayView> subarray(int start, int end) const; + PassRefPtr<GenericTypedArrayView> subarray(int start) const; + PassRefPtr<GenericTypedArrayView> subarray(int start, int end) const; virtual TypedArrayType getType() const override { diff --git a/Source/JavaScriptCore/runtime/GenericTypedArrayViewInlines.h b/Source/JavaScriptCore/runtime/GenericTypedArrayViewInlines.h index 253726965..1289c5035 100644 --- a/Source/JavaScriptCore/runtime/GenericTypedArrayViewInlines.h +++ b/Source/JavaScriptCore/runtime/GenericTypedArrayViewInlines.h @@ -40,16 +40,16 @@ GenericTypedArrayView<Adaptor>::GenericTypedArrayView( } template<typename Adaptor> -RefPtr<GenericTypedArrayView<Adaptor>> GenericTypedArrayView<Adaptor>::create(unsigned length) +PassRefPtr<GenericTypedArrayView<Adaptor>> GenericTypedArrayView<Adaptor>::create(unsigned length) { RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(length, sizeof(typename Adaptor::Type)); if (!buffer) - return nullptr; - return create(buffer.release(), 0, length); + return 0; + return create(buffer, 0, length); } template<typename Adaptor> -RefPtr<GenericTypedArrayView<Adaptor>> GenericTypedArrayView<Adaptor>::create( +PassRefPtr<GenericTypedArrayView<Adaptor>> GenericTypedArrayView<Adaptor>::create( const typename Adaptor::Type* array, unsigned length) { RefPtr<GenericTypedArrayView> result = create(length); @@ -58,38 +58,36 @@ RefPtr<GenericTypedArrayView<Adaptor>> GenericTypedArrayView<Adaptor>::create( } template<typename Adaptor> -RefPtr<GenericTypedArrayView<Adaptor>> GenericTypedArrayView<Adaptor>::create( +PassRefPtr<GenericTypedArrayView<Adaptor>> GenericTypedArrayView<Adaptor>::create( PassRefPtr<ArrayBuffer> passedBuffer, unsigned byteOffset, unsigned length) { RefPtr<ArrayBuffer> buffer = passedBuffer; - if (!verifySubRangeLength(buffer, byteOffset, length, sizeof(typename Adaptor::Type)) - || !verifyByteOffsetAlignment(byteOffset, sizeof(typename Adaptor::Type))) { - return nullptr; - } + if (!verifySubRange<typename Adaptor::Type>(buffer, byteOffset, length)) + return 0; - return adoptRef(new GenericTypedArrayView(buffer.release(), byteOffset, length)); + return adoptRef(new GenericTypedArrayView(buffer, byteOffset, length)); } template<typename Adaptor> -RefPtr<GenericTypedArrayView<Adaptor>> +PassRefPtr<GenericTypedArrayView<Adaptor>> GenericTypedArrayView<Adaptor>::createUninitialized(unsigned length) { RefPtr<ArrayBuffer> buffer = ArrayBuffer::createUninitialized(length, sizeof(typename Adaptor::Type)); if (!buffer) - return nullptr; - return create(buffer.release(), 0, length); + return 0; + return create(buffer, 0, length); } template<typename Adaptor> -RefPtr<GenericTypedArrayView<Adaptor>> +PassRefPtr<GenericTypedArrayView<Adaptor>> GenericTypedArrayView<Adaptor>::subarray(int start) const { return subarray(start, length()); } template<typename Adaptor> -RefPtr<GenericTypedArrayView<Adaptor>> +PassRefPtr<GenericTypedArrayView<Adaptor>> GenericTypedArrayView<Adaptor>::subarray(int start, int end) const { unsigned offset, length; diff --git a/Source/JavaScriptCore/runtime/GetterSetter.cpp b/Source/JavaScriptCore/runtime/GetterSetter.cpp index 2cd66e5cd..21a7153c0 100644 --- a/Source/JavaScriptCore/runtime/GetterSetter.cpp +++ b/Source/JavaScriptCore/runtime/GetterSetter.cpp @@ -1,7 +1,7 @@ /* * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2004, 2007, 2008, 2009, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2007, 2008, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,84 +24,57 @@ #include "GetterSetter.h" #include "Error.h" -#include "Exception.h" #include "JSObject.h" -#include "JSCInlines.h" +#include "Operations.h" #include <wtf/Assertions.h> namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(GetterSetter); -const ClassInfo GetterSetter::s_info = { "GetterSetter", 0, 0, CREATE_METHOD_TABLE(GetterSetter) }; +const ClassInfo GetterSetter::s_info = { "GetterSetter", 0, 0, 0, CREATE_METHOD_TABLE(GetterSetter) }; void GetterSetter::visitChildren(JSCell* cell, SlotVisitor& visitor) { GetterSetter* thisObject = jsCast<GetterSetter*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); JSCell::visitChildren(thisObject, visitor); visitor.append(&thisObject->m_getter); visitor.append(&thisObject->m_setter); } -GetterSetter* GetterSetter::withGetter(VM& vm, JSGlobalObject* globalObject, JSObject* newGetter) -{ - if (isGetterNull()) { - setGetter(vm, globalObject, newGetter); - return this; - } - - GetterSetter* result = GetterSetter::create(vm, globalObject); - result->setGetter(vm, globalObject, newGetter); - result->setSetter(vm, globalObject, setter()); - return result; -} - -GetterSetter* GetterSetter::withSetter(VM& vm, JSGlobalObject* globalObject, JSObject* newSetter) -{ - if (isSetterNull()) { - setSetter(vm, globalObject, newSetter); - return this; - } - - GetterSetter* result = GetterSetter::create(vm, globalObject); - result->setGetter(vm, globalObject, getter()); - result->setSetter(vm, globalObject, newSetter); - return result; -} - JSValue callGetter(ExecState* exec, JSValue base, JSValue getterSetter) { // FIXME: Some callers may invoke get() without checking for an exception first. // We work around that by checking here. if (exec->hadException()) - return exec->exception()->value(); + return exec->exception(); JSObject* getter = jsCast<GetterSetter*>(getterSetter)->getter(); + if (!getter) + return jsUndefined(); CallData callData; - CallType callType = getter->methodTable(exec->vm())->getCallData(getter, callData); + CallType callType = getter->methodTable()->getCallData(getter, callData); return call(exec, getter, callType, callData, base, ArgList()); } void callSetter(ExecState* exec, JSValue base, JSValue getterSetter, JSValue value, ECMAMode ecmaMode) { - GetterSetter* getterSetterObj = jsCast<GetterSetter*>(getterSetter); - - if (getterSetterObj->isSetterNull()) { + JSObject* setter = jsCast<GetterSetter*>(getterSetter)->setter(); + if (!setter) { if (ecmaMode == StrictMode) throwTypeError(exec, StrictModeReadonlyPropertyWriteError); return; } - JSObject* setter = getterSetterObj->setter(); - MarkedArgumentBuffer args; args.append(value); CallData callData; - CallType callType = setter->methodTable(exec->vm())->getCallData(setter, callData); + CallType callType = setter->methodTable()->getCallData(setter, callData); call(exec, setter, callType, callData, base, args); } diff --git a/Source/JavaScriptCore/runtime/GetterSetter.h b/Source/JavaScriptCore/runtime/GetterSetter.h index b983f043d..5695bb9e7 100644 --- a/Source/JavaScriptCore/runtime/GetterSetter.h +++ b/Source/JavaScriptCore/runtime/GetterSetter.h @@ -1,7 +1,7 @@ /* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -26,125 +26,61 @@ #include "JSCell.h" #include "CallFrame.h" -#include "JSGlobalObject.h" -#include "NullGetterFunction.h" -#include "NullSetterFunction.h" #include "Structure.h" namespace JSC { -class JSObject; - -// This is an internal value object which stores getter and setter functions -// for a property. Instances of this class have the property that once a getter -// or setter is set to a non-null value, then they cannot be changed. This means -// that if a property holding a GetterSetter reference is constant-inferred and -// that constant is observed to have a non-null setter (or getter) then we can -// constant fold that setter (or getter). -class GetterSetter final : public JSCell { - friend class JIT; - -private: - GetterSetter(VM& vm, JSGlobalObject* globalObject) - : JSCell(vm, vm.getterSetterStructure.get()) - { - m_getter.set(vm, this, globalObject->nullGetterFunction()); - m_setter.set(vm, this, globalObject->nullSetterFunction()); - } - -public: - typedef JSCell Base; - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; - - static GetterSetter* create(VM& vm, JSGlobalObject* globalObject) - { - GetterSetter* getterSetter = new (NotNull, allocateCell<GetterSetter>(vm.heap)) GetterSetter(vm, globalObject); - getterSetter->finishCreation(vm); - return getterSetter; - } - - static void visitChildren(JSCell*, SlotVisitor&); - - JSObject* getter() const { return m_getter.get(); } - - JSObject* getterConcurrently() const - { - JSObject* result = getter(); - WTF::loadLoadFence(); - return result; - } - - bool isGetterNull() const { return !!jsDynamicCast<NullGetterFunction*>(m_getter.get()); } - bool isSetterNull() const { return !!jsDynamicCast<NullSetterFunction*>(m_setter.get()); } - - // Set the getter. It's only valid to call this if you've never set the getter on this - // object. - void setGetter(VM& vm, JSGlobalObject* globalObject, JSObject* getter) - { - if (!getter) - getter = jsCast<JSObject*>(globalObject->nullGetterFunction()); - - RELEASE_ASSERT(isGetterNull()); - WTF::storeStoreFence(); - m_getter.set(vm, this, getter); - } - - JSObject* setter() const { return m_setter.get(); } - - JSObject* setterConcurrently() const - { - JSObject* result = setter(); - WTF::loadLoadFence(); - return result; - } - - // Set the setter. It's only valid to call this if you've never set the setter on this - // object. - void setSetter(VM& vm, JSGlobalObject* globalObject, JSObject* setter) - { - if (!setter) - setter = jsCast<JSObject*>(globalObject->nullSetterFunction()); - - RELEASE_ASSERT(isSetterNull()); - WTF::storeStoreFence(); - m_setter.set(vm, this, setter); - } - - GetterSetter* withGetter(VM&, JSGlobalObject*, JSObject* getter); - GetterSetter* withSetter(VM&, JSGlobalObject*, JSObject* setter); - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + class JSObject; + + // This is an internal value object which stores getter and setter functions + // for a property. + class GetterSetter : public JSCell { + friend class JIT; + + private: + GetterSetter(VM& vm) + : JSCell(vm, vm.getterSetterStructure.get()) + { + } + + public: + typedef JSCell Base; + + static GetterSetter* create(VM& vm) + { + GetterSetter* getterSetter = new (NotNull, allocateCell<GetterSetter>(vm.heap)) GetterSetter(vm); + getterSetter->finishCreation(vm); + return getterSetter; + } + + static void visitChildren(JSCell*, SlotVisitor&); + + JSObject* getter() const { return m_getter.get(); } + void setGetter(VM& vm, JSObject* getter) { m_getter.setMayBeNull(vm, this, getter); } + JSObject* setter() const { return m_setter.get(); } + void setSetter(VM& vm, JSObject* setter) { m_setter.setMayBeNull(vm, this, setter); } + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(GetterSetterType, OverridesVisitChildren), info()); + } + + DECLARE_INFO; + + private: + WriteBarrier<JSObject> m_getter; + WriteBarrier<JSObject> m_setter; + }; + + GetterSetter* asGetterSetter(JSValue); + + inline GetterSetter* asGetterSetter(JSValue value) { - return Structure::create(vm, globalObject, prototype, TypeInfo(GetterSetterType), info()); + ASSERT(value.asCell()->isGetterSetter()); + return static_cast<GetterSetter*>(value.asCell()); } - static ptrdiff_t offsetOfGetter() - { - return OBJECT_OFFSETOF(GetterSetter, m_getter); - } - - static ptrdiff_t offsetOfSetter() - { - return OBJECT_OFFSETOF(GetterSetter, m_setter); - } - - DECLARE_INFO; - -private: - WriteBarrier<JSObject> m_getter; - WriteBarrier<JSObject> m_setter; -}; - -GetterSetter* asGetterSetter(JSValue); - -inline GetterSetter* asGetterSetter(JSValue value) -{ - ASSERT_WITH_SECURITY_IMPLICATION(value.asCell()->isGetterSetter()); - return static_cast<GetterSetter*>(value.asCell()); -} - -JSValue callGetter(ExecState*, JSValue base, JSValue getterSetter); -void callSetter(ExecState*, JSValue base, JSValue getterSetter, JSValue, ECMAMode); + JSValue callGetter(ExecState*, JSValue base, JSValue getterSetter); + void callSetter(ExecState*, JSValue base, JSValue getterSetter, JSValue value, ECMAMode); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Identifier.cpp b/Source/JavaScriptCore/runtime/Identifier.cpp index d26d9567c..3658d8772 100644 --- a/Source/JavaScriptCore/runtime/Identifier.cpp +++ b/Source/JavaScriptCore/runtime/Identifier.cpp @@ -25,7 +25,7 @@ #include "JSObject.h" #include "JSScope.h" #include "NumericStrings.h" -#include "JSCInlines.h" +#include "Operations.h" #include <new> #include <string.h> #include <wtf/Assertions.h> @@ -38,33 +38,121 @@ using WTF::ThreadSpecific; namespace JSC { -Ref<StringImpl> Identifier::add(VM* vm, const char* c) +IdentifierTable* createIdentifierTable() +{ + return new IdentifierTable; +} + +void deleteIdentifierTable(IdentifierTable* table) +{ + delete table; +} + +struct IdentifierASCIIStringTranslator { + static unsigned hash(const LChar* c) + { + return StringHasher::computeHashAndMaskTop8Bits(c); + } + + static bool equal(StringImpl* r, const LChar* s) + { + return Identifier::equal(r, s); + } + + static void translate(StringImpl*& location, const LChar* c, unsigned hash) + { + size_t length = strlen(reinterpret_cast<const char*>(c)); + location = &StringImpl::createFromLiteral(reinterpret_cast<const char*>(c), length).leakRef(); + location->setHash(hash); + } +}; + +struct IdentifierLCharFromUCharTranslator { + static unsigned hash(const CharBuffer<UChar>& buf) + { + return StringHasher::computeHashAndMaskTop8Bits(buf.s, buf.length); + } + + static bool equal(StringImpl* str, const CharBuffer<UChar>& buf) + { + return Identifier::equal(str, buf.s, buf.length); + } + + static void translate(StringImpl*& location, const CharBuffer<UChar>& buf, unsigned hash) + { + LChar* d; + StringImpl& r = StringImpl::createUninitialized(buf.length, d).leakRef(); + WTF::copyLCharsFromUCharSource(d, buf.s, buf.length); + r.setHash(hash); + location = &r; + } +}; + +PassRefPtr<StringImpl> Identifier::add(VM* vm, const char* c) { ASSERT(c); ASSERT(c[0]); if (!c[1]) - return *vm->smallStrings.singleCharacterStringRep(c[0]); + return add(vm, vm->smallStrings.singleCharacterStringRep(c[0])); + + IdentifierTable& identifierTable = *vm->identifierTable; + + HashSet<StringImpl*>::AddResult addResult = identifierTable.add<const LChar*, IdentifierASCIIStringTranslator>(reinterpret_cast<const LChar*>(c)); + + // If the string is newly-translated, then we need to adopt it. + // The boolean in the pair tells us if that is so. + RefPtr<StringImpl> addedString = addResult.isNewEntry ? adoptRef(*addResult.iterator) : *addResult.iterator; - return *AtomicStringImpl::add(c); + return addedString.release(); } -Ref<StringImpl> Identifier::add(ExecState* exec, const char* c) +PassRefPtr<StringImpl> Identifier::add(ExecState* exec, const char* c) { return add(&exec->vm(), c); } -Ref<StringImpl> Identifier::add8(VM* vm, 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 *vm->smallStrings.singleCharacterStringRep(c); + return add(vm, vm->smallStrings.singleCharacterStringRep(c)); } + if (!length) - return *StringImpl::empty(); + return StringImpl::empty(); + CharBuffer<UChar> buf = { s, static_cast<unsigned>(length) }; + 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(VM* vm, StringImpl* r) +{ + if (r->isEmptyUnique()) + return r; + ASSERT(!r->isIdentifier()); + // The empty & null strings are static singletons, and static strings are handled + // in ::add() in the header, so we should never get here with a zero length string. + ASSERT(r->length()); + + if (r->length() == 1) { + UChar c = (*r)[0]; + if (c <= maxSingleCharacterString) + r = vm->smallStrings.singleCharacterStringRep(c); + if (r->isIdentifier()) + return r; + } + + return *vm->identifierTable->add(r).iterator; +} - return *AtomicStringImpl::add(s, length); +PassRefPtr<StringImpl> Identifier::addSlowCase(ExecState* exec, StringImpl* r) +{ + return addSlowCase(&exec->vm(), r); } Identifier Identifier::from(ExecState* exec, unsigned value) @@ -97,34 +185,26 @@ Identifier Identifier::from(VM* vm, double value) return Identifier(vm, vm->numericStrings.add(value)); } -void Identifier::dump(PrintStream& out) const -{ - if (impl()) - out.print(impl()); - else - out.print("<null identifier>"); -} - #ifndef NDEBUG -void Identifier::checkCurrentAtomicStringTable(VM* vm) +void Identifier::checkCurrentIdentifierTable(VM* vm) { // Check the identifier table accessible through the threadspecific matches the // vm's identifier table. - ASSERT_UNUSED(vm, vm->atomicStringTable() == wtfThreadData().atomicStringTable()); + ASSERT_UNUSED(vm, vm->identifierTable == wtfThreadData().currentIdentifierTable()); } -void Identifier::checkCurrentAtomicStringTable(ExecState* exec) +void Identifier::checkCurrentIdentifierTable(ExecState* exec) { - checkCurrentAtomicStringTable(&exec->vm()); + checkCurrentIdentifierTable(&exec->vm()); } #else // These only exists so that our exports are the same for debug and release builds. // This would be an RELEASE_ASSERT_NOT_REACHED(), but we're in NDEBUG only code here! -NO_RETURN_DUE_TO_CRASH void Identifier::checkCurrentAtomicStringTable(VM*) { CRASH(); } -NO_RETURN_DUE_TO_CRASH void Identifier::checkCurrentAtomicStringTable(ExecState*) { CRASH(); } +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 61de6536a..6733ec5f2 100644 --- a/Source/JavaScriptCore/runtime/Identifier.h +++ b/Source/JavaScriptCore/runtime/Identifier.h @@ -22,278 +22,248 @@ #define Identifier_h #include "VM.h" -#include <wtf/Optional.h> #include <wtf/ThreadSpecific.h> #include <wtf/WTFThreadData.h> #include <wtf/text/CString.h> -#include <wtf/text/UniquedStringImpl.h> #include <wtf/text/WTFString.h> namespace JSC { -class ExecState; - -ALWAYS_INLINE bool isIndex(uint32_t index) -{ - return index != 0xFFFFFFFFU; -} - -template <typename CharType> -ALWAYS_INLINE Optional<uint32_t> parseIndex(const CharType* characters, unsigned length) -{ - // An empty string is not a number. - if (!length) - return Nullopt; - - // Get the first character, turning it into a digit. - uint32_t value = characters[0] - '0'; - if (value > 9) - return Nullopt; - - // Check for leading zeros. If the first characher is 0, then the - // length of the string must be one - e.g. "042" is not equal to "42". - if (!value && length > 1) - return Nullopt; - - while (--length) { - // Multiply value by 10, checking for overflow out of 32 bits. - if (value > 0xFFFFFFFFU / 10) - return Nullopt; - value *= 10; - - // Get the next character, turning it into a digit. - uint32_t newValue = *(++characters) - '0'; - if (newValue > 9) - return Nullopt; - - // Add in the old value, checking for overflow out of 32 bits. - newValue += value; - if (newValue < value) - return Nullopt; - value = newValue; + class ExecState; + + class Identifier { + friend class Structure; + public: + Identifier() { } + enum EmptyIdentifierFlag { EmptyIdentifier }; + Identifier(EmptyIdentifierFlag) : m_string(StringImpl::empty()) { } + + // Only to be used with string literals. + template<unsigned charactersCount> + Identifier(ExecState* exec, const char (&characters)[charactersCount]) : m_string(add(exec, characters)) { } + template<unsigned charactersCount> + 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(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(); } + + const UChar* deprecatedCharacters() const { return m_string.deprecatedCharacters(); } + int length() const { return m_string.length(); } + + CString ascii() const { return m_string.ascii(); } + CString utf8() const { return m_string.utf8(); } + + static Identifier from(const PrivateName& name) + { + Identifier result; + result.m_string = name.uid(); + return result; + } + + 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(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(); } + + friend bool operator==(const Identifier&, const Identifier&); + friend bool operator!=(const Identifier&, const Identifier&); + + friend bool operator==(const Identifier&, const LChar*); + friend bool operator==(const Identifier&, const char*); + friend bool operator!=(const Identifier&, const LChar*); + friend bool operator!=(const Identifier&, const char*); + + static bool equal(const StringImpl*, const LChar*); + static inline bool equal(const StringImpl*a, const char*b) { return Identifier::equal(a, reinterpret_cast<const LChar*>(b)); }; + static bool equal(const StringImpl*, const LChar*, unsigned length); + static bool equal(const StringImpl*, const UChar*, unsigned length); + static bool equal(const StringImpl* a, const StringImpl* b) { return ::equal(a, b); } + + // Only to be used with string literals. + static PassRefPtr<StringImpl> add(VM*, const char*); + JS_EXPORT_PRIVATE static PassRefPtr<StringImpl> add(ExecState*, const char*); + + private: + String m_string; + + template <typename CharType> + ALWAYS_INLINE static uint32_t toUInt32FromCharacters(const CharType* characters, unsigned length, bool& ok); + + 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(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) + { +#ifndef NDEBUG + checkCurrentIdentifierTable(exec); +#endif + if (r->isIdentifier()) + return r; + return addSlowCase(exec, r); + } + static PassRefPtr<StringImpl> add(VM* vm, StringImpl* r) + { +#ifndef NDEBUG + checkCurrentIdentifierTable(vm); +#endif + if (r->isIdentifier()) + return r; + return addSlowCase(vm, r); + } + + JS_EXPORT_PRIVATE static PassRefPtr<StringImpl> addSlowCase(ExecState*, 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(VM*); + }; + + template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(LChar) + { + ASSERT(maxSingleCharacterString == 0xff); + return true; } - if (!isIndex(value)) - return Nullopt; - return value; -} - -ALWAYS_INLINE Optional<uint32_t> parseIndex(StringImpl& impl) -{ - if (impl.is8Bit()) - return parseIndex(impl.characters8(), impl.length()); - return parseIndex(impl.characters16(), impl.length()); -} - -class Identifier { - friend class Structure; -public: - Identifier() { } - enum EmptyIdentifierFlag { EmptyIdentifier }; - Identifier(EmptyIdentifierFlag) : m_string(StringImpl::empty()) { ASSERT(m_string.impl()->isAtomic()); } - - const String& string() const { return m_string; } - UniquedStringImpl* impl() const { return static_cast<UniquedStringImpl*>(m_string.impl()); } - - int length() const { return m_string.length(); } - - CString ascii() const { return m_string.ascii(); } - CString utf8() const { return m_string.utf8(); } - - // There's 2 functions to construct Identifier from string, (1) fromString and (2) fromUid. - // They have different meanings in keeping or discarding symbol-ness of strings. - // (1): fromString - // Just construct Identifier from string. String held by Identifier is always atomized. - // Symbol-ness of StringImpl*, which represents that the string is inteded to be used for ES6 Symbols, is discarded. - // So a constructed Identifier never represents a symbol. - // (2): fromUid - // `StringImpl* uid` represents ether String or Symbol property. - // fromUid keeps symbol-ness of provided StringImpl* while fromString discards it. - // Use fromUid when constructing Identifier from StringImpl* which may represent symbols. - - // Only to be used with string literals. - template<unsigned charactersCount> - static Identifier fromString(VM*, const char (&characters)[charactersCount]); - template<unsigned charactersCount> - static Identifier fromString(ExecState*, const char (&characters)[charactersCount]); - static Identifier fromString(VM*, const LChar*, int length); - static Identifier fromString(VM*, const UChar*, int length); - static Identifier fromString(VM*, const String&); - static Identifier fromString(ExecState*, AtomicStringImpl*); - static Identifier fromString(ExecState*, const AtomicString&); - static Identifier fromString(ExecState*, const String&); - static Identifier fromString(ExecState*, const char*); - - static Identifier fromUid(VM*, UniquedStringImpl* uid); - static Identifier fromUid(ExecState*, UniquedStringImpl* uid); - static Identifier fromUid(const PrivateName&); - - static Identifier createLCharFromUChar(VM* vm, const UChar* s, int length) { return Identifier(vm, add8(vm, s, length)); } - - JS_EXPORT_PRIVATE static Identifier from(ExecState*, unsigned y); - JS_EXPORT_PRIVATE static Identifier from(ExecState*, int y); - static Identifier from(ExecState*, 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(); } - bool isSymbol() const { return !isNull() && impl()->isSymbol(); } - - friend bool operator==(const Identifier&, const Identifier&); - friend bool operator!=(const Identifier&, const Identifier&); - - friend bool operator==(const Identifier&, const LChar*); - friend bool operator==(const Identifier&, const char*); - friend bool operator!=(const Identifier&, const LChar*); - friend bool operator!=(const Identifier&, const char*); - - static bool equal(const StringImpl*, const LChar*); - static inline bool equal(const StringImpl*a, const char*b) { return Identifier::equal(a, reinterpret_cast<const LChar*>(b)); }; - static bool equal(const StringImpl*, const LChar*, unsigned length); - static bool equal(const StringImpl*, const UChar*, unsigned length); - static bool equal(const StringImpl* a, const StringImpl* b) { return ::equal(a, b); } - - // Only to be used with string literals. - JS_EXPORT_PRIVATE static Ref<StringImpl> add(VM*, const char*); - JS_EXPORT_PRIVATE static Ref<StringImpl> add(ExecState*, const char*); - - void dump(PrintStream&) const; - -private: - String m_string; - - // Only to be used with string literals. - template<unsigned charactersCount> - Identifier(VM* vm, const char (&characters)[charactersCount]) : m_string(add(vm, characters)) { ASSERT(m_string.impl()->isAtomic()); } - - Identifier(VM* vm, const LChar* s, int length) : m_string(add(vm, s, length)) { ASSERT(m_string.impl()->isAtomic()); } - Identifier(VM* vm, const UChar* s, int length) : m_string(add(vm, s, length)) { ASSERT(m_string.impl()->isAtomic()); } - Identifier(ExecState*, AtomicStringImpl*); - Identifier(ExecState*, const AtomicString&); - Identifier(VM* vm, const String& string) : m_string(add(vm, string.impl())) { ASSERT(m_string.impl()->isAtomic()); } - Identifier(VM* vm, StringImpl* rep) : m_string(add(vm, rep)) { ASSERT(m_string.impl()->isAtomic()); } - - Identifier(SymbolImpl& uid) - : m_string(&uid) + template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(UChar c) { + return (c <= maxSingleCharacterString); } - template <typename CharType> - ALWAYS_INLINE static uint32_t toUInt32FromCharacters(const CharType* characters, unsigned length, bool& ok); + template <typename T> + struct CharBuffer { + const T* s; + unsigned int length; + }; + + template <typename T> + struct IdentifierCharBufferTranslator { + static unsigned hash(const CharBuffer<T>& buf) + { + return StringHasher::computeHashAndMaskTop8Bits(buf.s, buf.length); + } + + static bool equal(StringImpl* str, const CharBuffer<T>& buf) + { + return Identifier::equal(str, buf.s, buf.length); + } + + static void translate(StringImpl*& location, const CharBuffer<T>& buf, unsigned hash) + { + T* d; + StringImpl& r = StringImpl::createUninitialized(buf.length, d).leakRef(); + for (unsigned i = 0; i != buf.length; i++) + d[i] = buf.s[i]; + r.setHash(hash); + location = &r; + } + }; + + template <typename T> + PassRefPtr<StringImpl> Identifier::add(VM* vm, const T* s, int length) + { + if (length == 1) { + T c = s[0]; + if (canUseSingleCharacterString(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 = 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. + return addResult.isNewEntry ? adoptRef(*addResult.iterator) : *addResult.iterator; + } - 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); } + inline bool operator==(const Identifier& a, const Identifier& b) + { + return Identifier::equal(a, b); + } - template <typename T> static Ref<StringImpl> add(VM*, const T*, int length); - static Ref<StringImpl> add8(VM*, const UChar*, int length); - template <typename T> ALWAYS_INLINE static bool canUseSingleCharacterString(T); + inline bool operator!=(const Identifier& a, const Identifier& b) + { + return !Identifier::equal(a, b); + } - static Ref<StringImpl> add(ExecState*, StringImpl*); - static Ref<StringImpl> add(VM*, StringImpl*); + inline bool operator==(const Identifier& a, const LChar* b) + { + return Identifier::equal(a, b); + } -#ifndef NDEBUG - JS_EXPORT_PRIVATE static void checkCurrentAtomicStringTable(ExecState*); - JS_EXPORT_PRIVATE static void checkCurrentAtomicStringTable(VM*); -#else - JS_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH static void checkCurrentAtomicStringTable(ExecState*); - JS_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH static void checkCurrentAtomicStringTable(VM*); -#endif -}; - -template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(LChar) -{ - ASSERT(maxSingleCharacterString == 0xff); - return true; -} - -template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(UChar c) -{ - return (c <= maxSingleCharacterString); -} - -template <typename T> -Ref<StringImpl> Identifier::add(VM* vm, const T* s, int length) -{ - if (length == 1) { - T c = s[0]; - if (canUseSingleCharacterString(c)) - return *vm->smallStrings.singleCharacterStringRep(c); + inline bool operator==(const Identifier& a, const char* b) + { + return Identifier::equal(a, reinterpret_cast<const LChar*>(b)); + } + + inline bool operator!=(const Identifier& a, const LChar* b) + { + return !Identifier::equal(a, b); + } + + inline bool operator!=(const Identifier& a, const char* b) + { + return !Identifier::equal(a, reinterpret_cast<const LChar*>(b)); + } + + inline bool Identifier::equal(const StringImpl* r, const LChar* s) + { + return WTF::equal(r, s); + } + + inline bool Identifier::equal(const StringImpl* r, const LChar* s, unsigned length) + { + return WTF::equal(r, s, length); + } + + inline bool Identifier::equal(const StringImpl* r, const UChar* s, unsigned length) + { + return WTF::equal(r, s, length); + } + + IdentifierTable* createIdentifierTable(); + void deleteIdentifierTable(IdentifierTable*); + + struct IdentifierRepHash : PtrHash<RefPtr<StringImpl>> { + static unsigned hash(const RefPtr<StringImpl>& key) { return key->existingHash(); } + static unsigned hash(StringImpl* key) { return key->existingHash(); } + }; + + struct IdentifierMapIndexHashTraits : HashTraits<int> { + static int emptyValue() { return std::numeric_limits<int>::max(); } + static const bool emptyValueIsZero = false; + }; + + typedef HashMap<RefPtr<StringImpl>, int, IdentifierRepHash, HashTraits<RefPtr<StringImpl>>, IdentifierMapIndexHashTraits> IdentifierMap; + typedef HashMap<StringImpl*, int, IdentifierRepHash, HashTraits<StringImpl*>, IdentifierMapIndexHashTraits> BorrowedIdentifierMap; + + template<typename U, typename V> + HashSet<StringImpl*>::AddResult IdentifierTable::add(U value) + { + HashSet<StringImpl*>::AddResult result = m_table.add<V>(value); + (*result.iterator)->setIsIdentifier(true); + return result; } - if (!length) - return *StringImpl::empty(); - - return *AtomicStringImpl::add(s, length); -} - -inline bool operator==(const Identifier& a, const Identifier& b) -{ - return Identifier::equal(a, b); -} - -inline bool operator!=(const Identifier& a, const Identifier& b) -{ - return !Identifier::equal(a, b); -} - -inline bool operator==(const Identifier& a, const LChar* b) -{ - return Identifier::equal(a, b); -} - -inline bool operator==(const Identifier& a, const char* b) -{ - return Identifier::equal(a, reinterpret_cast<const LChar*>(b)); -} - -inline bool operator!=(const Identifier& a, const LChar* b) -{ - return !Identifier::equal(a, b); -} - -inline bool operator!=(const Identifier& a, const char* b) -{ - return !Identifier::equal(a, reinterpret_cast<const LChar*>(b)); -} - -inline bool Identifier::equal(const StringImpl* r, const LChar* s) -{ - return WTF::equal(r, s); -} - -inline bool Identifier::equal(const StringImpl* r, const LChar* s, unsigned length) -{ - return WTF::equal(r, s, length); -} - -inline bool Identifier::equal(const StringImpl* r, const UChar* s, unsigned length) -{ - return WTF::equal(r, s, length); -} - -ALWAYS_INLINE Optional<uint32_t> parseIndex(const Identifier& identifier) -{ - auto uid = identifier.impl(); - if (!uid) - return Nullopt; - if (uid->isSymbol()) - return Nullopt; - return parseIndex(*uid); -} - -struct IdentifierRepHash : PtrHash<RefPtr<UniquedStringImpl>> { - static unsigned hash(const RefPtr<UniquedStringImpl>& key) { return key->existingSymbolAwareHash(); } - static unsigned hash(UniquedStringImpl* key) { return key->existingSymbolAwareHash(); } -}; - -struct IdentifierMapIndexHashTraits : HashTraits<int> { - static int emptyValue() { return std::numeric_limits<int>::max(); } - static const bool emptyValueIsZero = false; -}; - -typedef HashMap<RefPtr<UniquedStringImpl>, int, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, IdentifierMapIndexHashTraits> IdentifierMap; -typedef HashMap<UniquedStringImpl*, int, IdentifierRepHash, HashTraits<UniquedStringImpl*>, IdentifierMapIndexHashTraits> BorrowedIdentifierMap; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/IdentifierInlines.h b/Source/JavaScriptCore/runtime/IdentifierInlines.h deleted file mode 100644 index 6b50748e7..000000000 --- a/Source/JavaScriptCore/runtime/IdentifierInlines.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (C) 2014 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 IdentifierInlines_h -#define IdentifierInlines_h - -#include "CallFrame.h" -#include "Identifier.h" - -namespace JSC { - -inline Identifier::Identifier(ExecState* exec, AtomicStringImpl* string) - : m_string(string) -{ -#ifndef NDEBUG - checkCurrentAtomicStringTable(exec); - if (string) - ASSERT_WITH_MESSAGE(!string->length() || string->isSymbol() || AtomicStringImpl::isInAtomicStringTable(string), "The atomic string comes from an other thread!"); -#else - UNUSED_PARAM(exec); -#endif -} - -inline Identifier::Identifier(ExecState* exec, const AtomicString& string) - : m_string(string.string()) -{ -#ifndef NDEBUG - checkCurrentAtomicStringTable(exec); - if (!string.isNull()) - ASSERT_WITH_MESSAGE(!string.length() || string.impl()->isSymbol() || AtomicStringImpl::isInAtomicStringTable(string.impl()), "The atomic string comes from an other thread!"); -#else - UNUSED_PARAM(exec); -#endif -} - -inline Ref<StringImpl> Identifier::add(ExecState* exec, StringImpl* r) -{ -#ifndef NDEBUG - checkCurrentAtomicStringTable(exec); -#endif - return *AtomicStringImpl::addWithStringTableProvider(*exec, r); -} -inline Ref<StringImpl> Identifier::add(VM* vm, StringImpl* r) -{ -#ifndef NDEBUG - checkCurrentAtomicStringTable(vm); -#endif - return *AtomicStringImpl::addWithStringTableProvider(*vm, r); -} - -inline Identifier Identifier::fromUid(VM* vm, UniquedStringImpl* uid) -{ - if (!uid || !uid->isSymbol()) - return Identifier(vm, uid); - return static_cast<SymbolImpl&>(*uid); -} - -inline Identifier Identifier::fromUid(ExecState* exec, UniquedStringImpl* uid) -{ - return fromUid(&exec->vm(), uid); -} - -inline Identifier Identifier::fromUid(const PrivateName& name) -{ - return *name.uid(); -} - -template<unsigned charactersCount> -inline Identifier Identifier::fromString(VM* vm, const char (&characters)[charactersCount]) -{ - return Identifier(vm, characters); -} - -template<unsigned charactersCount> -inline Identifier Identifier::fromString(ExecState* exec, const char (&characters)[charactersCount]) -{ - return Identifier(&exec->vm(), characters); -} - -inline Identifier Identifier::fromString(VM* vm, const LChar* s, int length) -{ - return Identifier(vm, s, length); -} - -inline Identifier Identifier::fromString(VM* vm, const UChar* s, int length) -{ - return Identifier(vm, s, length); -} - -inline Identifier Identifier::fromString(VM* vm, const String& string) -{ - return Identifier(vm, string.impl()); -} - -inline Identifier Identifier::fromString(ExecState* exec, const String& string) -{ - return Identifier(&exec->vm(), string.impl()); -} - -inline Identifier Identifier::fromString(ExecState* exec, AtomicStringImpl* atomicString) -{ - return Identifier(exec, atomicString); -} - -inline Identifier Identifier::fromString(ExecState* exec, const AtomicString& atomicString) -{ - return Identifier(exec, atomicString); -} - -inline Identifier Identifier::fromString(ExecState* exec, const char* s) -{ - return Identifier(exec, AtomicString(s)); -} - -} // namespace JSC - -#endif // IdentifierInlines_h diff --git a/Source/JavaScriptCore/runtime/IndexingHeader.h b/Source/JavaScriptCore/runtime/IndexingHeader.h index a88643239..27881297b 100644 --- a/Source/JavaScriptCore/runtime/IndexingHeader.h +++ b/Source/JavaScriptCore/runtime/IndexingHeader.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2014 Apple Inc. All rights reserved. + * 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 @@ -27,6 +27,7 @@ #define IndexingHeader_h #include "PropertyStorage.h" +#include <wtf/Platform.h> namespace JSC { @@ -62,7 +63,7 @@ public: u.lengths.vectorLength = length; } - uint32_t publicLength() const { return u.lengths.publicLength; } + uint32_t publicLength() { return u.lengths.publicLength; } void setPublicLength(uint32_t auxWord) { u.lengths.publicLength = auxWord; } ArrayBuffer* arrayBuffer() { return u.typedArray.buffer; } @@ -80,12 +81,7 @@ public: static IndexingHeader* from(ArrayStorage* arrayStorage) { - return const_cast<IndexingHeader*>(from(const_cast<const ArrayStorage*>(arrayStorage))); - } - - static const IndexingHeader* from(const ArrayStorage* arrayStorage) - { - return reinterpret_cast<const IndexingHeader*>(arrayStorage) - 1; + return reinterpret_cast<IndexingHeader*>(arrayStorage) - 1; } static IndexingHeader* fromEndOf(PropertyStorage propertyStorage) diff --git a/Source/JavaScriptCore/runtime/IndexingHeaderInlines.h b/Source/JavaScriptCore/runtime/IndexingHeaderInlines.h index b188741c3..cfad1c8c2 100644 --- a/Source/JavaScriptCore/runtime/IndexingHeaderInlines.h +++ b/Source/JavaScriptCore/runtime/IndexingHeaderInlines.h @@ -34,7 +34,7 @@ namespace JSC { inline size_t IndexingHeader::preCapacity(Structure* structure) { - if (LIKELY(!hasAnyArrayStorage(structure->indexingType()))) + if (LIKELY(!hasArrayStorage(structure->indexingType()))) return 0; return arrayStorage()->m_indexBias; diff --git a/Source/JavaScriptCore/runtime/IndexingType.h b/Source/JavaScriptCore/runtime/IndexingType.h index 3f9fdd1ed..66a75f8aa 100644 --- a/Source/JavaScriptCore/runtime/IndexingType.h +++ b/Source/JavaScriptCore/runtime/IndexingType.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2014 Apple Inc. All rights reserved. + * 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 @@ -31,43 +31,27 @@ namespace JSC { -/* - Structure of the IndexingType - ============================= - Conceptually, the IndexingType looks like this: - - struct IndexingType { - uint8_t isArray:1; // bit 0 - uint8_t shape:4; // bit 1 - 3 - uint8_t mayHaveIndexedAccessors:1; // bit 4 - }; - - The shape values (e.g. Int32Shape, ContiguousShape, etc) are an enumeration of - various shapes (though not necessarily sequential in terms of their values). - Hence, shape values are not bitwise exclusive with respect to each other. -*/ - typedef uint8_t IndexingType; // Flags for testing the presence of capabilities. static const IndexingType IsArray = 0x01; // The shape of the indexed property storage. -static const IndexingType IndexingShapeMask = 0x0E; +static const IndexingType IndexingShapeMask = 0x1E; static const IndexingType NoIndexingShape = 0x00; static const IndexingType UndecidedShape = 0x02; // Only useful for arrays. -static const IndexingType Int32Shape = 0x04; -static const IndexingType DoubleShape = 0x06; -static const IndexingType ContiguousShape = 0x08; -static const IndexingType ArrayStorageShape = 0x0A; -static const IndexingType SlowPutArrayStorageShape = 0x0C; +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 = 7; +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 = 0x10; +static const IndexingType MayHaveIndexedAccessors = 0x20; // List of acceptable array types. static const IndexingType NonArray = 0x0; @@ -137,14 +121,16 @@ static inline bool hasContiguous(IndexingType indexingType) return (indexingType & IndexingShapeMask) == ContiguousShape; } -static inline bool hasArrayStorage(IndexingType indexingType) +// FIXME: This is an awkward name. This should really be called hasArrayStorage() +// and then next method down should be called hasAnyArrayStorage(). +static inline bool hasFastArrayStorage(IndexingType indexingType) { return (indexingType & IndexingShapeMask) == ArrayStorageShape; } -static inline bool hasAnyArrayStorage(IndexingType indexingType) +static inline bool hasArrayStorage(IndexingType indexingType) { - return static_cast<uint8_t>(indexingType & IndexingShapeMask) >= ArrayStorageShape; + return static_cast<uint8_t>((indexingType & IndexingShapeMask) - ArrayStorageShape) <= static_cast<uint8_t>(SlowPutArrayStorageShape - ArrayStorageShape); } static inline bool shouldUseSlowPut(IndexingType indexingType) @@ -162,10 +148,10 @@ void dumpIndexingType(PrintStream&, IndexingType); MAKE_PRINT_ADAPTOR(IndexingTypeDump, IndexingType, dumpIndexingType); // Mask of all possible types. -static const IndexingType AllArrayTypes = IndexingShapeMask | IsArray; +static const IndexingType AllArrayTypes = 31; // Mask of all possible types including the history. -static const IndexingType AllArrayTypesAndHistory = AllArrayTypes | MayHaveIndexedAccessors; +static const IndexingType AllArrayTypesAndHistory = 127; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/InferredValue.cpp b/Source/JavaScriptCore/runtime/InferredValue.cpp deleted file mode 100644 index 73c6bc76b..000000000 --- a/Source/JavaScriptCore/runtime/InferredValue.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2015 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 "InferredValue.h" - -#include "JSCInlines.h" - -namespace JSC { - -const ClassInfo InferredValue::s_info = { "InferredValue", 0, 0, CREATE_METHOD_TABLE(InferredValue) }; - -InferredValue* InferredValue::create(VM& vm) -{ - InferredValue* result = new (NotNull, allocateCell<InferredValue>(vm.heap)) InferredValue(vm); - result->finishCreation(vm); - return result; -} - -void InferredValue::destroy(JSCell* cell) -{ - InferredValue* inferredValue = static_cast<InferredValue*>(cell); - inferredValue->InferredValue::~InferredValue(); -} - -Structure* InferredValue::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) -{ - return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); -} - -void InferredValue::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - InferredValue* inferredValue = jsCast<InferredValue*>(cell); - - if (inferredValue->m_set.hasBeenInvalidated()) { - inferredValue->m_cleanup = nullptr; - return; - } - - if (!inferredValue->m_value) - return; - if (!inferredValue->m_value.get().isCell()) - return; - - if (!inferredValue->m_cleanup) - inferredValue->m_cleanup = std::make_unique<ValueCleanup>(inferredValue); - visitor.addUnconditionalFinalizer(inferredValue->m_cleanup.get()); -} - -InferredValue::InferredValue(VM& vm) - : Base(vm, vm.inferredValueStructure.get()) - , m_set(ClearWatchpoint) -{ -} - -InferredValue::~InferredValue() -{ -} - -void InferredValue::notifyWriteSlow(VM& vm, JSValue value, const FireDetail& detail) -{ - ASSERT(!!value); - switch (m_set.state()) { - case ClearWatchpoint: - m_value.set(vm, this, value); - m_set.startWatching(); - return; - - case IsWatched: - ASSERT(!!m_value); - if (m_value.get() == value) - return; - invalidate(detail); - return; - - case IsInvalidated: - ASSERT_NOT_REACHED(); - return; - } - - ASSERT_NOT_REACHED(); -} - -void InferredValue::notifyWriteSlow(VM& vm, JSValue value, const char* reason) -{ - notifyWriteSlow(vm, value, StringFireDetail(reason)); -} - -InferredValue::ValueCleanup::ValueCleanup(InferredValue* owner) - : m_owner(owner) -{ -} - -InferredValue::ValueCleanup::~ValueCleanup() -{ -} - -void InferredValue::ValueCleanup::finalizeUnconditionally() -{ - ASSERT(m_owner->m_value); - ASSERT(m_owner->m_value.get().isCell()); - - if (Heap::isMarked(m_owner->m_value.get().asCell())) - return; - - m_owner->invalidate(StringFireDetail("InferredValue clean-up during GC")); -} - -} // namespace JSC - diff --git a/Source/JavaScriptCore/runtime/InferredValue.h b/Source/JavaScriptCore/runtime/InferredValue.h deleted file mode 100644 index 28318e992..000000000 --- a/Source/JavaScriptCore/runtime/InferredValue.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2015 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 InferredValue_h -#define InferredValue_h - -#include "JSCell.h" -#include "Watchpoint.h" -#include "WriteBarrier.h" - -namespace JSC { - -// Allocate one of these if you'd like to infer a constant value. Writes to the value should use -// notifyWrite(). So long as exactly one value had ever been written and invalidate() has never been -// called, and you register a watchpoint, you can rely on the inferredValue() being the one true -// value. -// -// Commonly used for inferring singletons - in that case each allocation does notifyWrite(). But you -// can use it for other things as well. - -class InferredValue : public JSCell { -public: - typedef JSCell Base; - - static InferredValue* create(VM&); - - static const bool needsDestruction = true; - static void destroy(JSCell*); - - static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype); - - static void visitChildren(JSCell*, SlotVisitor&); - - DECLARE_INFO; - - // For the purpose of deciding whether or not to watch this variable, you only need - // to inspect inferredValue(). If this returns something other than the empty - // value, then it means that at all future safepoints, this watchpoint set will be - // in one of these states: - // - // IsWatched: in this case, the variable's value must still be the - // inferredValue. - // - // IsInvalidated: in this case the variable's value may be anything but you'll - // either notice that it's invalidated and not install the watchpoint, or - // you will have been notified that the watchpoint was fired. - JSValue inferredValue() { return m_value.get(); } - - // Forwards some WatchpointSet methods. - WatchpointState state() const { return m_set.state(); } - bool isStillValid() const { return m_set.isStillValid(); } - bool hasBeenInvalidated() const { return m_set.hasBeenInvalidated(); } - void add(Watchpoint* watchpoint) { m_set.add(watchpoint); } - - void notifyWrite(VM& vm, JSValue value, const FireDetail& detail) - { - if (LIKELY(m_set.stateOnJSThread() == IsInvalidated)) - return; - notifyWriteSlow(vm, value, detail); - } - - void notifyWrite(VM& vm, JSValue value, const char* reason) - { - if (LIKELY(m_set.stateOnJSThread() == IsInvalidated)) - return; - notifyWriteSlow(vm, value, reason); - } - - void invalidate(const FireDetail& detail) - { - m_value.clear(); - m_set.invalidate(detail); - } - - static const unsigned StructureFlags = StructureIsImmortal | Base::StructureFlags; - - // We could have used Weak<>. But we want arbitrary JSValues, not just cells. It's also somewhat - // convenient to have eager notification of death. - // - // Also note that this should be a private class, but it isn't because Windows. - class ValueCleanup : public UnconditionalFinalizer { - WTF_MAKE_FAST_ALLOCATED; - - public: - ValueCleanup(InferredValue*); - virtual ~ValueCleanup(); - - protected: - void finalizeUnconditionally() override; - - private: - InferredValue* m_owner; - }; - -private: - InferredValue(VM&); - ~InferredValue(); - - JS_EXPORT_PRIVATE void notifyWriteSlow(VM&, JSValue, const FireDetail&); - JS_EXPORT_PRIVATE void notifyWriteSlow(VM&, JSValue, const char* reason); - - friend class ValueCleanup; - - InlineWatchpointSet m_set; - WriteBarrier<Unknown> m_value; - std::unique_ptr<ValueCleanup> m_cleanup; -}; - -// FIXME: We could have an InlineInferredValue, which only allocates the InferredValue object when -// a notifyWrite() transitions us towards watching, and then clears the reference (allowing the object -// to die) when we get invalidated. - -} // namespace JSC - -#endif // InferredValue_h - diff --git a/Source/JavaScriptCore/runtime/InitializeThreading.cpp b/Source/JavaScriptCore/runtime/InitializeThreading.cpp index d74460f20..1cb5e7abf 100644 --- a/Source/JavaScriptCore/runtime/InitializeThreading.cpp +++ b/Source/JavaScriptCore/runtime/InitializeThreading.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2015 Apple Inc. All rights reserved. + * 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 @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -38,7 +38,6 @@ #include "JSGlobalObject.h" #include "JSLock.h" #include "LLIntData.h" -#include "StructureIDTable.h" #include "WriteBarrier.h" #include <mutex> #include <wtf/dtoa.h> @@ -56,6 +55,7 @@ void initializeThreading() std::call_once(initializeThreadingOnceFlag, []{ WTF::double_conversion::initialize(); WTF::initializeThreading(); + GlobalJSLock::initialize(); Options::initialize(); if (Options::recordGCPauseTimes()) HeapStatistics::initialize(); @@ -65,12 +65,13 @@ void initializeThreading() #if ENABLE(ASSEMBLER) ExecutableAllocator::initializeAllocator(); #endif + JSStack::initializeThreading(); +#if ENABLE(LLINT) LLInt::initialize(); +#endif #ifndef NDEBUG DisallowGC::initialize(); #endif - WTFThreadData& threadData = wtfThreadData(); - threadData.setSavedLastStackTop(threadData.stack().origin()); }); } diff --git a/Source/JavaScriptCore/runtime/InitializeThreading.h b/Source/JavaScriptCore/runtime/InitializeThreading.h index 39845c243..91301a0d8 100644 --- a/Source/JavaScriptCore/runtime/InitializeThreading.h +++ b/Source/JavaScriptCore/runtime/InitializeThreading.h @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -31,9 +31,9 @@ namespace JSC { -// This function must be called from the main thread. It is safe to call it repeatedly. -// Darwin is an exception to this rule: it is OK to call this function from any thread, even reentrantly. -JS_EXPORT_PRIVATE void initializeThreading(); + // This function must be called from the main thread. It is safe to call it repeatedly. + // Darwin is an exception to this rule: it is OK to call this function from any thread, even reentrantly. + JS_EXPORT_PRIVATE void initializeThreading(); } diff --git a/Source/JavaScriptCore/runtime/IntegralTypedArrayBase.h b/Source/JavaScriptCore/runtime/IntegralTypedArrayBase.h index 466ff8cde..99c989ec7 100644 --- a/Source/JavaScriptCore/runtime/IntegralTypedArrayBase.h +++ b/Source/JavaScriptCore/runtime/IntegralTypedArrayBase.h @@ -11,10 +11,10 @@ * 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 + * 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 INC. OR + * 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 diff --git a/Source/JavaScriptCore/runtime/IntendedStructureChain.cpp b/Source/JavaScriptCore/runtime/IntendedStructureChain.cpp new file mode 100644 index 000000000..b38dae9f8 --- /dev/null +++ b/Source/JavaScriptCore/runtime/IntendedStructureChain.cpp @@ -0,0 +1,141 @@ +/* + * 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 "IntendedStructureChain.h" + +#include "CodeBlock.h" +#include "Operations.h" +#include "StructureChain.h" + +namespace JSC { + +IntendedStructureChain::IntendedStructureChain(JSGlobalObject* globalObject, Structure* head) + : m_globalObject(globalObject) + , m_head(head) +{ + JSValue prototype = head->prototypeForLookup(globalObject); + if (prototype.isNull()) + return; + for (Structure* current = asObject(prototype)->structure(); current; current = current->storedPrototypeStructure()) + m_vector.append(current); +} + +IntendedStructureChain::IntendedStructureChain(CodeBlock* codeBlock, Structure* head, Structure* prototypeStructure) + : m_globalObject(codeBlock->globalObject()) + , m_head(head) +{ + m_vector.append(prototypeStructure); +} + +IntendedStructureChain::IntendedStructureChain(CodeBlock* codeBlock, Structure* head, StructureChain* chain) + : m_globalObject(codeBlock->globalObject()) + , m_head(head) +{ + for (unsigned i = 0; chain->head()[i]; ++i) + m_vector.append(chain->head()[i].get()); +} + +IntendedStructureChain::IntendedStructureChain(CodeBlock* codeBlock, Structure* head, StructureChain* chain, unsigned count) + : m_globalObject(codeBlock->globalObject()) + , m_head(head) +{ + for (unsigned i = 0; i < count; ++i) + m_vector.append(chain->head()[i].get()); +} + +IntendedStructureChain::~IntendedStructureChain() +{ +} + +bool IntendedStructureChain::isStillValid() const +{ + JSValue currentPrototype = m_head->prototypeForLookup(m_globalObject); + for (unsigned i = 0; i < m_vector.size(); ++i) { + if (asObject(currentPrototype)->structure() != m_vector[i]) + return false; + currentPrototype = m_vector[i]->storedPrototype(); + } + return true; +} + +bool IntendedStructureChain::matches(StructureChain* chain) const +{ + for (unsigned i = 0; i < m_vector.size(); ++i) { + if (m_vector[i] != chain->head()[i].get()) + return false; + } + if (chain->head()[m_vector.size()]) + return false; + return true; +} + +StructureChain* IntendedStructureChain::chain(VM& vm) const +{ + ASSERT(isStillValid()); + StructureChain* result = StructureChain::create(vm, m_head); + ASSERT(matches(result)); + return result; +} + +bool IntendedStructureChain::mayInterceptStoreTo(VM& vm, StringImpl* uid) +{ + for (unsigned i = 0; i < m_vector.size(); ++i) { + unsigned attributes; + JSCell* specificValue; + PropertyOffset offset = m_vector[i]->getConcurrently(vm, uid, attributes, specificValue); + if (!isValidOffset(offset)) + continue; + if (attributes & (ReadOnly | Accessor)) + return true; + return false; + } + return false; +} + +bool IntendedStructureChain::isNormalized() +{ + if (m_head->typeInfo().type() == ProxyType) + return false; + for (unsigned i = 0; i < m_vector.size(); ++i) { + Structure* structure = m_vector[i]; + if (structure->typeInfo().type() == ProxyType) + return false; + if (structure->isDictionary()) + return false; + } + return true; +} + +JSObject* IntendedStructureChain::terminalPrototype() const +{ + ASSERT(!m_vector.isEmpty()); + if (m_vector.size() == 1) + return asObject(m_head->prototypeForLookup(m_globalObject)); + return asObject(m_vector[m_vector.size() - 2]->storedPrototype()); +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/runtime/IntendedStructureChain.h b/Source/JavaScriptCore/runtime/IntendedStructureChain.h new file mode 100644 index 000000000..40af95c65 --- /dev/null +++ b/Source/JavaScriptCore/runtime/IntendedStructureChain.h @@ -0,0 +1,70 @@ +/* + * 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 IntendedStructureChain_h +#define IntendedStructureChain_h + +#include "Structure.h" +#include <wtf/RefCounted.h> + +namespace JSC { + +class CodeBlock; +class JSGlobalObject; +class StructureChain; +class VM; + +class IntendedStructureChain : public RefCounted<IntendedStructureChain> { +public: + IntendedStructureChain(JSGlobalObject* globalObject, Structure* head); + IntendedStructureChain(CodeBlock* codeBlock, Structure* head, Structure* prototypeStructure); + IntendedStructureChain(CodeBlock* codeBlock, Structure* head, StructureChain* chain); + IntendedStructureChain(CodeBlock* codeBlock, Structure* head, StructureChain* chain, unsigned count); + ~IntendedStructureChain(); + + bool isStillValid() const; + bool matches(StructureChain*) const; + StructureChain* chain(VM&) const; + bool mayInterceptStoreTo(VM&, StringImpl* uid); + bool isNormalized(); + + Structure* head() const { return m_head; } + + size_t size() const { return m_vector.size(); } + Structure* at(size_t index) { return m_vector[index]; } + Structure* operator[](size_t index) { return at(index); } + + JSObject* terminalPrototype() const; + + Structure* last() const { return m_vector.last(); } +private: + JSGlobalObject* m_globalObject; + Structure* m_head; + Vector<Structure*> m_vector; +}; + +} // namespace JSC + +#endif // IntendedStructureChain_h diff --git a/Source/JavaScriptCore/runtime/InternalFunction.cpp b/Source/JavaScriptCore/runtime/InternalFunction.cpp index 6f53bc01f..69120bea5 100644 --- a/Source/JavaScriptCore/runtime/InternalFunction.cpp +++ b/Source/JavaScriptCore/runtime/InternalFunction.cpp @@ -26,13 +26,13 @@ #include "FunctionPrototype.h" #include "JSGlobalObject.h" #include "JSString.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(InternalFunction); -const ClassInfo InternalFunction::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(InternalFunction) }; +const ClassInfo InternalFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(InternalFunction) }; InternalFunction::InternalFunction(VM& vm, Structure* structure) : JSDestructibleObject(vm, structure) diff --git a/Source/JavaScriptCore/runtime/InternalFunction.h b/Source/JavaScriptCore/runtime/InternalFunction.h index 8b0d09f13..e216c2f82 100644 --- a/Source/JavaScriptCore/runtime/InternalFunction.h +++ b/Source/JavaScriptCore/runtime/InternalFunction.h @@ -29,39 +29,40 @@ namespace JSC { -class FunctionPrototype; + class FunctionPrototype; -class InternalFunction : public JSDestructibleObject { -public: - typedef JSDestructibleObject Base; - static const unsigned StructureFlags = Base::StructureFlags | ImplementsHasInstance | TypeOfShouldCallGetCallData; + class InternalFunction : public JSDestructibleObject { + public: + typedef JSDestructibleObject Base; - DECLARE_EXPORT_INFO; + DECLARE_EXPORT_INFO; - JS_EXPORT_PRIVATE const String& name(ExecState*); - const String displayName(ExecState*); - const String calculatedDisplayName(ExecState*); + JS_EXPORT_PRIVATE const String& name(ExecState*); + const String displayName(ExecState*); + const String calculatedDisplayName(ExecState*); - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) - { - return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info()); - } + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) + { + return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info()); + } + + protected: + static const unsigned StructureFlags = ImplementsHasInstance | JSObject::StructureFlags; -protected: - JS_EXPORT_PRIVATE InternalFunction(VM&, Structure*); + JS_EXPORT_PRIVATE InternalFunction(VM&, Structure*); - JS_EXPORT_PRIVATE void finishCreation(VM&, const String& name); + JS_EXPORT_PRIVATE void finishCreation(VM&, const String& name); - static CallType getCallData(JSCell*, CallData&); -}; + static CallType getCallData(JSCell*, CallData&); + }; -InternalFunction* asInternalFunction(JSValue); + InternalFunction* asInternalFunction(JSValue); -inline InternalFunction* asInternalFunction(JSValue value) -{ - ASSERT(asObject(value)->inherits(InternalFunction::info())); - return static_cast<InternalFunction*>(asObject(value)); -} + inline InternalFunction* asInternalFunction(JSValue value) + { + ASSERT(asObject(value)->inherits(InternalFunction::info())); + return static_cast<InternalFunction*>(asObject(value)); + } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/IntlCollator.cpp b/Source/JavaScriptCore/runtime/IntlCollator.cpp deleted file mode 100644 index 98108fc18..000000000 --- a/Source/JavaScriptCore/runtime/IntlCollator.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com) - * - * 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 "IntlCollator.h" - -#if ENABLE(INTL) - -#include "Error.h" -#include "IntlCollatorConstructor.h" -#include "IntlObject.h" -#include "JSBoundFunction.h" -#include "JSCJSValueInlines.h" -#include "JSCellInlines.h" -#include "SlotVisitorInlines.h" -#include "StructureInlines.h" - -namespace JSC { - -const ClassInfo IntlCollator::s_info = { "Object", &Base::s_info, 0, CREATE_METHOD_TABLE(IntlCollator) }; - -IntlCollator* IntlCollator::create(VM& vm, IntlCollatorConstructor* constructor) -{ - IntlCollator* format = new (NotNull, allocateCell<IntlCollator>(vm.heap)) IntlCollator(vm, constructor->collatorStructure()); - format->finishCreation(vm); - return format; -} - -Structure* IntlCollator::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) -{ - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); -} - -IntlCollator::IntlCollator(VM& vm, Structure* structure) - : JSDestructibleObject(vm, structure) -{ -} - -void IntlCollator::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); -} - -void IntlCollator::destroy(JSCell* cell) -{ - static_cast<IntlCollator*>(cell)->IntlCollator::~IntlCollator(); -} - -void IntlCollator::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - IntlCollator* thisObject = jsCast<IntlCollator*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - - Base::visitChildren(thisObject, visitor); - - visitor.append(&thisObject->m_boundCompare); -} - -void IntlCollator::setBoundCompare(VM& vm, JSBoundFunction* format) -{ - m_boundCompare.set(vm, this, format); -} - -EncodedJSValue JSC_HOST_CALL IntlCollatorFuncCompare(ExecState* exec) -{ - // 10.3.4 Collator Compare Functions (ECMA-402 2.0) - // 1. Let collator be the this value. - IntlCollator* collator = jsDynamicCast<IntlCollator*>(exec->thisValue()); - - // 2. Assert: Type(collator) is Object and collator has an [[initializedCollator]] internal slot whose value is true. - if (!collator) - return JSValue::encode(throwTypeError(exec)); - - // 3. If x is not provided, let x be undefined. - // 4. If y is not provided, let y be undefined. - // 5. Let X be ToString(x). - JSString* a = exec->argument(0).toString(exec); - // 6. ReturnIfAbrupt(X). - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - // 7. Let Y be ToString(y). - JSString* b = exec->argument(1).toString(exec); - // 8. ReturnIfAbrupt(Y). - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - // 9. Return CompareStrings(collator, X, Y). - - // 10.3.4 CompareStrings abstract operation (ECMA-402 2.0) - // FIXME: Implement CompareStrings. - - // Return simple check until properly implemented. - return JSValue::encode(jsNumber(codePointCompare(a->value(exec).impl(), b->value(exec).impl()))); -} - -} // namespace JSC - -#endif // ENABLE(INTL) diff --git a/Source/JavaScriptCore/runtime/IntlCollator.h b/Source/JavaScriptCore/runtime/IntlCollator.h deleted file mode 100644 index ff2251494..000000000 --- a/Source/JavaScriptCore/runtime/IntlCollator.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com) - * - * 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 IntlCollator_h -#define IntlCollator_h - -#if ENABLE(INTL) - -#include "JSDestructibleObject.h" - -namespace JSC { - -class IntlCollatorConstructor; -class JSBoundFunction; - -class IntlCollator : public JSDestructibleObject { -public: - typedef JSDestructibleObject Base; - - static IntlCollator* create(VM&, IntlCollatorConstructor*); - static Structure* createStructure(VM&, JSGlobalObject*, JSValue); - - DECLARE_INFO; - - JSBoundFunction* boundCompare() const { return m_boundCompare.get(); } - void setBoundCompare(VM&, JSBoundFunction*); - -protected: - IntlCollator(VM&, Structure*); - void finishCreation(VM&); - static void destroy(JSCell*); - static void visitChildren(JSCell*, SlotVisitor&); - -private: - WriteBarrier<JSBoundFunction> m_boundCompare; -}; - -EncodedJSValue JSC_HOST_CALL IntlCollatorFuncCompare(ExecState*); - -} // namespace JSC - -#endif // ENABLE(INTL) - -#endif // IntlCollator_h diff --git a/Source/JavaScriptCore/runtime/IntlCollatorConstructor.cpp b/Source/JavaScriptCore/runtime/IntlCollatorConstructor.cpp deleted file mode 100644 index d41dd17cd..000000000 --- a/Source/JavaScriptCore/runtime/IntlCollatorConstructor.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com) - * - * 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 "IntlCollatorConstructor.h" - -#if ENABLE(INTL) - -#include "Error.h" -#include "IntlCollator.h" -#include "IntlCollatorPrototype.h" -#include "IntlObject.h" -#include "JSCJSValueInlines.h" -#include "JSCellInlines.h" -#include "Lookup.h" -#include "SlotVisitorInlines.h" -#include "StructureInlines.h" - -namespace JSC { - -STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(IntlCollatorConstructor); - -static EncodedJSValue JSC_HOST_CALL IntlCollatorConstructorFuncSupportedLocalesOf(ExecState*); - -} - -#include "IntlCollatorConstructor.lut.h" - -namespace JSC { - -const ClassInfo IntlCollatorConstructor::s_info = { "Function", &InternalFunction::s_info, &collatorConstructorTable, CREATE_METHOD_TABLE(IntlCollatorConstructor) }; - -/* Source for IntlCollatorConstructor.lut.h -@begin collatorConstructorTable - supportedLocalesOf IntlCollatorConstructorFuncSupportedLocalesOf DontEnum|Function 1 -@end -*/ - -IntlCollatorConstructor* IntlCollatorConstructor::create(VM& vm, Structure* structure, IntlCollatorPrototype* collatorPrototype, Structure* collatorStructure) -{ - IntlCollatorConstructor* constructor = new (NotNull, allocateCell<IntlCollatorConstructor>(vm.heap)) IntlCollatorConstructor(vm, structure); - constructor->finishCreation(vm, collatorPrototype, collatorStructure); - return constructor; -} - -Structure* IntlCollatorConstructor::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) -{ - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); -} - -IntlCollatorConstructor::IntlCollatorConstructor(VM& vm, Structure* structure) - : InternalFunction(vm, structure) -{ -} - -void IntlCollatorConstructor::finishCreation(VM& vm, IntlCollatorPrototype* collatorPrototype, Structure* collatorStructure) -{ - Base::finishCreation(vm, ASCIILiteral("Collator")); - putDirectWithoutTransition(vm, vm.propertyNames->prototype, collatorPrototype, DontEnum | DontDelete | ReadOnly); - putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), ReadOnly | DontEnum | DontDelete); - m_collatorStructure.set(vm, this, collatorStructure); -} - -EncodedJSValue JSC_HOST_CALL constructIntlCollator(ExecState* exec) -{ - // 10.1.2 Intl.Collator ([locales [, options]]) (ECMA-402 2.0) - // 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget. - JSValue newTarget = exec->newTarget(); - if (!newTarget || newTarget.isUndefined()) - newTarget = exec->callee(); - - // 2. Let collator be OrdinaryCreateFromConstructor(newTarget, %CollatorPrototype%). - VM& vm = exec->vm(); - IntlCollator* collator = IntlCollator::create(vm, jsCast<IntlCollatorConstructor*>(exec->callee())); - if (collator && !jsDynamicCast<IntlCollatorConstructor*>(newTarget)) { - JSValue proto = asObject(newTarget)->getDirect(vm, vm.propertyNames->prototype); - asObject(collator)->setPrototypeWithCycleCheck(exec, proto); - } - - // 3. ReturnIfAbrupt(collator). - ASSERT(collator); - - // 4. Return InitializeCollator(collator, locales, options). - // FIXME: return JSValue::encode(InitializeCollator(collator, locales, options)); - - return JSValue::encode(collator); -} - -EncodedJSValue JSC_HOST_CALL callIntlCollator(ExecState* exec) -{ - // 10.1.2 Intl.Collator ([locales [, options]]) (ECMA-402 2.0) - // 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget. - // NewTarget is always undefined when called as a function. - - // 2. Let collator be OrdinaryCreateFromConstructor(newTarget, %CollatorPrototype%). - VM& vm = exec->vm(); - IntlCollator* collator = IntlCollator::create(vm, jsCast<IntlCollatorConstructor*>(exec->callee())); - - // 3. ReturnIfAbrupt(collator). - ASSERT(collator); - - // 4. Return InitializeCollator(collator, locales, options). - // FIXME: return JSValue::encode(InitializeCollator(collator, locales, options)); - - return JSValue::encode(collator); -} - -ConstructType IntlCollatorConstructor::getConstructData(JSCell*, ConstructData& constructData) -{ - constructData.native.function = constructIntlCollator; - return ConstructTypeHost; -} - -CallType IntlCollatorConstructor::getCallData(JSCell*, CallData& callData) -{ - callData.native.function = callIntlCollator; - return CallTypeHost; -} - -bool IntlCollatorConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) -{ - return getStaticFunctionSlot<InternalFunction>(exec, collatorConstructorTable, jsCast<IntlCollatorConstructor*>(object), propertyName, slot); -} - -EncodedJSValue JSC_HOST_CALL IntlCollatorConstructorFuncSupportedLocalesOf(ExecState* exec) -{ - // 10.2.2 Intl.Collator.supportedLocalesOf(locales [, options]) (ECMA-402 2.0) - - // 1. Let requestedLocales be CanonicalizeLocaleList(locales). - // FIXME: requested = CanonicalizeLocaleList(locales); - - // 2. ReturnIfAbrupt(requestedLocales). - // if (exec->hadException()) - // return JSValue::encode(jsUndefined()); - - // 3. Return SupportedLocales(%Collator%.[[availableLocales]], requestedLocales, options). - // FIXME: return JSValue::encode(SupportedLocales(available, requested, options)); - - // Return empty array until properly implemented. - VM& vm = exec->vm(); - JSGlobalObject* globalObject = exec->callee()->globalObject(); - JSArray* supportedLocales = JSArray::tryCreateUninitialized(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), 0); - if (!supportedLocales) - return JSValue::encode(throwOutOfMemoryError(exec)); - - return JSValue::encode(supportedLocales); -} - -void IntlCollatorConstructor::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - IntlCollatorConstructor* thisObject = jsCast<IntlCollatorConstructor*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - - Base::visitChildren(thisObject, visitor); - - visitor.append(&thisObject->m_collatorStructure); -} - -} // namespace JSC - -#endif // ENABLE(INTL) diff --git a/Source/JavaScriptCore/runtime/IntlCollatorConstructor.h b/Source/JavaScriptCore/runtime/IntlCollatorConstructor.h deleted file mode 100644 index 4aa98f2fa..000000000 --- a/Source/JavaScriptCore/runtime/IntlCollatorConstructor.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com) - * - * 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 IntlCollatorConstructor_h -#define IntlCollatorConstructor_h - -#if ENABLE(INTL) - -#include "InternalFunction.h" - -namespace JSC { - -class IntlCollator; -class IntlCollatorPrototype; - -class IntlCollatorConstructor : public InternalFunction { -public: - typedef InternalFunction Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; - - static IntlCollatorConstructor* create(VM&, Structure*, IntlCollatorPrototype*, Structure*); - static Structure* createStructure(VM&, JSGlobalObject*, JSValue); - - DECLARE_INFO; - - Structure* collatorStructure() const { return m_collatorStructure.get(); } - -protected: - void finishCreation(VM&, IntlCollatorPrototype*, Structure*); - -private: - IntlCollatorConstructor(VM&, Structure*); - static ConstructType getConstructData(JSCell*, ConstructData&); - static CallType getCallData(JSCell*, CallData&); - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); - static void visitChildren(JSCell*, SlotVisitor&); - - WriteBarrier<Structure> m_collatorStructure; -}; - -EncodedJSValue JSC_HOST_CALL constructIntlCollator(ExecState*); -EncodedJSValue JSC_HOST_CALL callIntlCollator(ExecState*); - -} // namespace JSC - -#endif // ENABLE(INTL) - -#endif // IntlCollatorConstructor_h diff --git a/Source/JavaScriptCore/runtime/IntlCollatorPrototype.cpp b/Source/JavaScriptCore/runtime/IntlCollatorPrototype.cpp deleted file mode 100644 index d46ddbfc8..000000000 --- a/Source/JavaScriptCore/runtime/IntlCollatorPrototype.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com) - * - * 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 "IntlCollatorPrototype.h" - -#if ENABLE(INTL) - -#include "Error.h" -#include "IntlCollator.h" -#include "JSBoundFunction.h" -#include "JSCJSValueInlines.h" -#include "JSCellInlines.h" -#include "JSObject.h" -#include "ObjectConstructor.h" -#include "StructureInlines.h" - -namespace JSC { - -STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(IntlCollatorPrototype); - -static EncodedJSValue JSC_HOST_CALL IntlCollatorPrototypeGetterCompare(ExecState*); -static EncodedJSValue JSC_HOST_CALL IntlCollatorPrototypeFuncResolvedOptions(ExecState*); - -} - -#include "IntlCollatorPrototype.lut.h" - -namespace JSC { - -const ClassInfo IntlCollatorPrototype::s_info = { "Object", &IntlCollator::s_info, &collatorPrototypeTable, CREATE_METHOD_TABLE(IntlCollatorPrototype) }; - -/* Source for IntlCollatorPrototype.lut.h -@begin collatorPrototypeTable - compare IntlCollatorPrototypeGetterCompare DontEnum|Accessor - resolvedOptions IntlCollatorPrototypeFuncResolvedOptions DontEnum|Function 0 -@end -*/ - -IntlCollatorPrototype* IntlCollatorPrototype::create(VM& vm, JSGlobalObject*, Structure* structure) -{ - IntlCollatorPrototype* object = new (NotNull, allocateCell<IntlCollatorPrototype>(vm.heap)) IntlCollatorPrototype(vm, structure); - object->finishCreation(vm); - return object; -} - -Structure* IntlCollatorPrototype::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) -{ - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); -} - -IntlCollatorPrototype::IntlCollatorPrototype(VM& vm, Structure* structure) - : IntlCollator(vm, structure) -{ -} - -void IntlCollatorPrototype::finishCreation(VM& vm) -{ - Base::finishCreation(vm); -} - -bool IntlCollatorPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) -{ - return getStaticFunctionSlot<JSObject>(exec, collatorPrototypeTable, jsCast<IntlCollatorPrototype*>(object), propertyName, slot); -} - -EncodedJSValue JSC_HOST_CALL IntlCollatorPrototypeGetterCompare(ExecState* exec) -{ - // 10.3.3 Intl.Collator.prototype.compare (ECMA-402 2.0) - // 1. Let collator be this Collator object. - IntlCollator* collator = jsDynamicCast<IntlCollator*>(exec->thisValue()); - if (!collator) - return JSValue::encode(throwTypeError(exec, ASCIILiteral("Intl.Collator.prototype.compare called on value that's not an object initialized as a Collator"))); - - JSBoundFunction* boundCompare = collator->boundCompare(); - // 2. If collator.[[boundCompare]] is undefined, - if (!boundCompare) { - VM& vm = exec->vm(); - JSGlobalObject* globalObject = collator->globalObject(); - // a. Let F be a new built-in function object as defined in 11.3.4. - // b. The value of F’s length property is 2. - JSFunction* targetObject = JSFunction::create(vm, globalObject, 2, ASCIILiteral("compare"), IntlCollatorFuncCompare, NoIntrinsic); - JSArray* boundArgs = JSArray::tryCreateUninitialized(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), 0); - if (!boundArgs) - return JSValue::encode(throwOutOfMemoryError(exec)); - - // c. Let bc be BoundFunctionCreate(F, «this value»). - boundCompare = JSBoundFunction::create(vm, globalObject, targetObject, collator, boundArgs, 2, ASCIILiteral("compare")); - // d. Set collator.[[boundCompare]] to bc. - collator->setBoundCompare(vm, boundCompare); - } - // 3. Return collator.[[boundCompare]]. - return JSValue::encode(boundCompare); -} - -EncodedJSValue JSC_HOST_CALL IntlCollatorPrototypeFuncResolvedOptions(ExecState* exec) -{ - // 10.3.5 Intl.Collator.prototype.resolvedOptions() (ECMA-402 2.0) - IntlCollator* collator = jsDynamicCast<IntlCollator*>(exec->thisValue()); - if (!collator) - return JSValue::encode(throwTypeError(exec, ASCIILiteral("Intl.Collator.prototype.resolvedOptions called on value that's not an object initialized as a Collator"))); - - // The function returns a new object whose properties and attributes are set as if constructed by an object literal assigning to each of the following properties the value of the corresponding internal slot of this Collator object (see 10.4): locale, usage, sensitivity, ignorePunctuation, collation, as well as those properties shown in Table 1 whose keys are included in the %Collator%[[relevantExtensionKeys]] internal slot of the standard built-in object that is the initial value of Intl.Collator. - - JSObject* options = constructEmptyObject(exec); - - // FIXME: Populate object from internal slots. - - return JSValue::encode(options); -} - -} // namespace JSC - -#endif // ENABLE(INTL) diff --git a/Source/JavaScriptCore/runtime/IntlCollatorPrototype.h b/Source/JavaScriptCore/runtime/IntlCollatorPrototype.h deleted file mode 100644 index f81642679..000000000 --- a/Source/JavaScriptCore/runtime/IntlCollatorPrototype.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com) - * - * 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 IntlCollatorPrototype_h -#define IntlCollatorPrototype_h - -#if ENABLE(INTL) - -#include "IntlCollator.h" -#include "JSObject.h" - -namespace JSC { - -class IntlCollatorPrototype : public IntlCollator { -public: - typedef IntlCollator Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; - - static IntlCollatorPrototype* create(VM&, JSGlobalObject*, Structure*); - static Structure* createStructure(VM&, JSGlobalObject*, JSValue); - - DECLARE_INFO; - -protected: - void finishCreation(VM&); - -private: - IntlCollatorPrototype(VM&, Structure*); - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); -}; - -} // namespace JSC - -#endif // ENABLE(INTL) - -#endif // IntlCollatorPrototype_h diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp deleted file mode 100644 index 7839badc3..000000000 --- a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com) - * - * 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 "IntlDateTimeFormat.h" - -#if ENABLE(INTL) - -#include "DateConstructor.h" -#include "DateInstance.h" -#include "Error.h" -#include "IntlDateTimeFormatConstructor.h" -#include "IntlObject.h" -#include "JSBoundFunction.h" -#include "JSCJSValueInlines.h" -#include "JSCellInlines.h" -#include "SlotVisitorInlines.h" -#include "StructureInlines.h" - -namespace JSC { - -const ClassInfo IntlDateTimeFormat::s_info = { "Object", &Base::s_info, 0, CREATE_METHOD_TABLE(IntlDateTimeFormat) }; - -IntlDateTimeFormat* IntlDateTimeFormat::create(VM& vm, IntlDateTimeFormatConstructor* constructor) -{ - IntlDateTimeFormat* format = new (NotNull, allocateCell<IntlDateTimeFormat>(vm.heap)) IntlDateTimeFormat(vm, constructor->dateTimeFormatStructure()); - format->finishCreation(vm); - return format; -} - -Structure* IntlDateTimeFormat::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) -{ - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); -} - -IntlDateTimeFormat::IntlDateTimeFormat(VM& vm, Structure* structure) - : JSDestructibleObject(vm, structure) -{ -} - -void IntlDateTimeFormat::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); -} - -void IntlDateTimeFormat::destroy(JSCell* cell) -{ - static_cast<IntlDateTimeFormat*>(cell)->IntlDateTimeFormat::~IntlDateTimeFormat(); -} - -void IntlDateTimeFormat::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - IntlDateTimeFormat* thisObject = jsCast<IntlDateTimeFormat*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - - Base::visitChildren(thisObject, visitor); - - visitor.append(&thisObject->m_boundFormat); -} - -void IntlDateTimeFormat::setBoundFormat(VM& vm, JSBoundFunction* format) -{ - m_boundFormat.set(vm, this, format); -} - -EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatFuncFormatDateTime(ExecState* exec) -{ - // 12.3.4 DateTime Format Functions (ECMA-402 2.0) - // 1. Let dtf be the this value. - IntlDateTimeFormat* format = jsDynamicCast<IntlDateTimeFormat*>(exec->thisValue()); - // 2. Assert: Type(dtf) is Object and dtf has an [[initializedDateTimeFormat]] internal slot whose value is true. - if (!format) - return JSValue::encode(throwTypeError(exec)); - - JSValue date = exec->argument(0); - double value; - - // 3. If date is not provided or is undefined, then - if (date.isUndefined()) { - // a. Let x be %Date_now%(). - value = JSValue::decode(dateNow(exec)).toNumber(exec); - } else { - // 4. Else - // a. Let x be ToNumber(date). - value = date.toNumber(exec); - // b. ReturnIfAbrupt(x). - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - } - - // 5. Return FormatDateTime(dtf, x). - - // 12.3.4 FormatDateTime abstract operation (ECMA-402 2.0) - - // 1. If x is not a finite Number, then throw a RangeError exception. - if (!std::isfinite(value)) - return JSValue::encode(throwRangeError(exec, ASCIILiteral("date value is not finite in DateTimeFormat.format()"))); - - // FIXME: implement 2 - 9 - - // Return new Date(value).toString() until properly implemented. - VM& vm = exec->vm(); - JSGlobalObject* globalObject = exec->callee()->globalObject(); - DateInstance* d = DateInstance::create(vm, globalObject->dateStructure(), value); - return JSValue::encode(JSValue(d).toString(exec)); -} - -} // namespace JSC - -#endif // ENABLE(INTL) diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h deleted file mode 100644 index 7daed138f..000000000 --- a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com) - * - * 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 IntlDateTimeFormat_h -#define IntlDateTimeFormat_h - -#if ENABLE(INTL) - -#include "JSDestructibleObject.h" - -namespace JSC { - -class IntlDateTimeFormatConstructor; -class JSBoundFunction; - -class IntlDateTimeFormat : public JSDestructibleObject { -public: - typedef JSDestructibleObject Base; - - static IntlDateTimeFormat* create(VM&, IntlDateTimeFormatConstructor*); - static Structure* createStructure(VM&, JSGlobalObject*, JSValue); - - DECLARE_INFO; - - JSBoundFunction* boundFormat() const { return m_boundFormat.get(); } - void setBoundFormat(VM&, JSBoundFunction*); - -protected: - IntlDateTimeFormat(VM&, Structure*); - void finishCreation(VM&); - static void destroy(JSCell*); - static void visitChildren(JSCell*, SlotVisitor&); - - WriteBarrier<JSBoundFunction> m_boundFormat; -}; - -EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatFuncFormatDateTime(ExecState*); - -} // namespace JSC - -#endif // ENABLE(INTL) - -#endif // IntlDateTimeFormat_h diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.cpp b/Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.cpp deleted file mode 100644 index 0b8d460d2..000000000 --- a/Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com) - * - * 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 "IntlDateTimeFormatConstructor.h" - -#if ENABLE(INTL) - -#include "Error.h" -#include "IntlDateTimeFormat.h" -#include "IntlDateTimeFormatPrototype.h" -#include "IntlObject.h" -#include "JSCJSValueInlines.h" -#include "JSCellInlines.h" -#include "Lookup.h" -#include "SlotVisitorInlines.h" -#include "StructureInlines.h" - -namespace JSC { - -STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(IntlDateTimeFormatConstructor); - -static EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatConstructorFuncSupportedLocalesOf(ExecState*); - -} - -#include "IntlDateTimeFormatConstructor.lut.h" - -namespace JSC { - -const ClassInfo IntlDateTimeFormatConstructor::s_info = { "Function", &InternalFunction::s_info, &dateTimeFormatConstructorTable, CREATE_METHOD_TABLE(IntlDateTimeFormatConstructor) }; - -/* Source for IntlDateTimeFormatConstructor.lut.h -@begin dateTimeFormatConstructorTable - supportedLocalesOf IntlDateTimeFormatConstructorFuncSupportedLocalesOf DontEnum|Function 1 -@end -*/ - -IntlDateTimeFormatConstructor* IntlDateTimeFormatConstructor::create(VM& vm, Structure* structure, IntlDateTimeFormatPrototype* dateTimeFormatPrototype, Structure* dateTimeFormatStructure) -{ - IntlDateTimeFormatConstructor* constructor = new (NotNull, allocateCell<IntlDateTimeFormatConstructor>(vm.heap)) IntlDateTimeFormatConstructor(vm, structure); - constructor->finishCreation(vm, dateTimeFormatPrototype, dateTimeFormatStructure); - return constructor; -} - -Structure* IntlDateTimeFormatConstructor::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) -{ - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); -} - -IntlDateTimeFormatConstructor::IntlDateTimeFormatConstructor(VM& vm, Structure* structure) - : InternalFunction(vm, structure) -{ -} - -void IntlDateTimeFormatConstructor::finishCreation(VM& vm, IntlDateTimeFormatPrototype* dateTimeFormatPrototype, Structure* dateTimeFormatStructure) -{ - Base::finishCreation(vm, ASCIILiteral("DateTimeFormat")); - putDirectWithoutTransition(vm, vm.propertyNames->prototype, dateTimeFormatPrototype, DontEnum | DontDelete | ReadOnly); - putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), ReadOnly | DontEnum | DontDelete); - m_dateTimeFormatStructure.set(vm, this, dateTimeFormatStructure); -} - -EncodedJSValue JSC_HOST_CALL constructIntlDateTimeFormat(ExecState* exec) -{ - // 12.1.2 Intl.DateTimeFormat ([locales [, options]]) (ECMA-402 2.0) - // 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget. - JSValue newTarget = exec->newTarget(); - if (!newTarget || newTarget.isUndefined()) - newTarget = exec->callee(); - - // 2. Let dateTimeFormat be OrdinaryCreateFromConstructor(newTarget, %DateTimeFormatPrototype%). - VM& vm = exec->vm(); - IntlDateTimeFormat* dateTimeFormat = IntlDateTimeFormat::create(vm, jsCast<IntlDateTimeFormatConstructor*>(exec->callee())); - if (dateTimeFormat && !jsDynamicCast<IntlDateTimeFormatConstructor*>(newTarget)) { - JSValue proto = asObject(newTarget)->getDirect(vm, vm.propertyNames->prototype); - asObject(dateTimeFormat)->setPrototypeWithCycleCheck(exec, proto); - } - - // 3. ReturnIfAbrupt(dateTimeFormat). - ASSERT(dateTimeFormat); - - // 4. Return InitializeDateTimeFormat(dateTimeFormat, locales, options). - // FIXME: return JSValue::encode(InitializeDateTimeFormat(dateTimeFormat, locales, options)); - - return JSValue::encode(dateTimeFormat); -} - -EncodedJSValue JSC_HOST_CALL callIntlDateTimeFormat(ExecState* exec) -{ - // 12.1.2 Intl.DateTimeFormat ([locales [, options]]) (ECMA-402 2.0) - // 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget. - // NewTarget is always undefined when called as a function. - - // 2. Let dateTimeFormat be OrdinaryCreateFromConstructor(newTarget, %DateTimeFormatPrototype%). - VM& vm = exec->vm(); - IntlDateTimeFormat* dateTimeFormat = IntlDateTimeFormat::create(vm, jsCast<IntlDateTimeFormatConstructor*>(exec->callee())); - - // 3. ReturnIfAbrupt(dateTimeFormat). - ASSERT(dateTimeFormat); - - // 4. Return InitializeDateTimeFormat(dateTimeFormat, locales, options). - // FIXME: return JSValue::encode(InitializeDateTimeFormat(dateTimeFormat, locales, options)); - - return JSValue::encode(dateTimeFormat); -} - -ConstructType IntlDateTimeFormatConstructor::getConstructData(JSCell*, ConstructData& constructData) -{ - constructData.native.function = constructIntlDateTimeFormat; - return ConstructTypeHost; -} - -CallType IntlDateTimeFormatConstructor::getCallData(JSCell*, CallData& callData) -{ - callData.native.function = callIntlDateTimeFormat; - return CallTypeHost; -} - -bool IntlDateTimeFormatConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) -{ - return getStaticFunctionSlot<InternalFunction>(exec, dateTimeFormatConstructorTable, jsCast<IntlDateTimeFormatConstructor*>(object), propertyName, slot); -} - -EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatConstructorFuncSupportedLocalesOf(ExecState* exec) -{ - // 12.2.2 Intl.DateTimeFormat.supportedLocalesOf(locales [, options]) (ECMA-402 2.0) - - // 1. Let availableLocales be %DateTimeFormat%.[[availableLocales]]. - // FIXME: available = IntlDateTimeFormatConstructor::getAvailableLocales() - - // 2. Let requestedLocales be CanonicalizeLocaleList(locales). - // FIXME: requested = CanonicalizeLocaleList(locales) - - // 3. Return SupportedLocales(availableLocales, requestedLocales, options). - // FIXME: return JSValue::encode(SupportedLocales(available, requested, options)); - - // Return empty array until properly implemented. - VM& vm = exec->vm(); - JSGlobalObject* globalObject = exec->callee()->globalObject(); - JSArray* supportedLocales = JSArray::tryCreateUninitialized(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), 0); - if (!supportedLocales) - return JSValue::encode(throwOutOfMemoryError(exec)); - - return JSValue::encode(supportedLocales); -} - -void IntlDateTimeFormatConstructor::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - IntlDateTimeFormatConstructor* thisObject = jsCast<IntlDateTimeFormatConstructor*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - - Base::visitChildren(thisObject, visitor); - - visitor.append(&thisObject->m_dateTimeFormatStructure); -} - -} // namespace JSC - -#endif // ENABLE(INTL) diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.h b/Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.h deleted file mode 100644 index cf043a7e7..000000000 --- a/Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com) - * - * 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 IntlDateTimeFormatConstructor_h -#define IntlDateTimeFormatConstructor_h - -#if ENABLE(INTL) - -#include "InternalFunction.h" - -namespace JSC { - -class IntlDateTimeFormat; -class IntlDateTimeFormatPrototype; - -class IntlDateTimeFormatConstructor : public InternalFunction { -public: - typedef InternalFunction Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; - - static IntlDateTimeFormatConstructor* create(VM&, Structure*, IntlDateTimeFormatPrototype*, Structure*); - static Structure* createStructure(VM&, JSGlobalObject*, JSValue); - - DECLARE_INFO; - - Structure* dateTimeFormatStructure() const { return m_dateTimeFormatStructure.get(); } - -protected: - void finishCreation(VM&, IntlDateTimeFormatPrototype*, Structure*); - -private: - IntlDateTimeFormatConstructor(VM&, Structure*); - static ConstructType getConstructData(JSCell*, ConstructData&); - static CallType getCallData(JSCell*, CallData&); - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); - static void visitChildren(JSCell*, SlotVisitor&); - - WriteBarrier<Structure> m_dateTimeFormatStructure; -}; - -EncodedJSValue JSC_HOST_CALL constructIntlDateTimeFormat(ExecState*); -EncodedJSValue JSC_HOST_CALL callIntlDateTimeFormat(ExecState*); - -} // namespace JSC - -#endif // ENABLE(INTL) - -#endif // IntlDateTimeFormatConstructor_h diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.cpp b/Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.cpp deleted file mode 100644 index 079b9295c..000000000 --- a/Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com) - * - * 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 "IntlDateTimeFormatPrototype.h" - -#if ENABLE(INTL) - -#include "Error.h" -#include "IntlDateTimeFormat.h" -#include "JSBoundFunction.h" -#include "JSCJSValueInlines.h" -#include "JSCellInlines.h" -#include "JSObject.h" -#include "ObjectConstructor.h" -#include "StructureInlines.h" - -namespace JSC { - -STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(IntlDateTimeFormatPrototype); - -static EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatPrototypeGetterFormat(ExecState*); -static EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatPrototypeFuncResolvedOptions(ExecState*); - -} - -#include "IntlDateTimeFormatPrototype.lut.h" - -namespace JSC { - -const ClassInfo IntlDateTimeFormatPrototype::s_info = { "Object", &IntlDateTimeFormat::s_info, &dateTimeFormatPrototypeTable, CREATE_METHOD_TABLE(IntlDateTimeFormatPrototype) }; - -/* Source for IntlDateTimeFormatPrototype.lut.h -@begin dateTimeFormatPrototypeTable - format IntlDateTimeFormatPrototypeGetterFormat DontEnum|Accessor - resolvedOptions IntlDateTimeFormatPrototypeFuncResolvedOptions DontEnum|Function 0 -@end -*/ - -IntlDateTimeFormatPrototype* IntlDateTimeFormatPrototype::create(VM& vm, JSGlobalObject*, Structure* structure) -{ - IntlDateTimeFormatPrototype* object = new (NotNull, allocateCell<IntlDateTimeFormatPrototype>(vm.heap)) IntlDateTimeFormatPrototype(vm, structure); - object->finishCreation(vm, structure); - return object; -} - -Structure* IntlDateTimeFormatPrototype::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) -{ - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); -} - -IntlDateTimeFormatPrototype::IntlDateTimeFormatPrototype(VM& vm, Structure* structure) - : IntlDateTimeFormat(vm, structure) -{ -} - -void IntlDateTimeFormatPrototype::finishCreation(VM& vm, Structure*) -{ - Base::finishCreation(vm); -} - -bool IntlDateTimeFormatPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) -{ - return getStaticFunctionSlot<JSObject>(exec, dateTimeFormatPrototypeTable, jsCast<IntlDateTimeFormatPrototype*>(object), propertyName, slot); -} - -EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatPrototypeGetterFormat(ExecState* exec) -{ - // 12.3.3 Intl.DateTimeFormat.prototype.format (ECMA-402 2.0) - // 1. Let dtf be this DateTimeFormat object. - IntlDateTimeFormat* dtf = jsDynamicCast<IntlDateTimeFormat*>(exec->thisValue()); - // 2. ReturnIfAbrupt(dtf). - if (!dtf) - return JSValue::encode(throwTypeError(exec, ASCIILiteral("Intl.DateTimeFormat.prototype.format called on value that's not an object initialized as a DateTimeFormat"))); - - JSBoundFunction* boundFormat = dtf->boundFormat(); - // 3. If the [[boundFormat]] internal slot of this DateTimeFormat object is undefined, - if (!boundFormat) { - VM& vm = exec->vm(); - JSGlobalObject* globalObject = dtf->globalObject(); - // a. Let F be a new built-in function object as defined in 12.3.4. - // b. The value of F’s length property is 1. (Note: F’s length property was 0 in ECMA-402 1.0) - JSFunction* targetObject = JSFunction::create(vm, globalObject, 1, ASCIILiteral("format"), IntlDateTimeFormatFuncFormatDateTime, NoIntrinsic); - JSArray* boundArgs = JSArray::tryCreateUninitialized(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), 0); - if (!boundArgs) - return JSValue::encode(throwOutOfMemoryError(exec)); - - // c. Let bf be BoundFunctionCreate(F, «this value»). - boundFormat = JSBoundFunction::create(vm, globalObject, targetObject, dtf, boundArgs, 1, ASCIILiteral("format")); - // d. Set dtf.[[boundFormat]] to bf. - dtf->setBoundFormat(vm, boundFormat); - } - // 4. Return dtf.[[boundFormat]]. - return JSValue::encode(boundFormat); -} - -EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatPrototypeFuncResolvedOptions(ExecState* exec) -{ - // 12.3.5 Intl.DateTimeFormat.prototype.resolvedOptions() (ECMA-402 2.0) - IntlDateTimeFormat* dtf = jsDynamicCast<IntlDateTimeFormat*>(exec->thisValue()); - if (!dtf) - return JSValue::encode(throwTypeError(exec, ASCIILiteral("Intl.DateTimeFormat.prototype.resolvedOptions called on value that's not an object initialized as a DateTimeFormat"))); - - // The function returns a new object whose properties and attributes are set as if constructed by an object literal assigning to each of the following properties the value of the corresponding internal slot of this DateTimeFormat object (see 12.4): locale, calendar, numberingSystem, timeZone, hour12, weekday, era, year, month, day, hour, minute, second, and timeZoneName. Properties whose corresponding internal slots are not present are not assigned. - // Note: In this version of the ECMAScript 2015 Internationalization API, the timeZone property will be the name of the default time zone if no timeZone property was provided in the options object provided to the Intl.DateTimeFormat constructor. The previous version left the timeZone property undefined in this case. - - JSObject* options = constructEmptyObject(exec); - - // FIXME: Populate object from internal slots. - - return JSValue::encode(options); -} - -} // namespace JSC - -#endif // ENABLE(INTL) diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.h b/Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.h deleted file mode 100644 index a2fd5e34e..000000000 --- a/Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com) - * - * 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 IntlDateTimeFormatPrototype_h -#define IntlDateTimeFormatPrototype_h - -#if ENABLE(INTL) - -#include "IntlDateTimeFormat.h" -#include "JSObject.h" - -namespace JSC { - -class IntlDateTimeFormatPrototype : public IntlDateTimeFormat { -public: - typedef IntlDateTimeFormat Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; - - static IntlDateTimeFormatPrototype* create(VM&, JSGlobalObject*, Structure*); - static Structure* createStructure(VM&, JSGlobalObject*, JSValue); - - DECLARE_INFO; - -protected: - void finishCreation(VM&, Structure*); - -private: - IntlDateTimeFormatPrototype(VM&, Structure*); - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); -}; - -} // namespace JSC - -#endif // ENABLE(INTL) - -#endif // IntlDateTimeFormatPrototype_h diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp b/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp deleted file mode 100644 index 139dc5b19..000000000 --- a/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com) - * - * 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 "IntlNumberFormat.h" - -#if ENABLE(INTL) - -#include "Error.h" -#include "IntlNumberFormatConstructor.h" -#include "IntlObject.h" -#include "JSBoundFunction.h" -#include "JSCJSValueInlines.h" -#include "JSCellInlines.h" -#include "SlotVisitorInlines.h" -#include "StructureInlines.h" - -namespace JSC { - -const ClassInfo IntlNumberFormat::s_info = { "Object", &Base::s_info, 0, CREATE_METHOD_TABLE(IntlNumberFormat) }; - -IntlNumberFormat* IntlNumberFormat::create(VM& vm, IntlNumberFormatConstructor* constructor) -{ - IntlNumberFormat* format = new (NotNull, allocateCell<IntlNumberFormat>(vm.heap)) IntlNumberFormat(vm, constructor->numberFormatStructure()); - format->finishCreation(vm); - return format; -} - -Structure* IntlNumberFormat::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) -{ - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); -} - -IntlNumberFormat::IntlNumberFormat(VM& vm, Structure* structure) - : JSDestructibleObject(vm, structure) -{ -} - -void IntlNumberFormat::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); -} - -void IntlNumberFormat::destroy(JSCell* cell) -{ - static_cast<IntlNumberFormat*>(cell)->IntlNumberFormat::~IntlNumberFormat(); -} - -void IntlNumberFormat::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - IntlNumberFormat* thisObject = jsCast<IntlNumberFormat*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - - Base::visitChildren(thisObject, visitor); - - visitor.append(&thisObject->m_boundFormat); -} - -void IntlNumberFormat::setBoundFormat(VM& vm, JSBoundFunction* format) -{ - m_boundFormat.set(vm, this, format); -} - -EncodedJSValue JSC_HOST_CALL IntlNumberFormatFuncFormatNumber(ExecState* exec) -{ - // 11.3.4 Format Number Functions (ECMA-402 2.0) - // 1. Let nf be the this value. - IntlNumberFormat* format = jsDynamicCast<IntlNumberFormat*>(exec->thisValue()); - // 2. Assert: Type(nf) is Object and nf has an [[initializedNumberFormat]] internal slot whose value is true. - if (!format) - return JSValue::encode(throwTypeError(exec)); - - // 3. If value is not provided, let value be undefined. - // 4. Let x be ToNumber(value). - double value = exec->argument(0).toNumber(exec); - // 5. ReturnIfAbrupt(x). - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - // 6. Return FormatNumber(nf, x). - - // 11.3.4 FormatNumber abstract operation (ECMA-402 2.0) - // FIXME: Implement FormatNumber. - - return JSValue::encode(jsNumber(value).toString(exec)); -} - -} // namespace JSC - -#endif // ENABLE(INTL) diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormat.h b/Source/JavaScriptCore/runtime/IntlNumberFormat.h deleted file mode 100644 index cc2538f9b..000000000 --- a/Source/JavaScriptCore/runtime/IntlNumberFormat.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com) - * - * 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 IntlNumberFormat_h -#define IntlNumberFormat_h - -#if ENABLE(INTL) - -#include "JSDestructibleObject.h" - -namespace JSC { - -class IntlNumberFormatConstructor; -class JSBoundFunction; - -class IntlNumberFormat : public JSDestructibleObject { -public: - typedef JSDestructibleObject Base; - - static IntlNumberFormat* create(VM&, IntlNumberFormatConstructor*); - static Structure* createStructure(VM&, JSGlobalObject*, JSValue); - - DECLARE_INFO; - - JSBoundFunction* boundFormat() const { return m_boundFormat.get(); } - void setBoundFormat(VM&, JSBoundFunction*); - -protected: - IntlNumberFormat(VM&, Structure*); - void finishCreation(VM&); - static void destroy(JSCell*); - static void visitChildren(JSCell*, SlotVisitor&); - - WriteBarrier<JSBoundFunction> m_boundFormat; -}; - -EncodedJSValue JSC_HOST_CALL IntlNumberFormatFuncFormatNumber(ExecState*); - -} // namespace JSC - -#endif // ENABLE(INTL) - -#endif // IntlNumberFormat_h diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormatConstructor.cpp b/Source/JavaScriptCore/runtime/IntlNumberFormatConstructor.cpp deleted file mode 100644 index b8639d6b1..000000000 --- a/Source/JavaScriptCore/runtime/IntlNumberFormatConstructor.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com) - * - * 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 "IntlNumberFormatConstructor.h" - -#if ENABLE(INTL) - -#include "Error.h" -#include "IntlNumberFormat.h" -#include "IntlNumberFormatPrototype.h" -#include "IntlObject.h" -#include "JSCJSValueInlines.h" -#include "JSCellInlines.h" -#include "Lookup.h" -#include "SlotVisitorInlines.h" -#include "StructureInlines.h" - -namespace JSC { - -STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(IntlNumberFormatConstructor); - -static EncodedJSValue JSC_HOST_CALL IntlNumberFormatConstructorFuncSupportedLocalesOf(ExecState*); - -} - -#include "IntlNumberFormatConstructor.lut.h" - -namespace JSC { - -const ClassInfo IntlNumberFormatConstructor::s_info = { "Function", &Base::s_info, &numberFormatConstructorTable, CREATE_METHOD_TABLE(IntlNumberFormatConstructor) }; - -/* Source for IntlNumberFormatConstructor.lut.h -@begin numberFormatConstructorTable - supportedLocalesOf IntlNumberFormatConstructorFuncSupportedLocalesOf DontEnum|Function 1 -@end -*/ - -IntlNumberFormatConstructor* IntlNumberFormatConstructor::create(VM& vm, Structure* structure, IntlNumberFormatPrototype* numberFormatPrototype, Structure* numberFormatStructure) -{ - IntlNumberFormatConstructor* constructor = new (NotNull, allocateCell<IntlNumberFormatConstructor>(vm.heap)) IntlNumberFormatConstructor(vm, structure); - constructor->finishCreation(vm, numberFormatPrototype, numberFormatStructure); - return constructor; -} - -Structure* IntlNumberFormatConstructor::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) -{ - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); -} - -IntlNumberFormatConstructor::IntlNumberFormatConstructor(VM& vm, Structure* structure) - : InternalFunction(vm, structure) -{ -} - -void IntlNumberFormatConstructor::finishCreation(VM& vm, IntlNumberFormatPrototype* numberFormatPrototype, Structure* numberFormatStructure) -{ - Base::finishCreation(vm, ASCIILiteral("NumberFormat")); - putDirectWithoutTransition(vm, vm.propertyNames->prototype, numberFormatPrototype, DontEnum | DontDelete | ReadOnly); - putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), ReadOnly | DontEnum | DontDelete); - m_numberFormatStructure.set(vm, this, numberFormatStructure); -} - -EncodedJSValue JSC_HOST_CALL constructIntlNumberFormat(ExecState* exec) -{ - // 11.1.2 Intl.NumberFormat ([locales [, options]]) (ECMA-402 2.0) - // 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget. - JSValue newTarget = exec->newTarget(); - if (!newTarget || newTarget.isUndefined()) - newTarget = exec->callee(); - - // 2. Let numberFormat be OrdinaryCreateFromConstructor(newTarget, %NumberFormatPrototype%). - VM& vm = exec->vm(); - IntlNumberFormat* numberFormat = IntlNumberFormat::create(vm, jsCast<IntlNumberFormatConstructor*>(exec->callee())); - if (numberFormat && !jsDynamicCast<IntlNumberFormatConstructor*>(newTarget)) { - JSValue proto = asObject(newTarget)->getDirect(vm, vm.propertyNames->prototype); - asObject(numberFormat)->setPrototypeWithCycleCheck(exec, proto); - } - - // 3. ReturnIfAbrupt(numberFormat). - ASSERT(numberFormat); - - // 4. Return InitializeNumberFormat(numberFormat, locales, options). - // FIXME: return JSValue::encode(InitializeNumberFormat(numberFormat, locales, options)); - - return JSValue::encode(numberFormat); -} - -EncodedJSValue JSC_HOST_CALL callIntlNumberFormat(ExecState* exec) -{ - // 11.1.2 Intl.NumberFormat ([locales [, options]]) (ECMA-402 2.0) - // 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget. - // NewTarget is always undefined when called as a function. - - // 2. Let numberFormat be OrdinaryCreateFromConstructor(newTarget, %NumberFormatPrototype%). - VM& vm = exec->vm(); - IntlNumberFormat* numberFormat = IntlNumberFormat::create(vm, jsCast<IntlNumberFormatConstructor*>(exec->callee())); - - // 3. ReturnIfAbrupt(numberFormat). - ASSERT(numberFormat); - - // 4. Return InitializeNumberFormat(numberFormat, locales, options). - // FIXME: return JSValue::encode(InitializeNumberFormat(numberFormat, locales, options)); - - return JSValue::encode(numberFormat); -} - -ConstructType IntlNumberFormatConstructor::getConstructData(JSCell*, ConstructData& constructData) -{ - constructData.native.function = constructIntlNumberFormat; - return ConstructTypeHost; -} - -CallType IntlNumberFormatConstructor::getCallData(JSCell*, CallData& callData) -{ - callData.native.function = callIntlNumberFormat; - return CallTypeHost; -} - -bool IntlNumberFormatConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) -{ - return getStaticFunctionSlot<InternalFunction>(exec, numberFormatConstructorTable, jsCast<IntlNumberFormatConstructor*>(object), propertyName, slot); -} - -EncodedJSValue JSC_HOST_CALL IntlNumberFormatConstructorFuncSupportedLocalesOf(ExecState* exec) -{ - // 11.2.2 Intl.NumberFormat.supportedLocalesOf(locales [, options]) (ECMA-402 2.0) - - // 1. Let availableLocales be %NumberFormat%.[[availableLocales]]. - // FIXME: available = IntlNumberFormatConstructor::getAvailableLocales() - - // 2. Let requestedLocales be CanonicalizeLocaleList(locales). - // FIXME: requested = CanonicalizeLocaleList(locales) - - // 3. Return SupportedLocales(availableLocales, requestedLocales, options). - // FIXME: return JSValue::encode(SupportedLocales(available, requested, options)); - - // Return empty array until properly implemented. - VM& vm = exec->vm(); - JSGlobalObject* globalObject = exec->callee()->globalObject(); - JSArray* supportedLocales = JSArray::tryCreateUninitialized(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), 0); - if (!supportedLocales) - return JSValue::encode(throwOutOfMemoryError(exec)); - - return JSValue::encode(supportedLocales); -} - -void IntlNumberFormatConstructor::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - IntlNumberFormatConstructor* thisObject = jsCast<IntlNumberFormatConstructor*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - - Base::visitChildren(thisObject, visitor); - - visitor.append(&thisObject->m_numberFormatStructure); -} - -} // namespace JSC - -#endif // ENABLE(INTL) diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormatConstructor.h b/Source/JavaScriptCore/runtime/IntlNumberFormatConstructor.h deleted file mode 100644 index bb75f1021..000000000 --- a/Source/JavaScriptCore/runtime/IntlNumberFormatConstructor.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com) - * - * 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 IntlNumberFormatConstructor_h -#define IntlNumberFormatConstructor_h - -#if ENABLE(INTL) - -#include "InternalFunction.h" - -namespace JSC { - -class IntlNumberFormat; -class IntlNumberFormatPrototype; - -class IntlNumberFormatConstructor : public InternalFunction { -public: - typedef InternalFunction Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; - - static IntlNumberFormatConstructor* create(VM&, Structure*, IntlNumberFormatPrototype*, Structure*); - static Structure* createStructure(VM&, JSGlobalObject*, JSValue); - - DECLARE_INFO; - - Structure* numberFormatStructure() const { return m_numberFormatStructure.get(); } - -protected: - void finishCreation(VM&, IntlNumberFormatPrototype*, Structure*); - -private: - IntlNumberFormatConstructor(VM&, Structure*); - static ConstructType getConstructData(JSCell*, ConstructData&); - static CallType getCallData(JSCell*, CallData&); - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); - static void visitChildren(JSCell*, SlotVisitor&); - - WriteBarrier<Structure> m_numberFormatStructure; -}; - -EncodedJSValue JSC_HOST_CALL constructIntlNumberFormat(ExecState*); -EncodedJSValue JSC_HOST_CALL callIntlNumberFormat(ExecState*); - -} // namespace JSC - -#endif // ENABLE(INTL) - -#endif // IntlNumberFormatConstructor_h diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp b/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp deleted file mode 100644 index 8a3492294..000000000 --- a/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com) - * - * 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 "IntlNumberFormatPrototype.h" - -#if ENABLE(INTL) - -#include "Error.h" -#include "IntlNumberFormat.h" -#include "JSBoundFunction.h" -#include "JSCJSValueInlines.h" -#include "JSCellInlines.h" -#include "JSObject.h" -#include "ObjectConstructor.h" -#include "StructureInlines.h" - -namespace JSC { - -STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(IntlNumberFormatPrototype); - -static EncodedJSValue JSC_HOST_CALL IntlNumberFormatPrototypeGetterFormat(ExecState*); -static EncodedJSValue JSC_HOST_CALL IntlNumberFormatPrototypeFuncResolvedOptions(ExecState*); - -} - -#include "IntlNumberFormatPrototype.lut.h" - -namespace JSC { - -const ClassInfo IntlNumberFormatPrototype::s_info = { "Object", &IntlNumberFormat::s_info, &numberFormatPrototypeTable, CREATE_METHOD_TABLE(IntlNumberFormatPrototype) }; - -/* Source for IntlNumberFormatPrototype.lut.h -@begin numberFormatPrototypeTable - format IntlNumberFormatPrototypeGetterFormat DontEnum|Accessor - resolvedOptions IntlNumberFormatPrototypeFuncResolvedOptions DontEnum|Function 0 -@end -*/ - -IntlNumberFormatPrototype* IntlNumberFormatPrototype::create(VM& vm, JSGlobalObject*, Structure* structure) -{ - IntlNumberFormatPrototype* object = new (NotNull, allocateCell<IntlNumberFormatPrototype>(vm.heap)) IntlNumberFormatPrototype(vm, structure); - object->finishCreation(vm, structure); - return object; -} - -Structure* IntlNumberFormatPrototype::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) -{ - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); -} - -IntlNumberFormatPrototype::IntlNumberFormatPrototype(VM& vm, Structure* structure) - : IntlNumberFormat(vm, structure) -{ -} - -void IntlNumberFormatPrototype::finishCreation(VM& vm, Structure*) -{ - Base::finishCreation(vm); -} - -bool IntlNumberFormatPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) -{ - return getStaticFunctionSlot<JSObject>(exec, numberFormatPrototypeTable, jsCast<IntlNumberFormatPrototype*>(object), propertyName, slot); -} - -EncodedJSValue JSC_HOST_CALL IntlNumberFormatPrototypeGetterFormat(ExecState* exec) -{ - // 11.3.3 Intl.NumberFormat.prototype.format (ECMA-402 2.0) - // 1. Let nf be this NumberFormat object. - IntlNumberFormat* nf = jsDynamicCast<IntlNumberFormat*>(exec->thisValue()); - if (!nf) - return JSValue::encode(throwTypeError(exec, ASCIILiteral("Intl.NumberFormat.prototype.format called on value that's not an object initialized as a NumberFormat"))); - - JSBoundFunction* boundFormat = nf->boundFormat(); - // 2. If nf.[[boundFormat]] is undefined, - if (!boundFormat) { - VM& vm = exec->vm(); - JSGlobalObject* globalObject = nf->globalObject(); - // a. Let F be a new built-in function object as defined in 11.3.4. - // b. The value of F’s length property is 1. - JSFunction* targetObject = JSFunction::create(vm, globalObject, 1, ASCIILiteral("format"), IntlNumberFormatFuncFormatNumber, NoIntrinsic); - JSArray* boundArgs = JSArray::tryCreateUninitialized(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), 0); - if (!boundArgs) - return JSValue::encode(throwOutOfMemoryError(exec)); - - // c. Let bf be BoundFunctionCreate(F, «this value»). - boundFormat = JSBoundFunction::create(vm, globalObject, targetObject, nf, boundArgs, 1, ASCIILiteral("format")); - // d. Set nf.[[boundFormat]] to bf. - nf->setBoundFormat(vm, boundFormat); - } - // 3. Return nf.[[boundFormat]]. - return JSValue::encode(boundFormat); -} - -EncodedJSValue JSC_HOST_CALL IntlNumberFormatPrototypeFuncResolvedOptions(ExecState* exec) -{ - // 11.3.5 Intl.NumberFormat.prototype.resolvedOptions() (ECMA-402 2.0) - IntlNumberFormat* nf = jsDynamicCast<IntlNumberFormat*>(exec->thisValue()); - if (!nf) - return JSValue::encode(throwTypeError(exec, ASCIILiteral("Intl.NumberFormat.prototype.resolvedOptions called on value that's not an object initialized as a NumberFormat"))); - - // The function returns a new object whose properties and attributes are set as if constructed by an object literal assigning to each of the following properties the value of the corresponding internal slot of this NumberFormat object (see 11.4): locale, numberingSystem, style, currency, currencyDisplay, minimumIntegerDigits, minimumFractionDigits, maximumFractionDigits, minimumSignificantDigits, maximumSignificantDigits, and useGrouping. Properties whose corresponding internal slots are not present are not assigned. - - JSObject* options = constructEmptyObject(exec); - - // FIXME: Populate object from internal slots. - - return JSValue::encode(options); -} - -} // namespace JSC - -#endif // ENABLE(INTL) diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.h b/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.h deleted file mode 100644 index 78bc051fd..000000000 --- a/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com) - * - * 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 IntlNumberFormatPrototype_h -#define IntlNumberFormatPrototype_h - -#if ENABLE(INTL) - -#include "IntlNumberFormat.h" -#include "JSObject.h" - -namespace JSC { - -class IntlNumberFormatPrototype : public IntlNumberFormat { -public: - typedef IntlNumberFormat Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; - - static IntlNumberFormatPrototype* create(VM&, JSGlobalObject*, Structure*); - static Structure* createStructure(VM&, JSGlobalObject*, JSValue); - - DECLARE_INFO; - -protected: - void finishCreation(VM&, Structure*); - -private: - IntlNumberFormatPrototype(VM&, Structure*); - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); -}; - -} // namespace JSC - -#endif // ENABLE(INTL) - -#endif // IntlNumberFormatPrototype_h diff --git a/Source/JavaScriptCore/runtime/IntlObject.cpp b/Source/JavaScriptCore/runtime/IntlObject.cpp deleted file mode 100644 index ba457e725..000000000 --- a/Source/JavaScriptCore/runtime/IntlObject.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com) - * - * 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 "IntlObject.h" - -#if ENABLE(INTL) - -#include "FunctionPrototype.h" -#include "IntlCollator.h" -#include "IntlCollatorConstructor.h" -#include "IntlCollatorPrototype.h" -#include "IntlDateTimeFormat.h" -#include "IntlDateTimeFormatConstructor.h" -#include "IntlDateTimeFormatPrototype.h" -#include "IntlNumberFormat.h" -#include "IntlNumberFormatConstructor.h" -#include "IntlNumberFormatPrototype.h" -#include "JSCInlines.h" -#include "Lookup.h" -#include "ObjectPrototype.h" -#include <wtf/Assertions.h> - -namespace JSC { - -STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(IntlObject); - -} - -namespace JSC { - -const ClassInfo IntlObject::s_info = { "Object", &Base::s_info, 0, CREATE_METHOD_TABLE(IntlObject) }; - -IntlObject::IntlObject(VM& vm, Structure* structure) - : JSNonFinalObject(vm, structure) -{ -} - -IntlObject* IntlObject::create(VM& vm, JSGlobalObject* globalObject, Structure* structure) -{ - IntlObject* object = new (NotNull, allocateCell<IntlObject>(vm.heap)) IntlObject(vm, structure); - object->finishCreation(vm, globalObject); - return object; -} - -void IntlObject::finishCreation(VM& vm, JSGlobalObject* globalObject) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); - - // Set up Collator. - IntlCollatorPrototype* collatorPrototype = IntlCollatorPrototype::create(vm, globalObject, IntlCollatorPrototype::createStructure(vm, globalObject, globalObject->objectPrototype())); - Structure* collatorStructure = IntlCollator::createStructure(vm, globalObject, collatorPrototype); - IntlCollatorConstructor* collatorConstructor = IntlCollatorConstructor::create(vm, IntlCollatorConstructor::createStructure(vm, globalObject, globalObject->functionPrototype()), collatorPrototype, collatorStructure); - - collatorPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, collatorConstructor, DontEnum); - - // Set up NumberFormat. - IntlNumberFormatPrototype* numberFormatPrototype = IntlNumberFormatPrototype::create(vm, globalObject, IntlNumberFormatPrototype::createStructure(vm, globalObject, globalObject->objectPrototype())); - Structure* numberFormatStructure = IntlNumberFormat::createStructure(vm, globalObject, numberFormatPrototype); - IntlNumberFormatConstructor* numberFormatConstructor = IntlNumberFormatConstructor::create(vm, IntlNumberFormatConstructor::createStructure(vm, globalObject, globalObject->functionPrototype()), numberFormatPrototype, numberFormatStructure); - - numberFormatPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, numberFormatConstructor, DontEnum); - - // Set up DateTimeFormat. - IntlDateTimeFormatPrototype* dateTimeFormatPrototype = IntlDateTimeFormatPrototype::create(vm, globalObject, IntlDateTimeFormatPrototype::createStructure(vm, globalObject, globalObject->objectPrototype())); - Structure* dateTimeFormatStructure = IntlDateTimeFormat::createStructure(vm, globalObject, dateTimeFormatPrototype); - IntlDateTimeFormatConstructor* dateTimeFormatConstructor = IntlDateTimeFormatConstructor::create(vm, IntlDateTimeFormatConstructor::createStructure(vm, globalObject, globalObject->functionPrototype()), dateTimeFormatPrototype, dateTimeFormatStructure); - - dateTimeFormatPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, dateTimeFormatConstructor, DontEnum); - - // 8.1 Properties of the Intl Object (ECMA-402 2.0) - putDirectWithoutTransition(vm, vm.propertyNames->Collator, collatorConstructor, DontEnum); - putDirectWithoutTransition(vm, vm.propertyNames->NumberFormat, numberFormatConstructor, DontEnum); - putDirectWithoutTransition(vm, vm.propertyNames->DateTimeFormat, dateTimeFormatConstructor, DontEnum); -} - -Structure* IntlObject::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) -{ - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); -} - -} // namespace JSC - -#endif // ENABLE(INTL) diff --git a/Source/JavaScriptCore/runtime/IntlObject.h b/Source/JavaScriptCore/runtime/IntlObject.h deleted file mode 100644 index 83428542b..000000000 --- a/Source/JavaScriptCore/runtime/IntlObject.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com) - * - * 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 IntlObject_h -#define IntlObject_h - -#if ENABLE(INTL) - -#include "JSObject.h" - -namespace JSC { - -class IntlCollatorConstructor; -class IntlCollatorPrototype; -class IntlDateTimeFormatConstructor; -class IntlDateTimeFormatPrototype; -class IntlNumberFormatConstructor; -class IntlNumberFormatPrototype; - -class IntlObject : public JSNonFinalObject { -public: - typedef JSNonFinalObject Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; - - static IntlObject* create(VM&, JSGlobalObject*, Structure*); - static Structure* createStructure(VM&, JSGlobalObject*, JSValue); - - DECLARE_INFO; - -protected: - void finishCreation(VM&, JSGlobalObject*); - -private: - IntlObject(VM&, Structure*); -}; - -} // namespace JSC - -#endif // ENABLE(INTL) - -#endif // IntlObject_h diff --git a/Source/JavaScriptCore/runtime/Intrinsic.h b/Source/JavaScriptCore/runtime/Intrinsic.h index fe552a781..1f741da1e 100644 --- a/Source/JavaScriptCore/runtime/Intrinsic.h +++ b/Source/JavaScriptCore/runtime/Intrinsic.h @@ -35,7 +35,6 @@ enum Intrinsic { MaxIntrinsic, SqrtIntrinsic, SinIntrinsic, - Clz32Intrinsic, CosIntrinsic, ArrayPushIntrinsic, ArrayPopIntrinsic, @@ -52,16 +51,9 @@ enum Intrinsic { RegExpTestIntrinsic, StringPrototypeValueOfIntrinsic, IMulIntrinsic, - FRoundIntrinsic, - - // Debugging intrinsics. These are meant to be used as testing hacks within - // jsc.cpp and should never be exposed to users. - DFGTrueIntrinsic, - OSRExitIntrinsic, - IsFinalTierIntrinsic, - SetInt32HeapPredictionIntrinsic, - CheckInt32Intrinsic, - FiatInt52Intrinsic, + ArrayIteratorNextValueIntrinsic, + ArrayIteratorNextKeyIntrinsic, + ArrayIteratorNextGenericIntrinsic }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/IterationStatus.h b/Source/JavaScriptCore/runtime/IterationStatus.h deleted file mode 100644 index fb8b5fb75..000000000 --- a/Source/JavaScriptCore/runtime/IterationStatus.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2015 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 IterationStatus_h -#define IterationStatus_h - -namespace JSC { - -enum class IterationStatus { - Continue, - Done -}; - -} // namespace JSC - -#endif // IterationStatus_h diff --git a/Source/JavaScriptCore/runtime/IteratorOperations.cpp b/Source/JavaScriptCore/runtime/IteratorOperations.cpp deleted file mode 100644 index 2e886bf96..000000000 --- a/Source/JavaScriptCore/runtime/IteratorOperations.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. - * - * 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 "IteratorOperations.h" - -#include "Error.h" -#include "JSCInlines.h" -#include "ObjectConstructor.h" - -using namespace WTF; - -namespace JSC { - -JSValue iteratorNext(ExecState* exec, JSValue iterator, JSValue value) -{ - JSValue nextFunction = iterator.get(exec, exec->vm().propertyNames->next); - if (exec->hadException()) - return jsUndefined(); - - CallData nextFunctionCallData; - CallType nextFunctionCallType = getCallData(nextFunction, nextFunctionCallData); - if (nextFunctionCallType == CallTypeNone) - return throwTypeError(exec); - - MarkedArgumentBuffer nextFunctionArguments; - if (!value.isEmpty()) - nextFunctionArguments.append(value); - JSValue result = call(exec, nextFunction, nextFunctionCallType, nextFunctionCallData, iterator, nextFunctionArguments); - if (exec->hadException()) - return jsUndefined(); - - if (!result.isObject()) - return throwTypeError(exec, ASCIILiteral("Iterator result interface is not an object.")); - - return result; -} - -JSValue iteratorNext(ExecState* exec, JSValue iterator) -{ - return iteratorNext(exec, iterator, JSValue()); -} - -JSValue iteratorValue(ExecState* exec, JSValue iterResult) -{ - return iterResult.get(exec, exec->vm().propertyNames->value); -} - -bool iteratorComplete(ExecState* exec, JSValue iterResult) -{ - JSValue done = iterResult.get(exec, exec->vm().propertyNames->done); - return done.toBoolean(exec); -} - -JSValue iteratorStep(ExecState* exec, JSValue iterator) -{ - JSValue result = iteratorNext(exec, iterator); - if (exec->hadException()) - return jsUndefined(); - bool done = iteratorComplete(exec, result); - if (exec->hadException()) - return jsUndefined(); - if (done) - return jsBoolean(false); - return result; -} - -void iteratorClose(ExecState* exec, JSValue iterator) -{ - Exception* exception = nullptr; - if (exec->hadException()) { - exception = exec->exception(); - exec->clearException(); - } - JSValue returnFunction = iterator.get(exec, exec->vm().propertyNames->returnKeyword); - if (exec->hadException()) - return; - - if (returnFunction.isUndefined()) { - if (exception) - exec->vm().throwException(exec, exception); - return; - } - - CallData returnFunctionCallData; - CallType returnFunctionCallType = getCallData(returnFunction, returnFunctionCallData); - if (returnFunctionCallType == CallTypeNone) { - if (exception) - exec->vm().throwException(exec, exception); - else - throwTypeError(exec); - return; - } - - MarkedArgumentBuffer returnFunctionArguments; - JSValue innerResult = call(exec, returnFunction, returnFunctionCallType, returnFunctionCallData, iterator, returnFunctionArguments); - - if (exception) { - exec->vm().throwException(exec, exception); - return; - } - - if (exec->hadException()) - return; - - if (!innerResult.isObject()) { - throwTypeError(exec, ASCIILiteral("Iterator result interface is not an object.")); - return; - } -} - -JSObject* createIteratorResultObject(ExecState* exec, JSValue value, bool done) -{ - JSObject* resultObject = constructEmptyObject(exec); - resultObject->putDirect(exec->vm(), exec->propertyNames().done, jsBoolean(done)); - resultObject->putDirect(exec->vm(), exec->propertyNames().value, value); - return resultObject; -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/IteratorOperations.h b/Source/JavaScriptCore/runtime/IteratorOperations.h deleted file mode 100644 index a9a300c94..000000000 --- a/Source/JavaScriptCore/runtime/IteratorOperations.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. - * - * 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 IteratorOperations_h -#define IteratorOperations_h - -#include "JSCJSValue.h" -#include "JSObject.h" - -namespace JSC { - -JSValue iteratorNext(ExecState*, JSValue iterator, JSValue); -JSValue iteratorNext(ExecState*, JSValue iterator); -JSValue iteratorValue(ExecState*, JSValue iterator); -bool iteratorComplete(ExecState*, JSValue iterator); -JSValue iteratorStep(ExecState*, JSValue iterator); -void iteratorClose(ExecState*, JSValue iterator); -JS_EXPORT_PRIVATE JSObject* createIteratorResultObject(ExecState*, JSValue, bool done); - -} - -#endif // !defined(IteratorOperations_h) diff --git a/Source/JavaScriptCore/runtime/IteratorPrototype.cpp b/Source/JavaScriptCore/runtime/IteratorPrototype.cpp deleted file mode 100644 index 3e4ec9303..000000000 --- a/Source/JavaScriptCore/runtime/IteratorPrototype.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. - * - * 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 "IteratorPrototype.h" - -#include "JSCBuiltins.h" -#include "JSCJSValueInlines.h" -#include "JSCellInlines.h" -#include "JSGlobalObject.h" -#include "ObjectConstructor.h" -#include "StructureInlines.h" - -namespace JSC { - -const ClassInfo IteratorPrototype::s_info = { "Iterator", &Base::s_info, nullptr, CREATE_METHOD_TABLE(IteratorPrototype) }; - -void IteratorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); - vm.prototypeMap.addPrototype(this); - - JSFunction* iteratorPrototypeFunction = JSFunction::createBuiltinFunction(vm, iteratorPrototypeSymbolIteratorCodeGenerator(vm), globalObject, "[Symbol.iterator]"); - putDirectWithoutTransition(vm, vm.propertyNames->iteratorSymbol, iteratorPrototypeFunction, DontEnum); -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSAPIValueWrapper.cpp b/Source/JavaScriptCore/runtime/JSAPIValueWrapper.cpp index 6e5b53618..80c762620 100644 --- a/Source/JavaScriptCore/runtime/JSAPIValueWrapper.cpp +++ b/Source/JavaScriptCore/runtime/JSAPIValueWrapper.cpp @@ -29,6 +29,6 @@ namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSAPIValueWrapper); -const ClassInfo JSAPIValueWrapper::s_info = { "API Wrapper", 0, 0, CREATE_METHOD_TABLE(JSAPIValueWrapper) }; +const ClassInfo JSAPIValueWrapper::s_info = { "API Wrapper", 0, 0, 0, CREATE_METHOD_TABLE(JSAPIValueWrapper) }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h b/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h index 66e61c70d..e1f2cd804 100644 --- a/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h +++ b/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h @@ -30,51 +30,50 @@ namespace JSC { -class JSAPIValueWrapper : public JSCell { - friend JSValue jsAPIValueWrapper(ExecState*, JSValue); -public: - typedef JSCell Base; - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; + class JSAPIValueWrapper : public JSCell { + friend JSValue jsAPIValueWrapper(ExecState*, JSValue); + public: + typedef JSCell Base; - JSValue value() const { return m_value.get(); } + JSValue value() const { return m_value.get(); } - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(APIValueWrapperType, OverridesGetPropertyNames), info()); - } + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(APIValueWrapperType, OverridesVisitChildren | OverridesGetPropertyNames), info()); + } + + DECLARE_EXPORT_INFO; + + static JSAPIValueWrapper* create(ExecState* exec, JSValue value) + { + VM& vm = exec->vm(); + JSAPIValueWrapper* wrapper = new (NotNull, allocateCell<JSAPIValueWrapper>(vm.heap)) JSAPIValueWrapper(exec); + wrapper->finishCreation(vm, value); + return wrapper; + } - DECLARE_EXPORT_INFO; + protected: + void finishCreation(VM& vm, JSValue value) + { + Base::finishCreation(vm); + m_value.set(vm, this, value); + ASSERT(!value.isCell()); + } - static JSAPIValueWrapper* create(ExecState* exec, JSValue value) - { - VM& vm = exec->vm(); - JSAPIValueWrapper* wrapper = new (NotNull, allocateCell<JSAPIValueWrapper>(vm.heap)) JSAPIValueWrapper(exec); - wrapper->finishCreation(vm, value); - return wrapper; - } + private: + JSAPIValueWrapper(ExecState* exec) + : JSCell(exec->vm(), exec->vm().apiWrapperStructure.get()) + { + } -protected: - void finishCreation(VM& vm, JSValue value) - { - Base::finishCreation(vm); - m_value.set(vm, this, value); - ASSERT(!value.isCell()); - } + WriteBarrier<Unknown> m_value; + }; -private: - JSAPIValueWrapper(ExecState* exec) - : JSCell(exec->vm(), exec->vm().apiWrapperStructure.get()) + inline JSValue jsAPIValueWrapper(ExecState* exec, JSValue value) { + return JSAPIValueWrapper::create(exec, value); } - WriteBarrier<Unknown> m_value; -}; - -inline JSValue jsAPIValueWrapper(ExecState* exec, JSValue value) -{ - return JSAPIValueWrapper::create(exec, value); -} - } // namespace JSC #endif // JSAPIValueWrapper_h diff --git a/Source/JavaScriptCore/runtime/JSActivation.cpp b/Source/JavaScriptCore/runtime/JSActivation.cpp new file mode 100644 index 000000000..72ed1c712 --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSActivation.cpp @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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 "JSActivation.h" + +#include "Arguments.h" +#include "Interpreter.h" +#include "JSFunction.h" +#include "Operations.h" + +using namespace std; + +namespace JSC { + +const ClassInfo JSActivation::s_info = { "JSActivation", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSActivation) }; + +void JSActivation::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + JSActivation* thisObject = jsCast<JSActivation*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + Base::visitChildren(thisObject, visitor); + + // No need to mark our registers if they're still in the JSStack. + if (!thisObject->isTornOff()) + return; + + for (int i = 0; i < thisObject->symbolTable()->captureCount(); ++i) + visitor.append(&thisObject->storage()[i]); +} + +inline bool JSActivation::symbolTableGet(PropertyName propertyName, PropertySlot& slot) +{ + SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.publicName()); + if (entry.isNull()) + return false; + + // Defend against the inspector asking for a var after it has been optimized out. + if (isTornOff() && !isValid(entry)) + return false; + + slot.setValue(this, DontEnum, registerAt(entry.getIndex()).get()); + return true; +} + +inline bool JSActivation::symbolTableGet(PropertyName propertyName, PropertyDescriptor& descriptor) +{ + SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.publicName()); + if (entry.isNull()) + return false; + + // Defend against the inspector asking for a var after it has been optimized out. + if (isTornOff() && !isValid(entry)) + return false; + + descriptor.setDescriptor(registerAt(entry.getIndex()).get(), entry.getAttributes()); + return true; +} + +inline bool JSActivation::symbolTablePut(ExecState* exec, PropertyName propertyName, JSValue value, bool shouldThrow) +{ + VM& vm = exec->vm(); + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); + + SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.publicName()); + if (entry.isNull()) + return false; + if (entry.isReadOnly()) { + if (shouldThrow) + throwTypeError(exec, StrictModeReadonlyPropertyWriteError); + return true; + } + + // Defend against the inspector asking for a var after it has been optimized out. + if (isTornOff() && !isValid(entry)) + return false; + + registerAt(entry.getIndex()).set(vm, this, value); + return true; +} + +void JSActivation::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +{ + JSActivation* thisObject = jsCast<JSActivation*>(object); + + CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(thisObject->m_registers)); + if (mode == IncludeDontEnumProperties && !thisObject->isTornOff() && (callFrame->codeBlock()->usesArguments() || callFrame->codeBlock()->usesEval())) + propertyNames.add(exec->propertyNames().arguments); + + { + ConcurrentJITLocker locker(thisObject->symbolTable()->m_lock); + SymbolTable::Map::iterator end = thisObject->symbolTable()->end(locker); + for (SymbolTable::Map::iterator it = thisObject->symbolTable()->begin(locker); it != end; ++it) { + if (it->value.getAttributes() & DontEnum && mode != IncludeDontEnumProperties) + continue; + if (!thisObject->isValid(it->value)) + continue; + propertyNames.add(Identifier(exec, it->key.get())); + } + } + // Skip the JSVariableObject implementation of getOwnNonIndexPropertyNames + JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode); +} + +inline bool JSActivation::symbolTablePutWithAttributes(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes) +{ + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); + + WriteBarrierBase<Unknown>* reg; + { + ConcurrentJITLocker locker(symbolTable()->m_lock); + SymbolTable::Map::iterator iter = symbolTable()->find(locker, propertyName.publicName()); + if (iter == symbolTable()->end(locker)) + return false; + SymbolTableEntry& entry = iter->value; + ASSERT(!entry.isNull()); + if (!isValid(entry)) + return false; + + entry.setAttributes(attributes); + reg = ®isterAt(entry.getIndex()); + } + reg->set(vm, this, value); + return true; +} + +bool JSActivation::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) +{ + JSActivation* thisObject = jsCast<JSActivation*>(object); + + if (propertyName == exec->propertyNames().arguments) { + // Defend against the inspector asking for the arguments object after it has been optimized out. + CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(thisObject->m_registers)); + if (!thisObject->isTornOff() && (callFrame->codeBlock()->usesArguments() || callFrame->codeBlock()->usesEval())) { + slot.setCustom(thisObject, DontEnum, argumentsGetter); + return true; + } + } + + if (thisObject->symbolTableGet(propertyName, slot)) + return true; + + unsigned attributes; + if (JSValue value = thisObject->getDirect(exec->vm(), propertyName, attributes)) { + slot.setValue(thisObject, attributes, value); + return true; + } + + // We don't call through to JSObject because there's no way to give an + // activation object getter properties or a prototype. + ASSERT(!thisObject->hasGetterSetterProperties()); + ASSERT(thisObject->prototype().isNull()); + return false; +} + +void JSActivation::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) +{ + JSActivation* thisObject = jsCast<JSActivation*>(cell); + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); + + if (thisObject->symbolTablePut(exec, propertyName, value, slot.isStrictMode())) + return; + + // We don't call through to JSObject because __proto__ and getter/setter + // properties are non-standard extensions that other implementations do not + // expose in the activation object. + ASSERT(!thisObject->hasGetterSetterProperties()); + thisObject->putOwnDataProperty(exec->vm(), propertyName, value, slot); +} + +bool JSActivation::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) +{ + if (propertyName == exec->propertyNames().arguments) + return false; + + return Base::deleteProperty(cell, exec, propertyName); +} + +JSValue JSActivation::toThis(JSCell*, ExecState* exec, ECMAMode ecmaMode) +{ + if (ecmaMode == StrictMode) + return jsUndefined(); + return exec->globalThisValue(); +} + +EncodedJSValue JSActivation::argumentsGetter(ExecState*, EncodedJSValue slotBase, EncodedJSValue, PropertyName) +{ + JSActivation* activation = jsCast<JSActivation*>(JSValue::decode(slotBase)); + CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(activation->m_registers)); + ASSERT(!activation->isTornOff() && (callFrame->codeBlock()->usesArguments() || callFrame->codeBlock()->usesEval())); + if (activation->isTornOff() || !(callFrame->codeBlock()->usesArguments() || callFrame->codeBlock()->usesEval())) + return JSValue::encode(jsUndefined()); + + VirtualRegister argumentsRegister = callFrame->codeBlock()->argumentsRegister(); + if (JSValue arguments = callFrame->uncheckedR(argumentsRegister.offset()).jsValue()) + return JSValue::encode(arguments); + int realArgumentsRegister = unmodifiedArgumentsRegister(argumentsRegister).offset(); + + JSValue arguments = JSValue(Arguments::create(callFrame->vm(), callFrame)); + callFrame->uncheckedR(argumentsRegister.offset()) = arguments; + callFrame->uncheckedR(realArgumentsRegister) = arguments; + + ASSERT(callFrame->uncheckedR(realArgumentsRegister).jsValue().inherits(Arguments::info())); + return JSValue::encode(callFrame->uncheckedR(realArgumentsRegister).jsValue()); +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSActivation.h b/Source/JavaScriptCore/runtime/JSActivation.h new file mode 100644 index 000000000..67eafeeeb --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSActivation.h @@ -0,0 +1,208 @@ +/* + * 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 + * 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 JSActivation_h +#define JSActivation_h + +#include "CodeBlock.h" +#include "CopiedSpaceInlines.h" +#include "JSVariableObject.h" +#include "Nodes.h" +#include "SymbolTable.h" + +namespace JSC { + +class Register; + +class JSActivation : public JSVariableObject { +private: + JSActivation(VM&, CallFrame*, Register*, SymbolTable*); + +public: + typedef JSVariableObject Base; + + static JSActivation* create(VM& vm, CallFrame* callFrame, Register* registers, CodeBlock* codeBlock) + { + SymbolTable* symbolTable = codeBlock->symbolTable(); + ASSERT(codeBlock->codeType() == FunctionCode); + JSActivation* activation = new ( + NotNull, + allocateCell<JSActivation>( + vm.heap, + allocationSize(symbolTable) + ) + ) JSActivation(vm, callFrame, registers, symbolTable); + activation->finishCreation(vm); + return activation; + } + + static JSActivation* create(VM& vm, CallFrame* callFrame, CodeBlock* codeBlock) + { + return create(vm, callFrame, callFrame->registers(), codeBlock); + } + + static void visitChildren(JSCell*, SlotVisitor&); + + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + + static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); + + static bool deleteProperty(JSCell*, ExecState*, PropertyName); + + static JSValue toThis(JSCell*, ExecState*, ECMAMode); + + void tearOff(VM&); + + DECLARE_INFO; + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(ActivationObjectType, StructureFlags), info()); } + + WriteBarrierBase<Unknown>& registerAt(int) const; + bool isValidIndex(int) const; + bool isValid(const SymbolTableEntry&) const; + bool isTornOff(); + int registersOffset(); + static int registersOffset(SymbolTable*); + +protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags; + +private: + bool symbolTableGet(PropertyName, PropertySlot&); + bool symbolTableGet(PropertyName, PropertyDescriptor&); + bool symbolTableGet(PropertyName, PropertySlot&, bool& slotIsWriteable); + bool symbolTablePut(ExecState*, PropertyName, JSValue, bool shouldThrow); + bool symbolTablePutWithAttributes(VM&, PropertyName, JSValue, unsigned attributes); + + static EncodedJSValue argumentsGetter(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); + + static size_t allocationSize(SymbolTable*); + static size_t storageOffset(); + + WriteBarrier<Unknown>* storage(); // captureCount() number of registers. +}; + +extern int activationCount; +extern int allTheThingsCount; + +inline JSActivation::JSActivation(VM& vm, CallFrame* callFrame, Register* registers, SymbolTable* symbolTable) + : Base( + vm, + callFrame->lexicalGlobalObject()->activationStructure(), + registers, + callFrame->scope(), + symbolTable) +{ + WriteBarrier<Unknown>* storage = this->storage(); + size_t captureCount = symbolTable->captureCount(); + for (size_t i = 0; i < captureCount; ++i) + new (NotNull, &storage[i]) WriteBarrier<Unknown>; +} + +JSActivation* asActivation(JSValue); + +inline JSActivation* asActivation(JSValue value) +{ + ASSERT(asObject(value)->inherits(JSActivation::info())); + return jsCast<JSActivation*>(asObject(value)); +} + +ALWAYS_INLINE JSActivation* Register::activation() const +{ + return asActivation(jsValue()); +} + +inline int JSActivation::registersOffset(SymbolTable* symbolTable) +{ + return storageOffset() + ((symbolTable->captureCount() - symbolTable->captureStart() - 1) * sizeof(WriteBarrier<Unknown>)); +} + +inline void JSActivation::tearOff(VM& vm) +{ + ASSERT(!isTornOff()); + + 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(vm, this, src[i].get()); + + m_registers = dst; + ASSERT(isTornOff()); +} + +inline bool JSActivation::isTornOff() +{ + return m_registers == reinterpret_cast_ptr<WriteBarrierBase<Unknown>*>( + reinterpret_cast<char*>(this) + registersOffset(symbolTable())); +} + +inline size_t JSActivation::storageOffset() +{ + return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(JSActivation)); +} + +inline WriteBarrier<Unknown>* JSActivation::storage() +{ + return reinterpret_cast_ptr<WriteBarrier<Unknown>*>( + reinterpret_cast<char*>(this) + storageOffset()); +} + +inline size_t JSActivation::allocationSize(SymbolTable* symbolTable) +{ + size_t objectSizeInBytes = WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(JSActivation)); + size_t storageSizeInBytes = symbolTable->captureCount() * sizeof(WriteBarrier<Unknown>); + return objectSizeInBytes + storageSizeInBytes; +} + +inline bool JSActivation::isValidIndex(int index) const +{ + if (index > symbolTable()->captureStart()) + return false; + if (index <= symbolTable()->captureEnd()) + return false; + return true; +} + +inline bool JSActivation::isValid(const SymbolTableEntry& entry) const +{ + return isValidIndex(entry.getIndex()); +} + +inline WriteBarrierBase<Unknown>& JSActivation::registerAt(int index) const +{ + ASSERT(isValidIndex(index)); + return Base::registerAt(index); +} + +} // namespace JSC + +#endif // JSActivation_h diff --git a/Source/JavaScriptCore/runtime/DirectArgumentsOffset.cpp b/Source/JavaScriptCore/runtime/JSArgumentsIterator.cpp index 9fc4c42df..2fcf8815c 100644 --- a/Source/JavaScriptCore/runtime/DirectArgumentsOffset.cpp +++ b/Source/JavaScriptCore/runtime/JSArgumentsIterator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Apple Inc. All rights reserved. + * 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 @@ -24,19 +24,18 @@ */ #include "config.h" -#include "DirectArgumentsOffset.h" +#include "JSArgumentsIterator.h" + +#include "Arguments.h" namespace JSC { -void DirectArgumentsOffset::dump(PrintStream& out) const -{ - if (!*this) { - out.print("capturedArgumentInvalid"); - return; - } +const ClassInfo JSArgumentsIterator::s_info = { "ArgumentsIterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSArgumentsIterator) }; - out.print("capturedArgument", offset()); +void JSArgumentsIterator::finishCreation(VM& vm, Arguments* arguments) +{ + Base::finishCreation(vm); + m_arguments.set(vm, this, arguments); } -} // namespace JSC - +} diff --git a/Source/JavaScriptCore/runtime/JSWeakSet.h b/Source/JavaScriptCore/runtime/JSArgumentsIterator.h index da2ecaa4a..0eed745c9 100644 --- a/Source/JavaScriptCore/runtime/JSWeakSet.h +++ b/Source/JavaScriptCore/runtime/JSArgumentsIterator.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Apple, Inc. All rights reserved. + * 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 @@ -23,16 +23,14 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSWeakSet_h -#define JSWeakSet_h +#ifndef JSArgumentsIterator_h +#define JSArgumentsIterator_h -#include "JSObject.h" +#include "Arguments.h" namespace JSC { -class WeakMapData; - -class JSWeakSet : public JSNonFinalObject { +class JSArgumentsIterator : public JSNonFinalObject { public: typedef JSNonFinalObject Base; @@ -43,39 +41,39 @@ public: return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } - static JSWeakSet* create(VM& vm, Structure* structure) + static JSArgumentsIterator* create(VM& vm, Structure* structure, Arguments* arguments) { - JSWeakSet* instance = new (NotNull, allocateCell<JSWeakSet>(vm.heap)) JSWeakSet(vm, structure); - instance->finishCreation(vm); + JSArgumentsIterator* instance = new (NotNull, allocateCell<JSArgumentsIterator>(vm.heap)) JSArgumentsIterator(vm, structure); + instance->finishCreation(vm, arguments); return instance; } - static JSWeakSet* create(ExecState* exec, Structure* structure) + bool next(CallFrame* callFrame, JSValue& value) { - return create(exec->vm(), structure); + if (m_nextIndex >= m_arguments->length(callFrame)) + return false; + value = m_arguments->tryGetArgument(m_nextIndex++); + if (!value) + value = jsUndefined(); + return true; } - WeakMapData* weakMapData() { return m_weakMapData.get(); } - - JSValue get(CallFrame*, JSObject*); - bool has(CallFrame*, JSObject*); - bool remove(CallFrame*, JSObject*); +private: - void set(CallFrame*, JSObject*, JSValue); - void clear(CallFrame*); + static const unsigned StructureFlags = Base::StructureFlags; -private: - JSWeakSet(VM& vm, Structure* structure) + JSArgumentsIterator(VM& vm, Structure* structure) : Base(vm, structure) + , m_nextIndex(0) { } - void finishCreation(VM&); - static void visitChildren(JSCell*, SlotVisitor&); - - WriteBarrier<WeakMapData> m_weakMapData; + void finishCreation(VM&, Arguments*); + + WriteBarrier<Arguments> m_arguments; + size_t m_nextIndex; }; } -#endif // !defined(JSWeakSet_h) +#endif // !defined(JSArgumentsIterator_h) diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp index 2c5a19ae6..9007b5f7d 100644 --- a/Source/JavaScriptCore/runtime/JSArray.cpp +++ b/Source/JavaScriptCore/runtime/JSArray.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2007, 2008, 2009, 2012, 2013, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2007, 2008, 2009, 2012, 2013 Apple Inc. All rights reserved. * Copyright (C) 2003 Peter Kelly (pmk@post.com) * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) * @@ -27,14 +27,17 @@ #include "ButterflyInlines.h" #include "CachedCall.h" #include "CopiedSpace.h" +#include "CopiedSpaceInlines.h" #include "Error.h" #include "Executable.h" #include "GetterSetter.h" #include "IndexingHeaderInlines.h" -#include "JSCInlines.h" #include "PropertyNameArray.h" #include "Reject.h" +#include <wtf/AVLTree.h> #include <wtf/Assertions.h> +#include <wtf/OwnPtr.h> +#include <Operations.h> using namespace std; using namespace WTF; @@ -43,7 +46,7 @@ namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSArray); -const ClassInfo JSArray::s_info = {"Array", &JSNonFinalObject::s_info, 0, CREATE_METHOD_TABLE(JSArray)}; +const ClassInfo JSArray::s_info = {"Array", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSArray)}; Butterfly* createArrayButterflyInDictionaryIndexingMode( VM& vm, JSCell* intendedOwner, unsigned initialLength) @@ -106,12 +109,11 @@ bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName unsigned newLen = descriptor.value().toUInt32(exec); // d. If newLen is not equal to ToNumber( Desc.[[Value]]), throw a RangeError exception. if (newLen != descriptor.value().toNumber(exec)) { - exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Invalid array length"))); + exec->vm().throwException(exec, createRangeError(exec, "Invalid array length")); return false; } // Based on SameValue check in 8.12.9, this is always okay. - // FIXME: Nothing prevents this from being called on a RuntimeArray, and the length function will always return 0 in that case. if (newLen == array->length()) { if (descriptor.writablePresent()) array->setLengthWritable(exec, descriptor.writable()); @@ -158,10 +160,9 @@ bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName // 4. Else if P is an array index (15.4), then // a. Let index be ToUint32(P). - if (Optional<uint32_t> optionalIndex = parseIndex(propertyName)) { + unsigned index = propertyName.asIndex(); + if (index != PropertyName::NotAnIndex) { // b. Reject if index >= oldLen and oldLenDesc.[[Writable]] is false. - uint32_t index = optionalIndex.value(); - // FIXME: Nothing prevents this from being called on a RuntimeArray, and the length function will always return 0 in that case. if (index >= array->length() && !array->isLengthWritable()) return reject(exec, throwException, "Attempting to define numeric property on array with non-writable length property."); // c. Let succeeded be the result of calling the default [[DefineOwnProperty]] internal method (8.12.9) on A passing P, Desc, and false as arguments. @@ -227,7 +228,7 @@ void JSArray::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, Pro { JSArray* thisObject = jsCast<JSArray*>(object); - if (mode.includeDontEnumProperties()) + if (mode == IncludeDontEnumProperties) propertyNames.add(exec->propertyNames().length); JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode); @@ -238,8 +239,8 @@ bool JSArray::unshiftCountSlowCase(VM& vm, bool addToFront, unsigned count) { ArrayStorage* storage = ensureArrayStorage(vm); Butterfly* butterfly = storage->butterfly(); - unsigned propertyCapacity = structure(vm)->outOfLineCapacity(); - unsigned propertySize = structure(vm)->outOfLineSize(); + unsigned propertyCapacity = structure()->outOfLineCapacity(); + unsigned propertySize = structure()->outOfLineSize(); // If not, we should have handled this on the fast path. ASSERT(!addToFront || count > storage->m_indexBias); @@ -273,7 +274,7 @@ bool JSArray::unshiftCountSlowCase(VM& vm, bool addToFront, unsigned count) unsigned newStorageCapacity; // If the current storage array is sufficiently large (but not too large!) then just keep using it. if (currentCapacity > desiredCapacity && isDenseEnoughForVector(currentCapacity, requiredVectorLength)) { - newAllocBase = butterfly->base(structure(vm)); + newAllocBase = butterfly->base(structure()); newStorageCapacity = currentCapacity; } else { size_t newSize = Butterfly::totalSize(0, propertyCapacity, true, ArrayStorage::sizeFor(desiredCapacity)); @@ -297,7 +298,7 @@ bool JSArray::unshiftCountSlowCase(VM& vm, bool addToFront, unsigned count) // Atomic decay, + the post-capacity cannot be greater than what is available. postCapacity = min((storage->vectorLength() - length) >> 1, newStorageCapacity - requiredVectorLength); // If we're moving contents within the same allocation, the post-capacity is being reduced. - ASSERT(newAllocBase != butterfly->base(structure(vm)) || postCapacity < storage->vectorLength() - length); + ASSERT(newAllocBase != butterfly->base(structure()) || postCapacity < storage->vectorLength() - length); } unsigned newVectorLength = requiredVectorLength + postCapacity; @@ -309,7 +310,7 @@ bool JSArray::unshiftCountSlowCase(VM& vm, bool addToFront, unsigned count) ASSERT(count + usedVectorLength <= newVectorLength); memmove(newButterfly->arrayStorage()->m_vector + count, storage->m_vector, sizeof(JSValue) * usedVectorLength); memmove(newButterfly->propertyStorage() - propertySize, butterfly->propertyStorage() - propertySize, sizeof(JSValue) * propertySize + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0)); - } else if ((newAllocBase != butterfly->base(structure(vm))) || (newIndexBias != storage->m_indexBias)) { + } else if ((newAllocBase != butterfly->base(structure())) || (newIndexBias != storage->m_indexBias)) { memmove(newButterfly->propertyStorage() - propertySize, butterfly->propertyStorage() - propertySize, sizeof(JSValue) * propertySize + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0)); memmove(newButterfly->arrayStorage()->m_vector, storage->m_vector, sizeof(JSValue) * usedVectorLength); @@ -378,7 +379,7 @@ bool JSArray::setLengthWithArrayStorage(ExecState* exec, unsigned newLength, boo unsigned usedVectorLength = min(length, storage->vectorLength()); for (unsigned i = newLength; i < usedVectorLength; ++i) { WriteBarrier<Unknown>& valueSlot = storage->m_vector[i]; - bool hadValue = !!valueSlot; + bool hadValue = valueSlot; valueSlot.clear(); storage->m_numValuesInVector -= hadValue; } @@ -391,7 +392,7 @@ bool JSArray::setLengthWithArrayStorage(ExecState* exec, unsigned newLength, boo bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException) { - switch (indexingType()) { + switch (structure()->indexingType()) { case ArrayClass: if (!newLength) return true; @@ -406,7 +407,7 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException case ArrayWithUndecided: case ArrayWithInt32: case ArrayWithDouble: - case ArrayWithContiguous: { + case ArrayWithContiguous: if (newLength == m_butterfly->publicLength()) return true; if (newLength >= MAX_ARRAY_INDEX // This case ensures that we can do fast push. @@ -420,24 +421,15 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException ensureLength(exec->vm(), newLength); return true; } - - unsigned lengthToClear = m_butterfly->publicLength() - newLength; - unsigned costToAllocateNewButterfly = 64; // a heuristic. - if (lengthToClear > newLength && lengthToClear > costToAllocateNewButterfly) { - reallocateAndShrinkButterfly(exec->vm(), newLength); - return true; - } - - if (indexingType() == ArrayWithDouble) { + if (structure()->indexingType() == ArrayWithDouble) { for (unsigned i = m_butterfly->publicLength(); i-- > newLength;) - m_butterfly->contiguousDouble()[i] = PNaN; + m_butterfly->contiguousDouble()[i] = QNaN; } else { for (unsigned i = m_butterfly->publicLength(); i-- > newLength;) m_butterfly->contiguous()[i].clear(); } m_butterfly->setPublicLength(newLength); return true; - } case ArrayWithArrayStorage: case ArrayWithSlowPutArrayStorage: @@ -451,7 +443,7 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException JSValue JSArray::pop(ExecState* exec) { - switch (indexingType()) { + switch (structure()->indexingType()) { case ArrayClass: return jsUndefined(); @@ -487,7 +479,7 @@ JSValue JSArray::pop(ExecState* exec) RELEASE_ASSERT(length < m_butterfly->vectorLength()); double value = m_butterfly->contiguousDouble()[length]; if (value == value) { - m_butterfly->contiguousDouble()[length] = PNaN; + m_butterfly->contiguousDouble()[length] = QNaN; m_butterfly->setPublicLength(length); return JSValue(JSValue::EncodeAsDouble, value); } @@ -532,7 +524,7 @@ JSValue JSArray::pop(ExecState* exec) return jsUndefined(); // Call the [[Delete]] internal method of O with arguments indx and true. if (!deletePropertyByIndex(this, exec, index)) { - throwTypeError(exec, ASCIILiteral("Unable to delete property.")); + throwTypeError(exec, "Unable to delete property."); return jsUndefined(); } // Call the [[Put]] internal method of O with arguments "length", indx, and true. @@ -546,7 +538,7 @@ JSValue JSArray::pop(ExecState* exec) // - pushing to an array of length 2^32-1 stores the property, but throws a range error. void JSArray::push(ExecState* exec, JSValue value) { - switch (indexingType()) { + switch (structure()->indexingType()) { case ArrayClass: { createInitialUndecided(exec->vm(), 0); FALLTHROUGH; @@ -574,9 +566,9 @@ void JSArray::push(ExecState* exec, JSValue value) } if (length > MAX_ARRAY_INDEX) { - methodTable(exec->vm())->putByIndex(this, exec, length, value, true); + methodTable()->putByIndex(this, exec, length, value, true); if (!exec->hadException()) - exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Invalid array length"))); + exec->vm().throwException(exec, createRangeError(exec, "Invalid array length")); return; } @@ -594,9 +586,9 @@ void JSArray::push(ExecState* exec, JSValue value) } if (length > MAX_ARRAY_INDEX) { - methodTable(exec->vm())->putByIndex(this, exec, length, value, true); + methodTable()->putByIndex(this, exec, length, value, true); if (!exec->hadException()) - exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Invalid array length"))); + exec->vm().throwException(exec, createRangeError(exec, "Invalid array length")); return; } @@ -626,9 +618,9 @@ void JSArray::push(ExecState* exec, JSValue value) } if (length > MAX_ARRAY_INDEX) { - methodTable(exec->vm())->putByIndex(this, exec, length, value, true); + methodTable()->putByIndex(this, exec, length, value, true); if (!exec->hadException()) - exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Invalid array length"))); + exec->vm().throwException(exec, createRangeError(exec, "Invalid array length")); return; } @@ -660,10 +652,10 @@ void JSArray::push(ExecState* exec, JSValue value) // Pushing to an array of invalid length (2^31-1) stores the property, but throws a range error. if (storage->length() > MAX_ARRAY_INDEX) { - methodTable(exec->vm())->putByIndex(this, exec, storage->length(), value, true); + methodTable()->putByIndex(this, exec, storage->length(), value, true); // Per ES5.1 15.4.4.7 step 6 & 15.4.5.1 step 3.d. if (!exec->hadException()) - exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Invalid array length"))); + exec->vm().throwException(exec, createRangeError(exec, "Invalid array length")); return; } @@ -677,80 +669,15 @@ void JSArray::push(ExecState* exec, JSValue value) } } -JSArray* JSArray::fastSlice(ExecState& exec, unsigned startIndex, unsigned count) -{ - auto arrayType = indexingType(); - switch (arrayType) { - case ArrayWithDouble: - case ArrayWithInt32: - case ArrayWithContiguous: { - VM& vm = exec.vm(); - if (count >= MIN_SPARSE_ARRAY_INDEX || structure(vm)->holesMustForwardToPrototype(vm)) - return nullptr; - - Structure* resultStructure = exec.lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(arrayType); - JSArray* resultArray = JSArray::tryCreateUninitialized(vm, resultStructure, count); - if (!resultArray) - return nullptr; - - auto& resultButterfly = *resultArray->butterfly(); - if (arrayType == ArrayWithDouble) - memcpy(resultButterfly.contiguousDouble().data(), m_butterfly->contiguousDouble().data() + startIndex, sizeof(JSValue) * count); - else - memcpy(resultButterfly.contiguous().data(), m_butterfly->contiguous().data() + startIndex, sizeof(JSValue) * count); - resultButterfly.setPublicLength(count); - - return resultArray; - } - default: - return nullptr; - } -} - -EncodedJSValue JSArray::fastConcatWith(ExecState& exec, JSArray& otherArray) -{ - auto newArrayType = indexingType(); - - VM& vm = exec.vm(); - ASSERT(newArrayType == fastConcatType(vm, *this, otherArray)); - - unsigned thisArraySize = m_butterfly->publicLength(); - unsigned otherArraySize = otherArray.m_butterfly->publicLength(); - ASSERT(thisArraySize + otherArraySize < MIN_SPARSE_ARRAY_INDEX); - - Structure* resultStructure = exec.lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(newArrayType); - JSArray* resultArray = JSArray::tryCreateUninitialized(vm, resultStructure, thisArraySize + otherArraySize); - if (!resultArray) - return JSValue::encode(throwOutOfMemoryError(&exec)); - - auto& resultButterfly = *resultArray->butterfly(); - auto& otherButterfly = *otherArray.butterfly(); - if (newArrayType == ArrayWithDouble) { - auto buffer = resultButterfly.contiguousDouble().data(); - memcpy(buffer, m_butterfly->contiguousDouble().data(), sizeof(JSValue) * thisArraySize); - memcpy(buffer + thisArraySize, otherButterfly.contiguousDouble().data(), sizeof(JSValue) * otherArraySize); - } else { - auto buffer = resultButterfly.contiguous().data(); - memcpy(buffer, m_butterfly->contiguous().data(), sizeof(JSValue) * thisArraySize); - memcpy(buffer + thisArraySize, otherButterfly.contiguous().data(), sizeof(JSValue) * otherArraySize); - } - - resultButterfly.setPublicLength(thisArraySize + otherArraySize); - return JSValue::encode(resultArray); -} - -bool JSArray::shiftCountWithArrayStorage(VM& vm, unsigned startIndex, unsigned count, ArrayStorage* storage) +bool JSArray::shiftCountWithArrayStorage(unsigned startIndex, unsigned count, ArrayStorage* storage) { unsigned oldLength = storage->length(); RELEASE_ASSERT(count <= oldLength); // If the array contains holes or is otherwise in an abnormal state, // use the generic algorithm in ArrayPrototype. - if ((storage->hasHoles() && this->structure(vm)->holesMustForwardToPrototype(vm)) - || hasSparseMap() - || shouldUseSlowPut(indexingType())) { + if (oldLength != storage->m_numValuesInVector || inSparseIndexingMode() || shouldUseSlowPut(structure()->indexingType())) return false; - } if (!oldLength) return true; @@ -784,22 +711,10 @@ bool JSArray::shiftCountWithArrayStorage(VM& vm, unsigned startIndex, unsigned c // after the shift region, so we move the elements before to the right. if (numElementsBeforeShiftRegion) { RELEASE_ASSERT(count + startIndex <= vectorLength); - if (storage->hasHoles()) { - for (unsigned i = startIndex; i-- > 0;) { - unsigned destinationIndex = count + i; - JSValue source = storage->m_vector[i].get(); - JSValue dest = storage->m_vector[destinationIndex].get(); - // Any time we overwrite a hole we know we overcounted the number of values we removed - // when we subtracted count from m_numValuesInVector above. - if (!dest && destinationIndex >= firstIndexAfterShiftRegion) - storage->m_numValuesInVector++; - storage->m_vector[count + i].setWithoutWriteBarrier(source); - } - } else { - memmove(storage->m_vector + count, - storage->m_vector, - sizeof(JSValue) * startIndex); - } + memmove( + storage->m_vector + count, + storage->m_vector, + sizeof(JSValue) * startIndex); } // Adjust the Butterfly and the index bias. We only need to do this here because we're changing // the start of the Butterfly, which needs to point at the first indexed property in the used @@ -814,22 +729,10 @@ bool JSArray::shiftCountWithArrayStorage(VM& vm, unsigned startIndex, unsigned c } else { // The number of elements before the shift region is greater than or equal to the number // of elements after the shift region, so we move the elements after the shift region to the left. - if (storage->hasHoles()) { - for (unsigned i = 0; i < numElementsAfterShiftRegion; ++i) { - unsigned destinationIndex = startIndex + i; - JSValue source = storage->m_vector[firstIndexAfterShiftRegion + i].get(); - JSValue dest = storage->m_vector[destinationIndex].get(); - // Any time we overwrite a hole we know we overcounted the number of values we removed - // when we subtracted count from m_numValuesInVector above. - if (!dest && destinationIndex < firstIndexAfterShiftRegion) - storage->m_numValuesInVector++; - storage->m_vector[startIndex + i].setWithoutWriteBarrier(source); - } - } else { - memmove(storage->m_vector + startIndex, - storage->m_vector + firstIndexAfterShiftRegion, - sizeof(JSValue) * numElementsAfterShiftRegion); - } + memmove( + storage->m_vector + startIndex, + storage->m_vector + firstIndexAfterShiftRegion, + sizeof(JSValue) * numElementsAfterShiftRegion); // Clear the slots of the elements we just moved. unsigned startOfEmptyVectorTail = usedVectorLength - count; for (unsigned i = startOfEmptyVectorTail; i < usedVectorLength; ++i) @@ -843,12 +746,11 @@ bool JSArray::shiftCountWithArrayStorage(VM& vm, unsigned startIndex, unsigned c return true; } -bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned& startIndex, unsigned count) +bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex, unsigned count) { - VM& vm = exec->vm(); RELEASE_ASSERT(count > 0); - switch (indexingType()) { + switch (structure()->indexingType()) { case ArrayClass: return true; @@ -864,28 +766,27 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned& startInde // 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(vm, startIndex, count, ensureArrayStorage(vm)); + return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm())); // Storing to a hole is fine since we're still having a good time. But reading from a hole // is totally not fine, since we might have to read from the proto chain. // We have to check for holes before we start moving things around so that we don't get halfway // through shifting and then realize we should have been in ArrayStorage mode. unsigned end = oldLength - count; - if (this->structure(vm)->holesMustForwardToPrototype(vm)) { - for (unsigned i = startIndex; i < end; ++i) { - JSValue v = m_butterfly->contiguous()[i + count].get(); - if (UNLIKELY(!v)) { - startIndex = i; - return shiftCountWithArrayStorage(vm, startIndex, count, ensureArrayStorage(vm)); - } - m_butterfly->contiguous()[i].setWithoutWriteBarrier(v); - } - } else { - memmove(m_butterfly->contiguous().data() + startIndex, - m_butterfly->contiguous().data() + startIndex + count, - sizeof(JSValue) * (end - startIndex)); + for (unsigned i = startIndex; i < end; ++i) { + JSValue v = m_butterfly->contiguous()[i + count].get(); + if (UNLIKELY(!v)) + return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm())); } + for (unsigned i = startIndex; i < end; ++i) { + JSValue v = m_butterfly->contiguous()[i + count].get(); + ASSERT(v); + // No need for a barrier since we're just moving data around in the same vector. + // This is in line with our standing assumption that we won't have a deletion + // barrier. + m_butterfly->contiguous()[i].setWithoutWriteBarrier(v); + } for (unsigned i = end; i < oldLength; ++i) m_butterfly->contiguous()[i].clear(); @@ -900,29 +801,29 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned& startInde // 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(vm, startIndex, count, ensureArrayStorage(vm)); + return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm())); // Storing to a hole is fine since we're still having a good time. But reading from a hole // is totally not fine, since we might have to read from the proto chain. // We have to check for holes before we start moving things around so that we don't get halfway // through shifting and then realize we should have been in ArrayStorage mode. unsigned end = oldLength - count; - if (this->structure(vm)->holesMustForwardToPrototype(vm)) { - for (unsigned i = startIndex; i < end; ++i) { - double v = m_butterfly->contiguousDouble()[i + count]; - if (UNLIKELY(v != v)) { - startIndex = i; - return shiftCountWithArrayStorage(vm, startIndex, count, ensureArrayStorage(vm)); - } - m_butterfly->contiguousDouble()[i] = v; - } - } else { - memmove(m_butterfly->contiguousDouble().data() + startIndex, - m_butterfly->contiguousDouble().data() + startIndex + count, - sizeof(JSValue) * (end - startIndex)); + for (unsigned i = startIndex; i < end; ++i) { + double v = m_butterfly->contiguousDouble()[i + count]; + if (UNLIKELY(v != v)) + return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm())); + } + + for (unsigned i = startIndex; i < end; ++i) { + double v = m_butterfly->contiguousDouble()[i + count]; + ASSERT(v == v); + // No need for a barrier since we're just moving data around in the same vector. + // This is in line with our standing assumption that we won't have a deletion + // barrier. + m_butterfly->contiguousDouble()[i] = v; } for (unsigned i = end; i < oldLength; ++i) - m_butterfly->contiguousDouble()[i] = PNaN; + m_butterfly->contiguousDouble()[i] = QNaN; m_butterfly->setPublicLength(oldLength - count); return true; @@ -930,7 +831,7 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned& startInde case ArrayWithArrayStorage: case ArrayWithSlowPutArrayStorage: - return shiftCountWithArrayStorage(vm, startIndex, count, arrayStorage()); + return shiftCountWithArrayStorage(startIndex, count, arrayStorage()); default: CRASH(); @@ -947,7 +848,7 @@ bool JSArray::unshiftCountWithArrayStorage(ExecState* exec, unsigned startIndex, // If the array contains holes or is otherwise in an abnormal state, // use the generic algorithm in ArrayPrototype. - if (storage->hasHoles() || storage->inSparseMode() || shouldUseSlowPut(indexingType())) + if (length != storage->m_numValuesInVector || storage->inSparseMode() || shouldUseSlowPut(structure()->indexingType())) return false; bool moveFront = !startIndex || startIndex < length / 2; @@ -985,7 +886,7 @@ bool JSArray::unshiftCountWithArrayStorage(ExecState* exec, unsigned startIndex, bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex, unsigned count) { - switch (indexingType()) { + switch (structure()->indexingType()) { case ArrayClass: case ArrayWithUndecided: // We could handle this. But it shouldn't ever come up, so we won't. @@ -1066,13 +967,526 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd } } +static int compareNumbersForQSortWithInt32(const void* a, const void* b) +{ + int32_t ia = static_cast<const JSValue*>(a)->asInt32(); + int32_t ib = static_cast<const JSValue*>(b)->asInt32(); + return ia - ib; +} + +static int compareNumbersForQSortWithDouble(const void* a, const void* b) +{ + double da = *static_cast<const double*>(a); + double db = *static_cast<const double*>(b); + return (da > db) - (da < db); +} + +static int compareNumbersForQSort(const void* a, const void* b) +{ + double da = static_cast<const JSValue*>(a)->asNumber(); + double db = static_cast<const JSValue*>(b)->asNumber(); + return (da > db) - (da < db); +} + +static int compareByStringPairForQSort(const void* a, const void* b) +{ + const ValueStringPair* va = static_cast<const ValueStringPair*>(a); + const ValueStringPair* vb = static_cast<const ValueStringPair*>(b); + return codePointCompare(va->second, vb->second); +} + +template<IndexingType indexingType> +void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData) +{ + ASSERT(indexingType == ArrayWithInt32 || indexingType == ArrayWithDouble || indexingType == ArrayWithContiguous || indexingType == ArrayWithArrayStorage); + + unsigned lengthNotIncludingUndefined; + unsigned newRelevantLength; + compactForSorting<indexingType>( + lengthNotIncludingUndefined, + newRelevantLength); + + ContiguousJSValues data = indexingData<indexingType>(); + + if (indexingType == ArrayWithArrayStorage && arrayStorage()->m_sparseMap.get()) { + throwOutOfMemoryError(exec); + return; + } + + if (!lengthNotIncludingUndefined) + return; + + bool allValuesAreNumbers = true; + switch (indexingType) { + case ArrayWithInt32: + case ArrayWithDouble: + break; + + default: + for (size_t i = 0; i < newRelevantLength; ++i) { + if (!data[i].isNumber()) { + allValuesAreNumbers = false; + break; + } + } + break; + } + + if (!allValuesAreNumbers) + return sort(exec, compareFunction, callType, callData); + + // For numeric comparison, which is fast, qsort is faster than mergesort. We + // also don't require mergesort's stability, since there's no user visible + // side-effect from swapping the order of equal primitive values. + int (*compare)(const void*, const void*); + switch (indexingType) { + case ArrayWithInt32: + compare = compareNumbersForQSortWithInt32; + break; + + case ArrayWithDouble: + compare = compareNumbersForQSortWithDouble; + ASSERT(sizeof(WriteBarrier<Unknown>) == sizeof(double)); + break; + + default: + compare = compareNumbersForQSort; + break; + } + ASSERT(data.length() >= newRelevantLength); + qsort(data.data(), newRelevantLength, sizeof(WriteBarrier<Unknown>), compare); + return; +} + +void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData) +{ + ASSERT(!inSparseIndexingMode()); + + switch (structure()->indexingType()) { + case ArrayClass: + return; + + case ArrayWithInt32: + sortNumericVector<ArrayWithInt32>(exec, compareFunction, callType, callData); + break; + + case ArrayWithDouble: + sortNumericVector<ArrayWithDouble>(exec, compareFunction, callType, callData); + break; + + case ArrayWithContiguous: + sortNumericVector<ArrayWithContiguous>(exec, compareFunction, callType, callData); + return; + + case ArrayWithArrayStorage: + sortNumericVector<ArrayWithArrayStorage>(exec, compareFunction, callType, callData); + return; + + default: + CRASH(); + return; + } +} + +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; + + 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, 0, UnsafeVectorOverflow> values(relevantLength); + if (!values.begin()) { + throwOutOfMemoryError(exec); + return; + } + + Heap::heap(this)->pushTempSortVector(&values); + + bool isSortingPrimitiveValues = true; + + 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(); + } + + // FIXME: The following loop continues to call toString on subsequent values even after + // a toString call raises an exception. + + for (size_t i = 0; i < relevantLength; i++) + values[i].second = values[i].first.toWTFStringInline(exec); + + if (exec->hadException()) { + Heap::heap(this)->popTempSortVector(&values); + return; + } + + // FIXME: Since we sort by string value, a fast algorithm might be to use a radix sort. That would be O(N) rather + // than O(N log N). + +#if HAVE(MERGESORT) + if (isSortingPrimitiveValues) + qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort); + else + mergesort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort); +#else + // FIXME: The qsort library function is likely to not be a stable sort. + // ECMAScript-262 does not specify a stable sort, but in practice, browsers perform a stable sort. + qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort); +#endif + + // If the toString function changed the length of the array or vector storage, + // increase the length to handle the orignal number of actual values. + switch (indexingType) { + case ArrayWithInt32: + case ArrayWithDouble: + case ArrayWithContiguous: + ensureLength(vm, relevantLength); + break; + + case ArrayWithArrayStorage: + if (arrayStorage()->vectorLength() < relevantLength) { + increaseVectorLength(exec->vm(), relevantLength); + ContiguousTypeAccessor<indexingType>::replaceDataReference(&data, arrayStorage()->vector()); + } + if (arrayStorage()->length() < relevantLength) + arrayStorage()->setLength(relevantLength); + break; + + default: + CRASH(); + } + + for (size_t i = 0; i < relevantLength; i++) + ContiguousTypeAccessor<indexingType>::setWithValue(vm, this, data, i, values[i].first); + + Heap::heap(this)->popTempSortVector(&values); +} + +void JSArray::sort(ExecState* exec) +{ + ASSERT(!inSparseIndexingMode()); + + switch (structure()->indexingType()) { + case ArrayClass: + case ArrayWithUndecided: + return; + + case ArrayWithInt32: { + unsigned lengthNotIncludingUndefined; + unsigned newRelevantLength; + compactForSorting<ArrayWithInt32>( + lengthNotIncludingUndefined, newRelevantLength); + + sortCompactedVector<ArrayWithInt32>( + exec, m_butterfly->contiguousInt32(), lengthNotIncludingUndefined); + return; + } + + case ArrayWithDouble: { + unsigned lengthNotIncludingUndefined; + unsigned newRelevantLength; + compactForSorting<ArrayWithDouble>( + lengthNotIncludingUndefined, newRelevantLength); + + sortCompactedVector<ArrayWithDouble>( + exec, m_butterfly->contiguousDouble(), lengthNotIncludingUndefined); + return; + } + + case ArrayWithContiguous: { + unsigned lengthNotIncludingUndefined; + unsigned newRelevantLength; + compactForSorting<ArrayWithContiguous>( + lengthNotIncludingUndefined, newRelevantLength); + + sortCompactedVector<ArrayWithContiguous>( + exec, m_butterfly->contiguous(), lengthNotIncludingUndefined); + return; + } + + case ArrayWithArrayStorage: { + unsigned lengthNotIncludingUndefined; + unsigned newRelevantLength; + compactForSorting<ArrayWithArrayStorage>( + lengthNotIncludingUndefined, newRelevantLength); + ArrayStorage* storage = m_butterfly->arrayStorage(); + ASSERT(!storage->m_sparseMap); + + sortCompactedVector<ArrayWithArrayStorage>(exec, storage->vector(), lengthNotIncludingUndefined); + return; + } + + default: + RELEASE_ASSERT_NOT_REACHED(); + } +} + +struct AVLTreeNodeForArrayCompare { + JSValue value; + + // Child pointers. The high bit of gt is robbed and used as the + // balance factor sign. The high bit of lt is robbed and used as + // the magnitude of the balance factor. + int32_t gt; + int32_t lt; +}; + +struct AVLTreeAbstractorForArrayCompare { + typedef int32_t handle; // Handle is an index into m_nodes vector. + typedef JSValue key; + typedef int32_t size; + + Vector<AVLTreeNodeForArrayCompare, 0, UnsafeVectorOverflow> m_nodes; + ExecState* m_exec; + JSValue m_compareFunction; + CallType m_compareCallType; + const CallData* m_compareCallData; + OwnPtr<CachedCall> m_cachedCall; + + handle get_less(handle h) { return m_nodes[h].lt & 0x7FFFFFFF; } + void set_less(handle h, handle lh) { m_nodes[h].lt &= 0x80000000; m_nodes[h].lt |= lh; } + handle get_greater(handle h) { return m_nodes[h].gt & 0x7FFFFFFF; } + void set_greater(handle h, handle gh) { m_nodes[h].gt &= 0x80000000; m_nodes[h].gt |= gh; } + + int get_balance_factor(handle h) + { + if (m_nodes[h].gt & 0x80000000) + return -1; + return static_cast<unsigned>(m_nodes[h].lt) >> 31; + } + + void set_balance_factor(handle h, int bf) + { + if (bf == 0) { + m_nodes[h].lt &= 0x7FFFFFFF; + m_nodes[h].gt &= 0x7FFFFFFF; + } else { + m_nodes[h].lt |= 0x80000000; + if (bf < 0) + m_nodes[h].gt |= 0x80000000; + else + m_nodes[h].gt &= 0x7FFFFFFF; + } + } + + int compare_key_key(key va, key vb) + { + ASSERT(!va.isUndefined()); + ASSERT(!vb.isUndefined()); + + if (m_exec->hadException()) + return 1; + + double compareResult; + if (m_cachedCall) { + m_cachedCall->setThis(jsUndefined()); + m_cachedCall->setArgument(0, va); + m_cachedCall->setArgument(1, vb); + compareResult = m_cachedCall->call().toNumber(m_exec); + } else { + MarkedArgumentBuffer arguments; + arguments.append(va); + arguments.append(vb); + compareResult = call(m_exec, m_compareFunction, m_compareCallType, *m_compareCallData, jsUndefined(), arguments).toNumber(m_exec); + } + return (compareResult < 0) ? -1 : 1; // Not passing equality through, because we need to store all values, even if equivalent. + } + + int compare_key_node(key k, handle h) { return compare_key_key(k, m_nodes[h].value); } + int compare_node_node(handle h1, handle h2) { return compare_key_key(m_nodes[h1].value, m_nodes[h2].value); } + + static handle null() { return 0x7FFFFFFF; } +}; + +template<IndexingType indexingType> +void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData) +{ + ASSERT(!inSparseIndexingMode()); + ASSERT(indexingType == structure()->indexingType()); + + // FIXME: This ignores exceptions raised in the compare function or in toNumber. + + // The maximum tree depth is compiled in - but the caller is clearly up to no good + // if a larger array is passed. + ASSERT(m_butterfly->publicLength() <= static_cast<unsigned>(std::numeric_limits<int>::max())); + if (m_butterfly->publicLength() > static_cast<unsigned>(std::numeric_limits<int>::max())) + return; + + unsigned usedVectorLength = relevantLength<indexingType>(); + unsigned nodeCount = usedVectorLength; + + if (!nodeCount) + return; + + AVLTree<AVLTreeAbstractorForArrayCompare, 44> tree; // Depth 44 is enough for 2^31 items + tree.abstractor().m_exec = exec; + tree.abstractor().m_compareFunction = compareFunction; + tree.abstractor().m_compareCallType = callType; + tree.abstractor().m_compareCallData = &callData; + tree.abstractor().m_nodes.grow(nodeCount); + + if (callType == CallTypeJS) + tree.abstractor().m_cachedCall = adoptPtr(new CachedCall(exec, jsCast<JSFunction*>(compareFunction), 2)); + + if (!tree.abstractor().m_nodes.begin()) { + throwOutOfMemoryError(exec); + return; + } + + // FIXME: If the compare function modifies the array, the vector, map, etc. could be modified + // right out from under us while we're building the tree here. + + unsigned numDefined = 0; + unsigned numUndefined = 0; + + // Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree. + for (; numDefined < usedVectorLength; ++numDefined) { + if (numDefined >= m_butterfly->vectorLength()) + break; + JSValue v = getHolyIndexQuickly(numDefined); + if (!v || v.isUndefined()) + break; + tree.abstractor().m_nodes[numDefined].value = v; + tree.insert(numDefined); + } + for (unsigned i = numDefined; i < usedVectorLength; ++i) { + if (i >= m_butterfly->vectorLength()) + break; + JSValue v = getHolyIndexQuickly(i); + if (v) { + if (v.isUndefined()) + ++numUndefined; + else { + tree.abstractor().m_nodes[numDefined].value = v; + tree.insert(numDefined); + ++numDefined; + } + } + } + + unsigned newUsedVectorLength = numDefined + numUndefined; + + // The array size may have changed. Figure out the new bounds. + unsigned newestUsedVectorLength = currentRelevantLength(); + + unsigned elementsToExtractThreshold = min(min(newestUsedVectorLength, numDefined), static_cast<unsigned>(tree.abstractor().m_nodes.size())); + unsigned undefinedElementsThreshold = min(newestUsedVectorLength, newUsedVectorLength); + unsigned clearElementsThreshold = min(newestUsedVectorLength, usedVectorLength); + + // Copy the values back into m_storage. + AVLTree<AVLTreeAbstractorForArrayCompare, 44>::Iterator iter; + iter.start_iter_least(tree); + 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(vm, this, tree.abstractor().m_nodes[*iter].value); + ++iter; + } + // Put undefined values back in. + switch (structure()->indexingType()) { + case ArrayWithInt32: + case ArrayWithDouble: + ASSERT(elementsToExtractThreshold == undefinedElementsThreshold); + break; + + default: + for (unsigned i = elementsToExtractThreshold; i < undefinedElementsThreshold; ++i) { + ASSERT(i < butterfly()->vectorLength()); + currentIndexingData()[i].setUndefined(); + } + } + + // Ensure that unused values in the vector are zeroed out. + for (unsigned i = undefinedElementsThreshold; i < clearElementsThreshold; ++i) { + ASSERT(i < butterfly()->vectorLength()); + if (structure()->indexingType() == ArrayWithDouble) + butterfly()->contiguousDouble()[i] = QNaN; + else + currentIndexingData()[i].clear(); + } + + if (hasArrayStorage(structure()->indexingType())) + arrayStorage()->m_numValuesInVector = newUsedVectorLength; +} + +void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData) +{ + ASSERT(!inSparseIndexingMode()); + + switch (structure()->indexingType()) { + case ArrayClass: + case ArrayWithUndecided: + return; + + case ArrayWithInt32: + sortVector<ArrayWithInt32>(exec, compareFunction, callType, callData); + return; + + case ArrayWithDouble: + sortVector<ArrayWithDouble>(exec, compareFunction, callType, callData); + return; + + case ArrayWithContiguous: + sortVector<ArrayWithContiguous>(exec, compareFunction, callType, callData); + return; + + case ArrayWithArrayStorage: + sortVector<ArrayWithArrayStorage>(exec, compareFunction, callType, callData); + return; + + default: + RELEASE_ASSERT_NOT_REACHED(); + } +} + void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args) { unsigned i = 0; unsigned vectorEnd; WriteBarrier<Unknown>* vector; - switch (indexingType()) { + switch (structure()->indexingType()) { case ArrayClass: return; @@ -1111,11 +1525,9 @@ void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args) default: CRASH(); -#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE) vector = 0; vectorEnd = 0; break; -#endif } for (; i < vectorEnd; ++i) { @@ -1124,23 +1536,19 @@ void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args) break; args.append(v.get()); } - - // FIXME: What prevents this from being called with a RuntimeArray? The length function will always return 0 in that case. + for (; i < length(); ++i) args.append(get(exec, i)); } -void JSArray::copyToArguments(ExecState* exec, VirtualRegister firstElementDest, unsigned offset, unsigned length) +void JSArray::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t length) { - unsigned i = offset; + unsigned i = 0; WriteBarrier<Unknown>* vector; unsigned vectorEnd; - length += offset; // We like to think of the length as being our length, rather than the output length. - - // FIXME: What prevents this from being called with a RuntimeArray? The length function will always return 0 in that case. + ASSERT(length == this->length()); - - switch (indexingType()) { + switch (structure()->indexingType()) { case ArrayClass: return; @@ -1165,7 +1573,7 @@ void JSArray::copyToArguments(ExecState* exec, VirtualRegister firstElementDest, double v = m_butterfly->contiguousDouble()[i]; if (v != v) break; - exec->r(firstElementDest + i - offset) = JSValue(JSValue::EncodeAsDouble, v); + callFrame->setArgument(i, JSValue(JSValue::EncodeAsDouble, v)); } break; } @@ -1179,25 +1587,111 @@ void JSArray::copyToArguments(ExecState* exec, VirtualRegister firstElementDest, default: CRASH(); -#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE) vector = 0; vectorEnd = 0; break; -#endif } for (; i < vectorEnd; ++i) { WriteBarrier<Unknown>& v = vector[i]; if (!v) break; - exec->r(firstElementDest + i - offset) = v.get(); + callFrame->setArgument(i, v.get()); } - for (; i < length; ++i) { - exec->r(firstElementDest + i - offset) = get(exec, i); - if (UNLIKELY(exec->vm().exception())) - return; + for (; i < length; ++i) + callFrame->setArgument(i, get(exec, i)); +} + +template<IndexingType indexingType> +void JSArray::compactForSorting(unsigned& numDefined, unsigned& newRelevantLength) +{ + ASSERT(!inSparseIndexingMode()); + ASSERT(indexingType == structure()->indexingType()); + + unsigned myRelevantLength = relevantLength<indexingType>(); + + numDefined = 0; + unsigned numUndefined = 0; + + for (; numDefined < myRelevantLength; ++numDefined) { + ASSERT(numDefined < m_butterfly->vectorLength()); + if (indexingType == ArrayWithInt32) { + JSValue v = m_butterfly->contiguousInt32()[numDefined].get(); + if (!v) + break; + ASSERT(v.isInt32()); + continue; + } + if (indexingType == ArrayWithDouble) { + double v = m_butterfly->contiguousDouble()[numDefined]; + if (v != v) + break; + continue; + } + JSValue v = indexingData<indexingType>()[numDefined].get(); + if (!v || v.isUndefined()) + break; + } + + for (unsigned i = numDefined; i < myRelevantLength; ++i) { + ASSERT(i < m_butterfly->vectorLength()); + if (indexingType == ArrayWithInt32) { + JSValue v = m_butterfly->contiguousInt32()[i].get(); + if (!v) + continue; + ASSERT(v.isInt32()); + ASSERT(numDefined < m_butterfly->vectorLength()); + m_butterfly->contiguousInt32()[numDefined++].setWithoutWriteBarrier(v); + continue; + } + if (indexingType == ArrayWithDouble) { + double v = m_butterfly->contiguousDouble()[i]; + if (v != v) + continue; + ASSERT(numDefined < m_butterfly->vectorLength()); + m_butterfly->contiguousDouble()[numDefined++] = v; + continue; + } + JSValue v = indexingData<indexingType>()[i].get(); + if (v) { + if (v.isUndefined()) + ++numUndefined; + else { + ASSERT(numDefined < m_butterfly->vectorLength()); + indexingData<indexingType>()[numDefined++].setWithoutWriteBarrier(v); + } + } } + + newRelevantLength = numDefined + numUndefined; + + if (hasArrayStorage(indexingType)) + RELEASE_ASSERT(!arrayStorage()->m_sparseMap); + + switch (indexingType) { + case ArrayWithInt32: + case ArrayWithDouble: + RELEASE_ASSERT(numDefined == newRelevantLength); + break; + + default: + for (unsigned i = numDefined; i < newRelevantLength; ++i) { + ASSERT(i < m_butterfly->vectorLength()); + indexingData<indexingType>()[i].setUndefined(); + } + break; + } + for (unsigned i = newRelevantLength; i < myRelevantLength; ++i) { + ASSERT(i < m_butterfly->vectorLength()); + if (indexingType == ArrayWithDouble) + m_butterfly->contiguousDouble()[i] = QNaN; + else + indexingData<indexingType>()[i].clear(); + } + + if (hasArrayStorage(indexingType)) + arrayStorage()->m_numValuesInVector = newRelevantLength; } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSArray.h b/Source/JavaScriptCore/runtime/JSArray.h index 45b558b20..fe30d9f96 100644 --- a/Source/JavaScriptCore/runtime/JSArray.h +++ b/Source/JavaScriptCore/runtime/JSArray.h @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2007, 2008, 2009, 2012, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -37,7 +37,6 @@ class JSArray : public JSNonFinalObject { public: typedef JSNonFinalObject Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames; static size_t allocationSize(size_t inlineCapacity) { @@ -53,7 +52,6 @@ protected: public: static JSArray* create(VM&, Structure*, unsigned initialLength = 0); - static JSArray* createWithButterfly(VM&, Structure*, Butterfly*); // tryCreateUninitialized is used for fast construction of arrays whose size and // contents are known at time of creation. Clients of this interface must: @@ -63,34 +61,20 @@ public: JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool throwException); - JS_EXPORT_PRIVATE static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); DECLARE_EXPORT_INFO; - - // OK if we know this is a JSArray, but not if it could be an object of a derived class; for RuntimeArray this always returns 0. + unsigned length() const { return getArrayLength(); } + // OK to use on new arrays, but not if it might be a RegExpMatchArray. + bool setLength(ExecState*, unsigned, bool throwException = false); - // OK to use on new arrays, but not if it might be a RegExpMatchArray or RuntimeArray. - JS_EXPORT_PRIVATE bool setLength(ExecState*, unsigned, bool throwException = false); - - JS_EXPORT_PRIVATE void push(ExecState*, JSValue); - JS_EXPORT_PRIVATE JSValue pop(ExecState*); + void sort(ExecState*); + void sort(ExecState*, JSValue compareFunction, CallType, const CallData&); + void sortNumeric(ExecState*, JSValue compareFunction, CallType, const CallData&); - JSArray* fastSlice(ExecState&, unsigned startIndex, unsigned count); - - static IndexingType fastConcatType(VM& vm, JSArray& firstArray, JSArray& secondArray) - { - IndexingType type = firstArray.indexingType(); - if (type != secondArray.indexingType()) - return NonArray; - if (type != ArrayWithDouble && type != ArrayWithInt32 && type != ArrayWithContiguous) - return NonArray; - if (firstArray.structure(vm)->holesMustForwardToPrototype(vm) - || secondArray.structure(vm)->holesMustForwardToPrototype(vm)) - return NonArray; - return type; - } - EncodedJSValue fastConcatWith(ExecState&, JSArray&); + void push(ExecState*, JSValue); + JSValue pop(ExecState*); enum ShiftCountMode { // This form of shift hints that we're doing queueing. With this assumption in hand, @@ -105,14 +89,14 @@ public: bool shiftCountForShift(ExecState* exec, unsigned startIndex, unsigned count) { - return shiftCountWithArrayStorage(exec->vm(), startIndex, count, ensureArrayStorage(exec->vm())); + return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm())); } - bool shiftCountForSplice(ExecState* exec, unsigned& startIndex, unsigned count) + bool shiftCountForSplice(ExecState* exec, unsigned startIndex, unsigned count) { return shiftCountWithAnyIndexingType(exec, startIndex, count); } template<ShiftCountMode shiftCountMode> - bool shiftCount(ExecState* exec, unsigned& startIndex, unsigned count) + bool shiftCount(ExecState* exec, unsigned startIndex, unsigned count) { switch (shiftCountMode) { case ShiftCountForShift: @@ -147,8 +131,8 @@ public: } } - JS_EXPORT_PRIVATE void fillArgList(ExecState*, MarkedArgumentBuffer&); - JS_EXPORT_PRIVATE void copyToArguments(ExecState*, VirtualRegister firstElementDest, unsigned offset, unsigned length); + void fillArgList(ExecState*, MarkedArgumentBuffer&); + void copyToArguments(ExecState*, CallFrame*, uint32_t length); static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, IndexingType indexingType) { @@ -156,6 +140,7 @@ public: } protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSObject::StructureFlags; static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); static bool deleteProperty(JSCell*, ExecState*, PropertyName); @@ -171,15 +156,27 @@ private: return !map || !map->lengthIsReadOnly(); } - bool shiftCountWithAnyIndexingType(ExecState*, unsigned& startIndex, unsigned count); - JS_EXPORT_PRIVATE bool shiftCountWithArrayStorage(VM&, unsigned startIndex, unsigned count, ArrayStorage*); + bool shiftCountWithAnyIndexingType(ExecState*, unsigned startIndex, unsigned count); + bool shiftCountWithArrayStorage(unsigned startIndex, unsigned count, ArrayStorage*); bool unshiftCountWithAnyIndexingType(ExecState*, unsigned startIndex, unsigned count); bool unshiftCountWithArrayStorage(ExecState*, unsigned startIndex, unsigned count, ArrayStorage*); bool unshiftCountSlowCase(VM&, bool, unsigned); + template<IndexingType indexingType> + void sortNumericVector(ExecState*, JSValue compareFunction, CallType, const CallData&); + + template<IndexingType indexingType, typename StorageType> + void sortCompactedVector(ExecState*, ContiguousData<StorageType>, unsigned relevantLength); + + template<IndexingType indexingType> + void sortVector(ExecState*, JSValue compareFunction, CallType, const CallData&); + bool setLengthWithArrayStorage(ExecState*, unsigned newLength, bool throwException, ArrayStorage*); void setLengthWritable(ExecState*, bool writable); + + template<IndexingType indexingType> + void compactForSorting(unsigned& numDefined, unsigned& newRelevantLength); }; inline Butterfly* createContiguousArrayButterfly(VM& vm, JSCell* intendedOwner, unsigned length, unsigned& vectorLength) @@ -211,7 +208,7 @@ Butterfly* createArrayButterflyInDictionaryIndexingMode( inline JSArray* JSArray::create(VM& vm, Structure* structure, unsigned initialLength) { Butterfly* butterfly; - if (LIKELY(!hasAnyArrayStorage(structure->indexingType()))) { + if (LIKELY(!hasArrayStorage(structure->indexingType()))) { ASSERT( hasUndecided(structure->indexingType()) || hasInt32(structure->indexingType()) @@ -219,10 +216,10 @@ inline JSArray* JSArray::create(VM& vm, Structure* structure, unsigned initialLe || hasContiguous(structure->indexingType())); unsigned vectorLength; butterfly = createContiguousArrayButterfly(vm, 0, initialLength, vectorLength); - ASSERT(initialLength < MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH); + ASSERT(initialLength < MIN_SPARSE_ARRAY_INDEX); if (hasDouble(structure->indexingType())) { for (unsigned i = 0; i < vectorLength; ++i) - butterfly->contiguousDouble()[i] = PNaN; + butterfly->contiguousDouble()[i] = QNaN; } } else { ASSERT( @@ -230,8 +227,9 @@ inline JSArray* JSArray::create(VM& vm, Structure* structure, unsigned initialLe || structure->indexingType() == ArrayWithArrayStorage); butterfly = createArrayButterfly(vm, 0, initialLength); } - - return createWithButterfly(vm, structure, butterfly); + JSArray* array = new (NotNull, allocateCell<JSArray>(vm.heap)) JSArray(vm, structure, butterfly); + array->finishCreation(vm); + return array; } inline JSArray* JSArray::tryCreateUninitialized(VM& vm, Structure* structure, unsigned initialLength) @@ -241,7 +239,7 @@ inline JSArray* JSArray::tryCreateUninitialized(VM& vm, Structure* structure, un return 0; Butterfly* butterfly; - if (LIKELY(!hasAnyArrayStorage(structure->indexingType()))) { + if (LIKELY(!hasArrayStorage(structure->indexingType()))) { ASSERT( hasUndecided(structure->indexingType()) || hasInt32(structure->indexingType()) @@ -256,7 +254,7 @@ inline JSArray* JSArray::tryCreateUninitialized(VM& vm, Structure* structure, un butterfly->setPublicLength(initialLength); if (hasDouble(structure->indexingType())) { for (unsigned i = initialLength; i < vectorLength; ++i) - butterfly->contiguousDouble()[i] = PNaN; + butterfly->contiguousDouble()[i] = QNaN; } } else { void* temp; @@ -269,12 +267,7 @@ inline JSArray* JSArray::tryCreateUninitialized(VM& vm, Structure* structure, un storage->m_sparseMap.clear(); storage->m_numValuesInVector = initialLength; } - - return createWithButterfly(vm, structure, butterfly); -} - -inline JSArray* JSArray::createWithButterfly(VM& vm, Structure* structure, Butterfly* butterfly) -{ + JSArray* array = new (NotNull, allocateCell<JSArray>(vm.heap)) JSArray(vm, structure, butterfly); array->finishCreation(vm); return array; diff --git a/Source/JavaScriptCore/runtime/JSArrayBuffer.cpp b/Source/JavaScriptCore/runtime/JSArrayBuffer.cpp index 62ab89a3d..b24e09ef9 100644 --- a/Source/JavaScriptCore/runtime/JSArrayBuffer.cpp +++ b/Source/JavaScriptCore/runtime/JSArrayBuffer.cpp @@ -26,13 +26,13 @@ #include "config.h" #include "JSArrayBuffer.h" -#include "JSCInlines.h" +#include "Operations.h" #include "Reject.h" namespace JSC { const ClassInfo JSArrayBuffer::s_info = { - "ArrayBuffer", &Base::s_info, 0, CREATE_METHOD_TABLE(JSArrayBuffer)}; + "ArrayBuffer", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSArrayBuffer)}; JSArrayBuffer::JSArrayBuffer(VM& vm, Structure* structure, PassRefPtr<ArrayBuffer> arrayBuffer) : Base(vm, structure) @@ -119,7 +119,7 @@ void JSArrayBuffer::getOwnNonIndexPropertyNames( { JSArrayBuffer* thisObject = jsCast<JSArrayBuffer*>(object); - if (mode.includeDontEnumProperties()) + if (mode == IncludeDontEnumProperties) array.add(exec->propertyNames().byteLength); Base::getOwnNonIndexPropertyNames(thisObject, exec, array, mode); diff --git a/Source/JavaScriptCore/runtime/JSArrayBuffer.h b/Source/JavaScriptCore/runtime/JSArrayBuffer.h index 7529e3634..319b82e5a 100644 --- a/Source/JavaScriptCore/runtime/JSArrayBuffer.h +++ b/Source/JavaScriptCore/runtime/JSArrayBuffer.h @@ -34,7 +34,6 @@ namespace JSC { class JSArrayBuffer : public JSNonFinalObject { public: typedef JSNonFinalObject Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetPropertyNames | OverridesGetOwnPropertySlot; protected: JSArrayBuffer(VM&, Structure*, PassRefPtr<ArrayBuffer>); @@ -57,6 +56,8 @@ protected: static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + static const unsigned StructureFlags = OverridesGetPropertyNames | OverridesGetOwnPropertySlot | Base::StructureFlags; + private: ArrayBuffer* m_impl; }; diff --git a/Source/JavaScriptCore/runtime/JSArrayBufferConstructor.cpp b/Source/JavaScriptCore/runtime/JSArrayBufferConstructor.cpp index 3d14a9ef5..ca7e030e8 100644 --- a/Source/JavaScriptCore/runtime/JSArrayBufferConstructor.cpp +++ b/Source/JavaScriptCore/runtime/JSArrayBufferConstructor.cpp @@ -31,14 +31,14 @@ #include "JSArrayBuffer.h" #include "JSArrayBufferPrototype.h" #include "JSGlobalObject.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { static EncodedJSValue JSC_HOST_CALL arrayBufferFuncIsView(ExecState*); const ClassInfo JSArrayBufferConstructor::s_info = { - "Function", &Base::s_info, 0, + "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSArrayBufferConstructor) }; @@ -49,7 +49,7 @@ JSArrayBufferConstructor::JSArrayBufferConstructor(VM& vm, Structure* structure) void JSArrayBufferConstructor::finishCreation(VM& vm, JSArrayBufferPrototype* prototype) { - Base::finishCreation(vm, ASCIILiteral("ArrayBuffer")); + Base::finishCreation(vm, "ArrayBuffer"); putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, DontEnum | DontDelete | ReadOnly); putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), DontEnum | DontDelete | ReadOnly); @@ -92,10 +92,10 @@ static EncodedJSValue JSC_HOST_CALL constructArrayBuffer(ExecState* exec) RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(length, 1); if (!buffer) - return throwVMError(exec, createOutOfMemoryError(exec)); + return throwVMError(exec, createOutOfMemoryError(constructor->globalObject())); JSArrayBuffer* result = JSArrayBuffer::create( - exec->vm(), constructor->globalObject()->arrayBufferStructure(), buffer.release()); + exec->vm(), constructor->globalObject()->arrayBufferStructure(), buffer); return JSValue::encode(result); } diff --git a/Source/JavaScriptCore/runtime/JSArrayBufferPrototype.cpp b/Source/JavaScriptCore/runtime/JSArrayBufferPrototype.cpp index ef650f6eb..42889f7ea 100644 --- a/Source/JavaScriptCore/runtime/JSArrayBufferPrototype.cpp +++ b/Source/JavaScriptCore/runtime/JSArrayBufferPrototype.cpp @@ -30,7 +30,7 @@ #include "ExceptionHelpers.h" #include "JSArrayBuffer.h" #include "JSFunction.h" -#include "JSCInlines.h" +#include "Operations.h" #include "TypedArrayAdaptors.h" namespace JSC { @@ -41,10 +41,10 @@ static EncodedJSValue JSC_HOST_CALL arrayBufferProtoFuncSlice(ExecState* exec) JSArrayBuffer* thisObject = jsDynamicCast<JSArrayBuffer*>(exec->thisValue()); if (!thisObject) - return throwVMError(exec, createTypeError(exec, ASCIILiteral("Receiver of slice must be an array buffer."))); + return throwVMError(exec, createTypeError(exec, "Receiver of slice must be an array buffer.")); if (!exec->argumentCount()) - return throwVMError(exec, createTypeError(exec, ASCIILiteral("Slice requires at least one argument."))); + return throwVMError(exec, createTypeError(exec, "Slice requires at least one argument.")); int32_t begin = exec->argument(0).toInt32(exec); if (exec->hadException()) @@ -60,7 +60,7 @@ static EncodedJSValue JSC_HOST_CALL arrayBufferProtoFuncSlice(ExecState* exec) RefPtr<ArrayBuffer> newBuffer = thisObject->impl()->slice(begin, end); if (!newBuffer) - return throwVMError(exec, createOutOfMemoryError(exec)); + return throwVMError(exec, createOutOfMemoryError(callee->globalObject())); Structure* structure = callee->globalObject()->arrayBufferStructure(); @@ -70,7 +70,7 @@ static EncodedJSValue JSC_HOST_CALL arrayBufferProtoFuncSlice(ExecState* exec) } const ClassInfo JSArrayBufferPrototype::s_info = { - "ArrayBufferPrototype", &Base::s_info, 0, CREATE_METHOD_TABLE(JSArrayBufferPrototype) + "ArrayBufferPrototype", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSArrayBufferPrototype) }; JSArrayBufferPrototype::JSArrayBufferPrototype(VM& vm, Structure* structure) diff --git a/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp b/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp index a3398dbaa..c9812688e 100644 --- a/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp +++ b/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp @@ -27,13 +27,13 @@ #include "JSArrayBufferView.h" #include "JSArrayBuffer.h" -#include "JSCInlines.h" +#include "Operations.h" #include "Reject.h" namespace JSC { const ClassInfo JSArrayBufferView::s_info = { - "ArrayBufferView", &Base::s_info, 0, CREATE_METHOD_TABLE(JSArrayBufferView) + "ArrayBufferView", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSArrayBufferView) }; JSArrayBufferView::ConstructionContext::ConstructionContext( @@ -78,7 +78,7 @@ JSArrayBufferView::ConstructionContext::ConstructionContext( return; } - vm.heap.reportExtraMemoryAllocated(static_cast<size_t>(length) * elementSize); + vm.heap.reportExtraMemoryCost(static_cast<size_t>(length) * elementSize); m_structure = structure; m_mode = OversizeTypedArray; @@ -201,7 +201,7 @@ void JSArrayBufferView::getOwnNonIndexPropertyNames( JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(object); // length/byteOffset/byteLength are DontEnum, at least in Firefox. - if (mode.includeDontEnumProperties()) { + if (mode == IncludeDontEnumProperties) { array.add(exec->propertyNames().byteOffset); array.add(exec->propertyNames().byteLength); array.add(exec->propertyNames().buffer); diff --git a/Source/JavaScriptCore/runtime/JSArrayBufferView.h b/Source/JavaScriptCore/runtime/JSArrayBufferView.h index 051445299..3feb03b72 100644 --- a/Source/JavaScriptCore/runtime/JSArrayBufferView.h +++ b/Source/JavaScriptCore/runtime/JSArrayBufferView.h @@ -93,7 +93,6 @@ inline bool hasArrayBuffer(TypedArrayMode mode) class JSArrayBufferView : public JSNonFinalObject { public: typedef JSNonFinalObject Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetPropertyNames | OverridesGetOwnPropertySlot; static const unsigned fastSizeLimit = 1000; @@ -175,6 +174,8 @@ private: static void finalize(JSCell*); protected: + static const unsigned StructureFlags = OverridesGetPropertyNames | OverridesGetOwnPropertySlot | Base::StructureFlags; + ArrayBuffer* existingBufferInButterfly(); void* m_vector; diff --git a/Source/JavaScriptCore/runtime/JSArrayIterator.cpp b/Source/JavaScriptCore/runtime/JSArrayIterator.cpp index 0abc9d120..d506c4ebd 100644 --- a/Source/JavaScriptCore/runtime/JSArrayIterator.cpp +++ b/Source/JavaScriptCore/runtime/JSArrayIterator.cpp @@ -29,42 +29,141 @@ #include "JSCJSValueInlines.h" #include "JSCellInlines.h" #include "SlotVisitorInlines.h" -#include "StructureInlines.h" namespace JSC { -const ClassInfo JSArrayIterator::s_info = { "Array Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(JSArrayIterator) }; +const ClassInfo JSArrayIterator::s_info = { "ArrayIterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSArrayIterator) }; -void JSArrayIterator::finishCreation(VM& vm, JSGlobalObject*, ArrayIterationKind kind, JSObject* iteratedObject) +static EncodedJSValue JSC_HOST_CALL arrayIteratorNextKey(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayIteratorNextValue(ExecState*); +static EncodedJSValue JSC_HOST_CALL arrayIteratorNextGeneric(ExecState*); + +void JSArrayIterator::finishCreation(VM& vm, JSGlobalObject* globalObject, ArrayIterationKind kind, JSObject* iteratedObject) { Base::finishCreation(vm); ASSERT(inherits(info())); + m_iterationKind = kind; + m_iteratedObject.set(vm, this, iteratedObject); + switch (kind) { + case ArrayIterateKey: + JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->iteratorNextPrivateName, arrayIteratorNextKey, DontEnum, 0, ArrayIteratorNextKeyIntrinsic); + break; + case ArrayIterateValue: + JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->iteratorNextPrivateName, arrayIteratorNextValue, DontEnum, 0, ArrayIteratorNextValueIntrinsic); + break; + default: + JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->iteratorNextPrivateName, arrayIteratorNextGeneric, DontEnum, 0, ArrayIteratorNextGenericIntrinsic); + break; + } - putDirect(vm, vm.propertyNames->iteratedObjectPrivateName, iteratedObject); - putDirect(vm, vm.propertyNames->arrayIteratorNextIndexPrivateName, jsNumber(0)); - putDirect(vm, vm.propertyNames->arrayIterationKindPrivateName, jsNumber(kind)); } - -ArrayIterationKind JSArrayIterator::kind(ExecState* exec) const + + +void JSArrayIterator::visitChildren(JSCell* cell, SlotVisitor& visitor) { - JSValue kindValue = getDirect(exec->vm(), exec->vm().propertyNames->arrayIterationKindPrivateName); - return static_cast<ArrayIterationKind>(kindValue.asInt32()); + JSArrayIterator* thisObject = jsCast<JSArrayIterator*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + + Base::visitChildren(thisObject, visitor); + visitor.append(&thisObject->m_iteratedObject); + } -JSValue JSArrayIterator::iteratedValue(ExecState* exec) const +static EncodedJSValue createIteratorResult(CallFrame* callFrame, ArrayIterationKind kind, size_t index, JSValue result, bool done) { - return getDirect(exec->vm(), exec->vm().propertyNames->iteratedObjectPrivateName); + if (done) + return JSValue::encode(callFrame->vm().iterationTerminator.get()); + + switch (kind & ~ArrayIterateSparseTag) { + case ArrayIterateKey: + return JSValue::encode(jsNumber(index)); + + case ArrayIterateValue: + return JSValue::encode(result); + + case ArrayIterateKeyValue: { + MarkedArgumentBuffer args; + args.append(jsNumber(index)); + args.append(result); + JSGlobalObject* globalObject = callFrame->callee()->globalObject(); + return JSValue::encode(constructArray(callFrame, 0, globalObject, args)); + + } + default: + RELEASE_ASSERT_NOT_REACHED(); + } + return JSValue::encode(JSValue()); } -JSArrayIterator* JSArrayIterator::clone(ExecState* exec) +static inline EncodedJSValue JSC_HOST_CALL arrayIteratorNext(CallFrame* callFrame) { - VM& vm = exec->vm(); - JSValue iteratedObject = getDirect(vm, vm.propertyNames->iteratedObjectPrivateName); - JSValue nextIndex = getDirect(vm, vm.propertyNames->arrayIteratorNextIndexPrivateName); - - auto clone = JSArrayIterator::create(exec, exec->callee()->globalObject()->arrayIteratorStructure(), kind(exec), asObject(iteratedObject)); - clone->putDirect(vm, vm.propertyNames->arrayIteratorNextIndexPrivateName, nextIndex); - return clone; + JSArrayIterator* iterator = jsDynamicCast<JSArrayIterator*>(callFrame->thisValue()); + if (!iterator) { + ASSERT_NOT_REACHED(); + return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot call ArrayIterator.next() on a non-ArrayIterator object"))); + } + JSObject* iteratedObject = iterator->iteratedObject(); + size_t index = iterator->nextIndex(); + ArrayIterationKind kind = iterator->iterationKind(); + JSValue jsLength = JSValue(iteratedObject).get(callFrame, callFrame->propertyNames().length); + if (callFrame->hadException()) + return JSValue::encode(jsNull()); + + size_t length = jsLength.toUInt32(callFrame); + if (callFrame->hadException()) + return JSValue::encode(jsNull()); + + if (index >= length) { + iterator->finish(); + return createIteratorResult(callFrame, kind, index, jsUndefined(), true); + } + if (JSValue result = iteratedObject->tryGetIndexQuickly(index)) { + iterator->setNextIndex(index + 1); + return createIteratorResult(callFrame, kind, index, result, false); + } + + JSValue result = jsUndefined(); + PropertySlot slot(iteratedObject); + if (kind > ArrayIterateSparseTag) { + // We assume that the indexed property will be an own property so cache the getOwnProperty + // method locally + auto getOwnPropertySlotByIndex = iteratedObject->methodTable()->getOwnPropertySlotByIndex; + while (index < length) { + if (getOwnPropertySlotByIndex(iteratedObject, callFrame, index, slot)) { + result = slot.getValue(callFrame, index); + break; + } + if (iteratedObject->getPropertySlot(callFrame, index, slot)) { + result = slot.getValue(callFrame, index); + break; + } + index++; + } + } else if (iteratedObject->getPropertySlot(callFrame, index, slot)) + result = slot.getValue(callFrame, index); + + if (index == length) + iterator->finish(); + else + iterator->setNextIndex(index + 1); + return createIteratorResult(callFrame, kind, index, jsUndefined(), index == length); +} + +EncodedJSValue JSC_HOST_CALL arrayIteratorNextKey(CallFrame* callFrame) +{ + return arrayIteratorNext(callFrame); +} + +EncodedJSValue JSC_HOST_CALL arrayIteratorNextValue(CallFrame* callFrame) +{ + return arrayIteratorNext(callFrame); +} + +EncodedJSValue JSC_HOST_CALL arrayIteratorNextGeneric(CallFrame* callFrame) +{ + return arrayIteratorNext(callFrame); } } diff --git a/Source/JavaScriptCore/runtime/JSArrayIterator.h b/Source/JavaScriptCore/runtime/JSArrayIterator.h index 0166bd2e5..2994a67d1 100644 --- a/Source/JavaScriptCore/runtime/JSArrayIterator.h +++ b/Source/JavaScriptCore/runtime/JSArrayIterator.h @@ -33,7 +33,11 @@ namespace JSC { enum ArrayIterationKind : uint32_t { ArrayIterateKey, ArrayIterateValue, - ArrayIterateKeyValue + ArrayIterateKeyValue, + ArrayIterateSparseTag = 4, + ArrayIterateSparseKey, + ArrayIterateSparseValue, + ArrayIterateSparseKeyValue }; class JSArrayIterator : public JSNonFinalObject { @@ -55,18 +59,33 @@ public: return instance; } - ArrayIterationKind kind(ExecState*) const; - JSValue iteratedValue(ExecState*) const; - JSArrayIterator* clone(ExecState*); - + ArrayIterationKind iterationKind() const { return m_iterationKind; } + JSObject* iteratedObject() const { return m_iteratedObject.get(); } + size_t nextIndex() const { return m_nextIndex; } + void setNextIndex(size_t nextIndex) { m_nextIndex = nextIndex; } + void finish() { m_nextIndex = std::numeric_limits<uint32_t>::max(); } + using JSNonFinalObject::arrayStorageOrNull; + static ptrdiff_t offsetOfIterationKind() { return OBJECT_OFFSETOF(JSArrayIterator, m_iterationKind); } + static ptrdiff_t offsetOfIteratedObject() { return OBJECT_OFFSETOF(JSArrayIterator, m_iteratedObject); } + static ptrdiff_t offsetOfNextIndex() { return OBJECT_OFFSETOF(JSArrayIterator, m_nextIndex); } + private: + + static const unsigned StructureFlags = Base::StructureFlags | OverridesVisitChildren; + JSArrayIterator(VM& vm, Structure* structure) : Base(vm, structure) + , m_nextIndex(0) { } void finishCreation(VM&, JSGlobalObject*, ArrayIterationKind, JSObject* iteratedObject); + static void visitChildren(JSCell*, SlotVisitor&); + + ArrayIterationKind m_iterationKind; + WriteBarrier<JSObject> m_iteratedObject; + uint32_t m_nextIndex; }; } diff --git a/Source/JavaScriptCore/runtime/JSBoundFunction.cpp b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp index 8c5cc2ed3..f22827a37 100644 --- a/Source/JavaScriptCore/runtime/JSBoundFunction.cpp +++ b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp @@ -28,11 +28,11 @@ #include "GetterSetter.h" #include "JSGlobalObject.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { -const ClassInfo JSBoundFunction::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(JSBoundFunction) }; +const ClassInfo JSBoundFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSBoundFunction) }; EncodedJSValue JSC_HOST_CALL boundFunctionCall(ExecState* exec) { @@ -86,6 +86,11 @@ JSBoundFunction* JSBoundFunction::create(VM& vm, JSGlobalObject* globalObject, J return function; } +void JSBoundFunction::destroy(JSCell* cell) +{ + static_cast<JSBoundFunction*>(cell)->JSBoundFunction::~JSBoundFunction(); +} + bool JSBoundFunction::customHasInstance(JSObject* object, ExecState* exec, JSValue value) { return jsCast<JSBoundFunction*>(object)->m_targetFunction->hasInstance(exec, value); @@ -112,6 +117,8 @@ void JSBoundFunction::visitChildren(JSCell* cell, SlotVisitor& visitor) { JSBoundFunction* thisObject = jsCast<JSBoundFunction*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); Base::visitChildren(thisObject, visitor); visitor.append(&thisObject->m_targetFunction); diff --git a/Source/JavaScriptCore/runtime/JSBoundFunction.h b/Source/JavaScriptCore/runtime/JSBoundFunction.h index af2a6323d..7852f78ce 100644 --- a/Source/JavaScriptCore/runtime/JSBoundFunction.h +++ b/Source/JavaScriptCore/runtime/JSBoundFunction.h @@ -36,10 +36,11 @@ EncodedJSValue JSC_HOST_CALL boundFunctionConstruct(ExecState*); class JSBoundFunction : public JSFunction { public: typedef JSFunction Base; - const static unsigned StructureFlags = OverridesHasInstance | Base::StructureFlags; static JSBoundFunction* create(VM&, JSGlobalObject*, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs, int, const String&); + static void destroy(JSCell*); + static bool customHasInstance(JSObject*, ExecState*, JSValue); JSObject* targetFunction() { return m_targetFunction.get(); } @@ -55,6 +56,8 @@ public: DECLARE_INFO; protected: + const static unsigned StructureFlags = OverridesHasInstance | OverridesVisitChildren | Base::StructureFlags; + static void visitChildren(JSCell*, SlotVisitor&); private: diff --git a/Source/JavaScriptCore/runtime/JSCInlines.h b/Source/JavaScriptCore/runtime/JSCInlines.h deleted file mode 100644 index e9fabb53e..000000000 --- a/Source/JavaScriptCore/runtime/JSCInlines.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2014 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 JSCInlines_h -#define JSCInlines_h - -// This file's only purpose is to collect commonly used *Inlines.h files, so that you don't -// have to include all of them in every .cpp file. Instead you just include this. It's good -// style to make sure that every .cpp file includes JSCInlines.h. -// -// JSC should never include this file, or any *Inline.h file, from interface headers, since -// this could lead to a circular dependency. -// -// WebCore, or any other downstream client of JSC, is allowed to include this file in headers. -// In fact, it can make a lot of sense: outside of JSC, this file becomes a kind of umbrella -// header that pulls in most (all?) of the interesting things in JSC. - -#include "CallFrameInlines.h" -#include "ExceptionHelpers.h" -#include "GCIncomingRefCountedInlines.h" -#include "HeapInlines.h" -#include "IdentifierInlines.h" -#include "Interpreter.h" -#include "JSArrayBufferViewInlines.h" -#include "JSCJSValueInlines.h" -#include "JSFunctionInlines.h" -#include "JSProxy.h" -#include "JSString.h" -#include "Operations.h" -#include "SlotVisitorInlines.h" -#include "StructureInlines.h" -#include "WeakGCMapInlines.h" - -#endif // JSCInlines_h diff --git a/Source/JavaScriptCore/runtime/JSCJSValue.cpp b/Source/JavaScriptCore/runtime/JSCJSValue.cpp index 9e0aab177..cca6888bf 100644 --- a/Source/JavaScriptCore/runtime/JSCJSValue.cpp +++ b/Source/JavaScriptCore/runtime/JSCJSValue.cpp @@ -25,7 +25,6 @@ #include "BooleanConstructor.h" #include "BooleanPrototype.h" -#include "CustomGetterSetter.h" #include "Error.h" #include "ExceptionHelpers.h" #include "GetterSetter.h" @@ -34,7 +33,6 @@ #include "JSGlobalObject.h" #include "JSNotAnObject.h" #include "NumberObject.h" -#include "StructureInlines.h" #include <wtf/MathExtras.h> #include <wtf/StringExtras.h> @@ -63,7 +61,7 @@ double JSValue::toNumberSlowCase(ExecState* exec) const return asCell()->toNumber(exec); if (isTrue()) return 1.0; - return isUndefined() ? PNaN : 0; // null and false both convert to 0. + return isUndefined() ? QNaN : 0; // null and false both convert to 0. } JSObject* JSValue::toObjectSlowCase(ExecState* exec, JSGlobalObject* globalObject) const @@ -99,10 +97,8 @@ JSValue JSValue::toThisSlowCase(ExecState* exec, ECMAMode ecmaMode) const JSObject* JSValue::synthesizePrototype(ExecState* exec) const { if (isCell()) { - if (isString()) - return exec->lexicalGlobalObject()->stringPrototype(); - ASSERT(isSymbol()); - return exec->lexicalGlobalObject()->symbolPrototype(); + ASSERT(isString()); + return exec->lexicalGlobalObject()->stringPrototype(); } if (isNumber()) @@ -121,8 +117,9 @@ void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue { VM& vm = exec->vm(); - if (Optional<uint32_t> index = parseIndex(propertyName)) { - putToPrimitiveByIndex(exec, index.value(), value, slot.isStrictMode()); + unsigned index = propertyName.asIndex(); + if (index != PropertyName::NotAnIndex) { + putToPrimitiveByIndex(exec, index, value, slot.isStrictMode()); return; } @@ -142,7 +139,8 @@ void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue for (; ; obj = asObject(prototype)) { unsigned attributes; - PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes); + JSCell* specificValue; + PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes, specificValue); if (offset != invalidOffset) { if (attributes & ReadOnly) { if (slot.isStrictMode()) @@ -156,11 +154,6 @@ void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue return; } - if (gs.isCustomGetterSetter()) { - callCustomSetter(exec, gs, obj, slot.thisValue(), value); - return; - } - // If there's an existing property on the object or one of its // prototypes it should be replaced, so break here. break; @@ -198,13 +191,6 @@ void JSValue::dump(PrintStream& out) const void JSValue::dumpInContext(PrintStream& out, DumpContext* context) const { - dumpInContextAssumingStructure( - out, context, (!!*this && isCell()) ? asCell()->structure() : nullptr); -} - -void JSValue::dumpInContextAssumingStructure( - PrintStream& out, DumpContext* context, Structure* structure) const -{ if (!*this) out.print("<JSValue()>"); else if (isInt32()) @@ -221,7 +207,7 @@ void JSValue::dumpInContextAssumingStructure( out.printf("Double: %08x:%08x, %lf", u.asTwoInt32s[1], u.asTwoInt32s[0], asDouble()); #endif } else if (isCell()) { - if (structure->classInfo()->isSubClassOf(JSString::info())) { + if (asCell()->inherits(JSString::info())) { JSString* string = jsCast<JSString*>(asCell()); out.print("String"); if (string->isRope()) @@ -230,62 +216,18 @@ void JSValue::dumpInContextAssumingStructure( if (impl) { if (impl->isAtomic()) out.print(" (atomic)"); - if (impl->isAtomic()) + if (impl->isIdentifier()) out.print(" (identifier)"); - if (impl->isSymbol()) - out.print(" (symbol)"); + if (impl->isEmptyUnique()) + out.print(" (unique)"); } else out.print(" (unresolved)"); out.print(": ", impl); - } else if (structure->classInfo()->isSubClassOf(Structure::info())) + } else if (asCell()->inherits(Structure::info())) out.print("Structure: ", inContext(*jsCast<Structure*>(asCell()), context)); else { out.print("Cell: ", RawPointer(asCell())); - out.print(" (", inContext(*structure, context), ")"); - } -#if USE(JSVALUE64) - out.print(", ID: ", asCell()->structureID()); -#endif - } else if (isTrue()) - out.print("True"); - else if (isFalse()) - out.print("False"); - else if (isNull()) - out.print("Null"); - else if (isUndefined()) - out.print("Undefined"); - else - out.print("INVALID"); -} - -void JSValue::dumpForBacktrace(PrintStream& out) const -{ - if (!*this) - out.print("<JSValue()>"); - else if (isInt32()) - out.printf("%d", asInt32()); - else if (isDouble()) - out.printf("%lf", asDouble()); - else if (isCell()) { - if (asCell()->inherits(JSString::info())) { - JSString* string = jsCast<JSString*>(asCell()); - const StringImpl* impl = string->tryGetValueImpl(); - if (impl) - out.print("\"", impl, "\""); - else - out.print("(unresolved string)"); - } else if (asCell()->inherits(Structure::info())) { - out.print("Structure[ ", asCell()->structure()->classInfo()->className); -#if USE(JSVALUE64) - out.print(" ID: ", asCell()->structureID()); -#endif - out.print("]: ", RawPointer(asCell())); - } else { - out.print("Cell[", asCell()->structure()->classInfo()->className); -#if USE(JSVALUE64) - out.print(" ID: ", asCell()->structureID()); -#endif - out.print("]: ", RawPointer(asCell())); + out.print(" (", inContext(*asCell()->structure(), context), ")"); } } else if (isTrue()) out.print("True"); @@ -353,12 +295,8 @@ JSString* JSValue::toStringSlowCase(ExecState* exec) const { VM& vm = exec->vm(); ASSERT(!isString()); - if (isInt32()) { - auto integer = asInt32(); - if (static_cast<unsigned>(integer) <= 9) - return vm.smallStrings.singleCharacterString(integer + '0'); - return jsNontrivialString(&vm, vm.numericStrings.add(integer)); - } + if (isInt32()) + return jsString(&vm, vm.numericStrings.add(asInt32())); if (isDouble()) return jsString(&vm, vm.numericStrings.add(asDouble())); if (isTrue()) @@ -369,10 +307,6 @@ JSString* JSValue::toStringSlowCase(ExecState* exec) const return vm.smallStrings.nullString(); if (isUndefined()) return vm.smallStrings.undefinedString(); - if (isSymbol()) { - throwTypeError(exec); - return jsEmptyString(exec); - } ASSERT(isCell()); JSValue value = asCell()->toPrimitive(exec, PreferString); @@ -384,20 +318,7 @@ JSString* JSValue::toStringSlowCase(ExecState* exec) const String JSValue::toWTFStringSlowCase(ExecState* exec) const { - VM& vm = exec->vm(); - if (isInt32()) - return vm.numericStrings.add(asInt32()); - if (isDouble()) - return vm.numericStrings.add(asDouble()); - if (isTrue()) - return vm.propertyNames->trueKeyword.string(); - if (isFalse()) - return vm.propertyNames->falseKeyword.string(); - if (isNull()) - return vm.propertyNames->nullKeyword.string(); - if (isUndefined()) - return vm.propertyNames->undefinedKeyword.string(); - return toString(exec)->value(exec); + return inlineJSValueNotStringtoString(*this, exec); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSCJSValue.h b/Source/JavaScriptCore/runtime/JSCJSValue.h index b7eaad2da..85ac32bdd 100644 --- a/Source/JavaScriptCore/runtime/JSCJSValue.h +++ b/Source/JavaScriptCore/runtime/JSCJSValue.h @@ -1,7 +1,7 @@ /* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2012, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -23,23 +23,23 @@ #ifndef JSCJSValue_h #define JSCJSValue_h -#include "JSExportMacros.h" -#include "PureNaN.h" -#include <functional> #include <math.h> -#include <stddef.h> +#include <stddef.h> // for size_t #include <stdint.h> #include <wtf/Assertions.h> #include <wtf/Forward.h> #include <wtf/HashMap.h> #include <wtf/HashTraits.h> #include <wtf/MathExtras.h> -#include <wtf/MediaTime.h> #include <wtf/StdLibExtras.h> #include <wtf/TriState.h> namespace JSC { +// This is used a lot throughout JavaScriptCore for everything from value boxing to marking +// values as being missing, so it is useful to have it abbreviated. +#define QNaN (std::numeric_limits<double>::quiet_NaN()) + class AssemblyHelpers; class ExecState; class JSCell; @@ -48,11 +48,9 @@ class VM; class JSGlobalObject; class JSObject; class JSString; -class Identifier; class PropertyName; class PropertySlot; class PutPropertySlot; -class Structure; #if ENABLE(DFG_JIT) namespace DFG { class JITCompiler; @@ -60,7 +58,7 @@ class OSRExitCompiler; class SpeculativeJIT; } #endif -#if !ENABLE(JIT) +#if ENABLE(LLINT_C_LOOP) namespace LLInt { class CLoop; } @@ -99,15 +97,6 @@ union EncodedValueDescriptor { #endif }; -#define TagOffset (OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)) -#define PayloadOffset (OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)) - -#if USE(JSVALUE64) -#define CellPayloadOffset 0 -#else -#define CellPayloadOffset PayloadOffset -#endif - enum WhichValueWord { TagWord, PayloadWord @@ -124,18 +113,8 @@ inline uint32_t toUInt32(double number) return toInt32(number); } -int64_t tryConvertToInt52(double); -bool isInt52(double); - -enum class SourceCodeRepresentation { - Other, - Integer, - Double -}; - class JSValue { friend struct EncodedJSValueHashTraits; - friend struct EncodedJSValueWithRepresentationHashTraits; friend class AssemblyHelpers; friend class JIT; friend class JITSlowPathCall; @@ -149,7 +128,7 @@ class JSValue { friend class DFG::OSRExitCompiler; friend class DFG::SpeculativeJIT; #endif -#if !ENABLE(JIT) +#if ENABLE(LLINT_C_LOOP) friend class LLInt::CLoop; #endif @@ -197,7 +176,8 @@ public: explicit JSValue(long long); explicit JSValue(unsigned long long); - explicit operator bool() const; + typedef void* (JSValue::*UnspecifiedBoolType); + operator UnspecifiedBoolType*() const; bool operator==(const JSValue& other) const; bool operator!=(const JSValue& other) const; @@ -213,8 +193,6 @@ public: double asDouble() const; bool asBoolean() const; double asNumber() const; - - int32_t asInt32ForArithmetic() const; // Boolean becomes an int, but otherwise like asInt32(). // Querying the type. bool isEmpty() const; @@ -226,10 +204,8 @@ public: bool isMachineInt() const; bool isNumber() const; bool isString() const; - bool isSymbol() const; bool isPrimitive() const; bool isGetterSetter() const; - bool isCustomGetterSetter() const; bool isObject() const; bool inherits(const ClassInfo*) const; @@ -252,19 +228,19 @@ public: // been set in the ExecState already. double toNumber(ExecState*) const; JSString* toString(ExecState*) const; - Identifier toPropertyKey(ExecState*) const; WTF::String toWTFString(ExecState*) const; + WTF::String toWTFStringInline(ExecState*) const; JSObject* toObject(ExecState*) const; JSObject* toObject(ExecState*, JSGlobalObject*) const; // Integer conversions. JS_EXPORT_PRIVATE double toInteger(ExecState*) const; - JS_EXPORT_PRIVATE double toIntegerPreserveNaN(ExecState*) const; + double toIntegerPreserveNaN(ExecState*) const; int32_t toInt32(ExecState*) const; uint32_t toUInt32(ExecState*) const; - // Floating point conversions (this is a convenience function for WebCore; - // single precision float is not a representation used in JS or JSC). + // Floating point conversions (this is a convenience method for webcore; + // signle precision float is not a representation used in JS or JSC). float toFloat(ExecState* exec) const { return static_cast<float>(toNumber(exec)); } // Object operations, with the toObject operation included. @@ -272,12 +248,9 @@ public: JSValue get(ExecState*, PropertyName, PropertySlot&) const; JSValue get(ExecState*, unsigned propertyName) const; JSValue get(ExecState*, unsigned propertyName, PropertySlot&) const; - - bool getPropertySlot(ExecState*, PropertyName, PropertySlot&) const; - void put(ExecState*, PropertyName, JSValue, PutPropertySlot&); - JS_EXPORT_PRIVATE void putToPrimitive(ExecState*, PropertyName, JSValue, PutPropertySlot&); - JS_EXPORT_PRIVATE void putToPrimitiveByIndex(ExecState*, unsigned propertyName, JSValue, bool shouldThrow); + void putToPrimitive(ExecState*, PropertyName, JSValue, PutPropertySlot&); + void putToPrimitiveByIndex(ExecState*, unsigned propertyName, JSValue, bool shouldThrow); void putByIndex(ExecState*, unsigned propertyName, JSValue, bool shouldThrow); JSValue toThis(ExecState*, ECMAMode) const; @@ -293,26 +266,35 @@ public: bool isCell() const; JSCell* asCell() const; JS_EXPORT_PRIVATE bool isValidCallee(); - + JSValue structureOrUndefined() const; JS_EXPORT_PRIVATE void dump(PrintStream&) const; void dumpInContext(PrintStream&, DumpContext*) const; - void dumpInContextAssumingStructure(PrintStream&, DumpContext*, Structure*) const; - void dumpForBacktrace(PrintStream&) const; JS_EXPORT_PRIVATE JSObject* synthesizePrototype(ExecState*) const; - bool requireObjectCoercible(ExecState*) const; // Constants used for Int52. Int52 isn't part of JSValue right now, but JSValues may be // converted to Int52s and back again. static const unsigned numberOfInt52Bits = 52; - static const int64_t notInt52 = static_cast<int64_t>(1) << numberOfInt52Bits; static const unsigned int52ShiftAmount = 12; static ptrdiff_t offsetOfPayload() { return OBJECT_OFFSETOF(JSValue, u.asBits.payload); } static ptrdiff_t offsetOfTag() { return OBJECT_OFFSETOF(JSValue, u.asBits.tag); } +private: + template <class T> JSValue(WriteBarrierBase<T>); + + enum HashTableDeletedValueTag { HashTableDeletedValue }; + JSValue(HashTableDeletedValueTag); + + inline const JSValue asValue() const { return *this; } + JS_EXPORT_PRIVATE double toNumberSlowCase(ExecState*) const; + JS_EXPORT_PRIVATE JSString* toStringSlowCase(ExecState*) const; + JS_EXPORT_PRIVATE WTF::String toWTFStringSlowCase(ExecState*) const; + JS_EXPORT_PRIVATE JSObject* toObjectSlowCase(ExecState*, JSGlobalObject*) const; + JS_EXPORT_PRIVATE JSValue toThisSlowCase(ExecState*, ECMAMode) const; + #if USE(JSVALUE32_64) /* * On 32-bit platforms USE(JSVALUE32_64) should be defined, and we use a NaN-encoded @@ -335,7 +317,7 @@ public: uint32_t tag() const; int32_t payload() const; -#if !ENABLE(JIT) +#if ENABLE(LLINT_C_LOOP) // This should only be used by the LLInt C Loop interpreter who needs // synthesize JSValue from its "register"s holding tag and payload // values. @@ -358,7 +340,7 @@ public: * * This range of NaN space is represented by 64-bit numbers begining with the 16-bit * hex patterns 0xFFFE and 0xFFFF - we rely on the fact that no valid double-precision - * numbers will fall in these ranges. + * numbers will begin fall in these ranges. * * The top 16-bits denote the type of the encoded JSValue: * @@ -372,7 +354,7 @@ public: * 64-bit integer addition of the value 2^48 to the number. After this manipulation * no encoded double-precision value will begin with the pattern 0x0000 or 0xFFFF. * Values must be decoded by reversing this operation before subsequent floating point - * operations may be peformed. + * operations my be peformed. * * 32-bit signed integers are marked with the 16-bit tag 0xFFFF. * @@ -425,19 +407,6 @@ public: #define ValueDeleted 0x4ll #endif -private: - template <class T> JSValue(WriteBarrierBase<T>); - - enum HashTableDeletedValueTag { HashTableDeletedValue }; - JSValue(HashTableDeletedValueTag); - - inline const JSValue asValue() const { return *this; } - JS_EXPORT_PRIVATE double toNumberSlowCase(ExecState*) const; - JS_EXPORT_PRIVATE JSString* toStringSlowCase(ExecState*) const; - JS_EXPORT_PRIVATE WTF::String toWTFStringSlowCase(ExecState*) const; - JS_EXPORT_PRIVATE JSObject* toObjectSlowCase(ExecState*, JSGlobalObject*) const; - JS_EXPORT_PRIVATE JSValue toThisSlowCase(ExecState*, ECMAMode) const; - EncodedValueDescriptor u; }; @@ -457,26 +426,7 @@ struct EncodedJSValueHashTraits : HashTraits<EncodedJSValue> { }; #endif -typedef std::pair<EncodedJSValue, SourceCodeRepresentation> EncodedJSValueWithRepresentation; - -struct EncodedJSValueWithRepresentationHashTraits : HashTraits<EncodedJSValueWithRepresentation> { - static const bool emptyValueIsZero = false; - static EncodedJSValueWithRepresentation emptyValue() { return std::make_pair(JSValue::encode(JSValue()), SourceCodeRepresentation::Other); } - static void constructDeletedValue(EncodedJSValueWithRepresentation& slot) { slot = std::make_pair(JSValue::encode(JSValue(JSValue::HashTableDeletedValue)), SourceCodeRepresentation::Other); } - static bool isDeletedValue(EncodedJSValueWithRepresentation value) { return value == std::make_pair(JSValue::encode(JSValue(JSValue::HashTableDeletedValue)), SourceCodeRepresentation::Other); } -}; - -struct EncodedJSValueWithRepresentationHash { - static unsigned hash(const EncodedJSValueWithRepresentation& value) - { - return WTF::pairIntHash(EncodedJSValueHash::hash(value.first), IntHash<SourceCodeRepresentation>::hash(value.second)); - } - static bool equal(const EncodedJSValueWithRepresentation& a, const EncodedJSValueWithRepresentation& b) - { - return a == b; - } - static const bool safeToCompareToEmptyOrDeleted = true; -}; +typedef HashMap<EncodedJSValue, unsigned, EncodedJSValueHash, EncodedJSValueHashTraits> JSValueMap; // Stand-alone helper functions. inline JSValue jsNull() @@ -489,11 +439,6 @@ inline JSValue jsUndefined() return JSValue(JSValue::JSUndefined); } -inline JSValue jsTDZValue() -{ - return JSValue(); -} - inline JSValue jsBoolean(bool b) { return b ? JSValue(JSValue::JSTrue) : JSValue(JSValue::JSFalse); @@ -511,11 +456,6 @@ ALWAYS_INLINE JSValue jsNumber(double d) return JSValue(d); } -ALWAYS_INLINE JSValue jsNumber(MediaTime t) -{ - return jsNumber(t.toDouble()); -} - ALWAYS_INLINE JSValue jsNumber(char i) { return JSValue(i); diff --git a/Source/JavaScriptCore/runtime/JSCJSValueInlines.h b/Source/JavaScriptCore/runtime/JSCJSValueInlines.h index 71842c21c..b34adf809 100644 --- a/Source/JavaScriptCore/runtime/JSCJSValueInlines.h +++ b/Source/JavaScriptCore/runtime/JSCJSValueInlines.h @@ -26,13 +26,10 @@ #ifndef JSValueInlines_h #define JSValueInlines_h -#include "ExceptionHelpers.h" -#include "Identifier.h" #include "InternalFunction.h" #include "JSCJSValue.h" #include "JSCellInlines.h" #include "JSFunction.h" -#include <wtf/text/StringImpl.h> namespace JSC { @@ -68,7 +65,7 @@ inline double JSValue::asNumber() const inline JSValue jsNaN() { - return JSValue(PNaN); + return JSValue(QNaN); } inline JSValue::JSValue(char i) @@ -213,10 +210,10 @@ inline JSValue::JSValue(const JSCell* ptr) u.asBits.payload = reinterpret_cast<int32_t>(const_cast<JSCell*>(ptr)); } -inline JSValue::operator bool() const +inline JSValue::operator UnspecifiedBoolType*() const { ASSERT(tag() != DeletedValueTag); - return tag() != EmptyValueTag; + return tag() != EmptyValueTag ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; } inline bool JSValue::operator==(const JSValue& other) const @@ -304,7 +301,6 @@ ALWAYS_INLINE JSCell* JSValue::asCell() const ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d) { - ASSERT(!isImpureNaN(d)); u.asDouble = d; } @@ -314,7 +310,7 @@ inline JSValue::JSValue(int i) u.asBits.payload = i; } -#if !ENABLE(JIT) +#if ENABLE(LLINT_C_LOOP) inline JSValue::JSValue(int32_t tag, int32_t payload) { u.asBits.tag = tag; @@ -329,7 +325,7 @@ inline bool JSValue::isNumber() const inline bool JSValue::isBoolean() const { - return tag() == BooleanTag; + return isTrue() || isFalse(); } inline bool JSValue::asBoolean() const @@ -362,9 +358,9 @@ inline JSValue::JSValue(const JSCell* ptr) u.asInt64 = reinterpret_cast<uintptr_t>(const_cast<JSCell*>(ptr)); } -inline JSValue::operator bool() const +inline JSValue::operator UnspecifiedBoolType*() const { - return u.asInt64; + return u.asInt64 ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; } inline bool JSValue::operator==(const JSValue& other) const @@ -471,7 +467,6 @@ inline double reinterpretInt64ToDouble(int64_t value) ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d) { - ASSERT(!isImpureNaN(d)); u.asInt64 = reinterpretDoubleToInt64(d) + DoubleEncodeOffset; } @@ -499,43 +494,25 @@ ALWAYS_INLINE JSCell* JSValue::asCell() const #endif // USE(JSVALUE64) -inline int64_t tryConvertToInt52(double number) -{ - if (number != number) - return JSValue::notInt52; -#if OS(WINDOWS) && CPU(X86) - // The VS Compiler for 32-bit builds generates a floating point error when attempting to cast - // from an infinity to a 64-bit integer. We leave this routine with the floating point error - // left in a register, causing undefined behavior in later floating point operations. - // - // To avoid this issue, we check for infinity here, and return false in that case. - if (std::isinf(number)) - return JSValue::notInt52; -#endif - int64_t asInt64 = static_cast<int64_t>(number); - if (asInt64 != number) - return JSValue::notInt52; - if (!asInt64 && std::signbit(number)) - return JSValue::notInt52; - if (asInt64 >= (static_cast<int64_t>(1) << (JSValue::numberOfInt52Bits - 1))) - return JSValue::notInt52; - if (asInt64 < -(static_cast<int64_t>(1) << (JSValue::numberOfInt52Bits - 1))) - return JSValue::notInt52; - return asInt64; -} - -inline bool isInt52(double number) -{ - return tryConvertToInt52(number) != JSValue::notInt52; -} - inline bool JSValue::isMachineInt() const { if (isInt32()) return true; if (!isNumber()) return false; - return isInt52(asDouble()); + double number = asDouble(); + if (number != number) + return false; + int64_t asInt64 = static_cast<int64_t>(number); + if (asInt64 != number) + return false; + if (!asInt64 && std::signbit(number)) + return false; + if (asInt64 >= (static_cast<int64_t>(1) << (numberOfInt52Bits - 1))) + return false; + if (asInt64 < -(static_cast<int64_t>(1) << (numberOfInt52Bits - 1))) + return false; + return true; } inline int64_t JSValue::asMachineInt() const @@ -551,14 +528,9 @@ inline bool JSValue::isString() const return isCell() && asCell()->isString(); } -inline bool JSValue::isSymbol() const -{ - return isCell() && asCell()->isSymbol(); -} - inline bool JSValue::isPrimitive() const { - return !isCell() || asCell()->isString() || asCell()->isSymbol(); + return !isCell() || asCell()->isString(); } inline bool JSValue::isGetterSetter() const @@ -566,11 +538,6 @@ inline bool JSValue::isGetterSetter() const return isCell() && asCell()->isGetterSetter(); } -inline bool JSValue::isCustomGetterSetter() const -{ - return isCell() && asCell()->isCustomGetterSetter(); -} - inline bool JSValue::isObject() const { return isCell() && asCell()->isObject(); @@ -611,17 +578,6 @@ ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const return false; } -ALWAYS_INLINE Identifier JSValue::toPropertyKey(ExecState* exec) const -{ - if (isString()) - return asString(*this)->toIdentifier(exec); - - JSValue primitive = toPrimitive(exec, PreferString); - if (primitive.isSymbol()) - return Identifier::fromUid(asSymbol(primitive)->privateName()); - return primitive.toString(exec)->toIdentifier(exec); -} - inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const { return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue(); @@ -652,7 +608,7 @@ inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue return true; } ASSERT(isUndefined()); - number = PNaN; + number = QNaN; value = *this; return true; } @@ -689,49 +645,45 @@ inline bool JSValue::inherits(const ClassInfo* classInfo) const inline JSValue JSValue::toThis(ExecState* exec, ECMAMode ecmaMode) const { - return isCell() ? asCell()->methodTable(exec->vm())->toThis(asCell(), exec, ecmaMode) : toThisSlowCase(exec, ecmaMode); + return isCell() ? asCell()->methodTable()->toThis(asCell(), exec, ecmaMode) : toThisSlowCase(exec, ecmaMode); } -ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, PropertyName propertyName) const +inline JSValue JSValue::get(ExecState* exec, PropertyName propertyName) const { PropertySlot slot(asValue()); return get(exec, propertyName, slot); } -ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, PropertyName propertyName, PropertySlot& slot) const -{ - return getPropertySlot(exec, propertyName, slot) ? - slot.getValue(exec, propertyName) : jsUndefined(); -} - -ALWAYS_INLINE bool JSValue::getPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot) const +inline JSValue JSValue::get(ExecState* exec, PropertyName propertyName, PropertySlot& slot) const { // If this is a primitive, we'll need to synthesize the prototype - // and if it's a string there are special properties to check first. JSObject* object; if (UNLIKELY(!isObject())) { - if (isString() && asString(*this)->getStringPropertySlot(exec, propertyName, slot)) - return true; + if (isCell() && asString(*this)->getStringPropertySlot(exec, propertyName, slot)) + return slot.getValue(exec, propertyName); object = synthesizePrototype(exec); } else object = asObject(asCell()); - return object->getPropertySlot(exec, propertyName, slot); + if (object->getPropertySlot(exec, propertyName, slot)) + return slot.getValue(exec, propertyName); + return jsUndefined(); } -ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, unsigned propertyName) const +inline JSValue JSValue::get(ExecState* exec, unsigned propertyName) const { PropertySlot slot(asValue()); return get(exec, propertyName, slot); } -ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const +inline JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const { // If this is a primitive, we'll need to synthesize the prototype - // and if it's a string there are special properties to check first. JSObject* object; if (UNLIKELY(!isObject())) { - if (isString() && asString(*this)->getStringPropertySlot(exec, propertyName, slot)) + if (isCell() && asString(*this)->getStringPropertySlot(exec, propertyName, slot)) return slot.getValue(exec, propertyName); object = synthesizePrototype(exec); } else @@ -748,7 +700,7 @@ inline void JSValue::put(ExecState* exec, PropertyName propertyName, JSValue val putToPrimitive(exec, propertyName, value, slot); return; } - asCell()->methodTable(exec->vm())->put(asCell(), exec, propertyName, value, slot); + asCell()->methodTable()->put(asCell(), exec, propertyName, value, slot); } inline void JSValue::putByIndex(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow) @@ -757,7 +709,7 @@ inline void JSValue::putByIndex(ExecState* exec, unsigned propertyName, JSValue putToPrimitiveByIndex(exec, propertyName, value, shouldThrow); return; } - asCell()->methodTable(exec->vm())->putByIndex(asCell(), exec, propertyName, value, shouldThrow); + asCell()->methodTable()->putByIndex(asCell(), exec, propertyName, value, shouldThrow); } inline JSValue JSValue::structureOrUndefined() const @@ -778,7 +730,6 @@ inline bool JSValue::equal(ExecState* exec, JSValue v1, JSValue v2) ALWAYS_INLINE bool JSValue::equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2) { - VM& vm = exec->vm(); do { if (v1.isNumber() && v2.isNumber()) return v1.asNumber() == v2.asNumber(); @@ -786,20 +737,20 @@ ALWAYS_INLINE bool JSValue::equalSlowCaseInline(ExecState* exec, JSValue v1, JSV bool s1 = v1.isString(); bool s2 = v2.isString(); if (s1 && s2) - return WTF::equal(*asString(v1)->value(exec).impl(), *asString(v2)->value(exec).impl()); + 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(vm)->masqueradesAsUndefined(exec->lexicalGlobalObject()); + return v2.asCell()->structure()->masqueradesAsUndefined(exec->lexicalGlobalObject()); } if (v2.isUndefinedOrNull()) { if (!v1.isCell()) return false; - return v1.asCell()->structure(vm)->masqueradesAsUndefined(exec->lexicalGlobalObject()); + return v1.asCell()->structure()->masqueradesAsUndefined(exec->lexicalGlobalObject()); } if (v1.isObject()) { @@ -824,14 +775,6 @@ ALWAYS_INLINE bool JSValue::equalSlowCaseInline(ExecState* exec, JSValue v1, JSV continue; } - bool sym1 = v1.isSymbol(); - bool sym2 = v2.isSymbol(); - if (sym1 || sym2) { - if (sym1 && sym2) - return asSymbol(v1)->privateName() == asSymbol(v2)->privateName(); - return false; - } - if (s1 || s2) { double d1 = v1.toNumber(exec); double d2 = v2.toNumber(exec); @@ -856,9 +799,7 @@ ALWAYS_INLINE bool JSValue::strictEqualSlowCaseInline(ExecState* exec, JSValue v ASSERT(v1.isCell() && v2.isCell()); if (v1.asCell()->isString() && v2.asCell()->isString()) - return WTF::equal(*asString(v1)->value(exec).impl(), *asString(v2)->value(exec).impl()); - if (v1.asCell()->isSymbol() && v2.asCell()->isSymbol()) - return asSymbol(v1)->privateName() == asSymbol(v2)->privateName(); + return asString(v1)->value(exec) == asString(v2)->value(exec); return v1 == v2; } @@ -877,13 +818,6 @@ inline bool JSValue::strictEqual(ExecState* exec, JSValue v1, JSValue v2) return strictEqualSlowCaseInline(exec, v1, v2); } -inline int32_t JSValue::asInt32ForArithmetic() const -{ - if (isBoolean()) - return asBoolean(); - return asInt32(); -} - inline TriState JSValue::pureStrictEqual(JSValue v1, JSValue v2) { if (v1.isInt32() && v2.isInt32()) @@ -900,7 +834,7 @@ inline TriState JSValue::pureStrictEqual(JSValue v1, JSValue v2) const StringImpl* v2String = asString(v2)->tryGetValueImpl(); if (!v1String || !v2String) return MixedTriState; - return triState(WTF::equal(*v1String, *v2String)); + return triState(WTF::equal(v1String, v2String)); } return triState(v1 == v2); @@ -917,14 +851,6 @@ inline TriState JSValue::pureToBoolean() const return isTrue() ? TrueTriState : FalseTriState; } -ALWAYS_INLINE bool JSValue::requireObjectCoercible(ExecState* exec) const -{ - if (!isUndefinedOrNull()) - return true; - exec->vm().throwException(exec, createNotAnObjectError(exec, *this)); - return false; -} - } // namespace JSC #endif // JSValueInlines_h diff --git a/Source/JavaScriptCore/runtime/JSCallee.cpp b/Source/JavaScriptCore/runtime/JSCallee.cpp deleted file mode 100644 index d303296cc..000000000 --- a/Source/JavaScriptCore/runtime/JSCallee.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2014 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 "JSCallee.h" - -#include "GetterSetter.h" -#include "JSCJSValueInlines.h" -#include "JSCell.h" -#include "JSCellInlines.h" -#include "JSGlobalObject.h" -#include "SlotVisitorInlines.h" -#include "StackVisitor.h" -#include "StructureInlines.h" - -namespace JSC { - -const ClassInfo JSCallee::s_info = { "Callee", &Base::s_info, 0, CREATE_METHOD_TABLE(JSCallee) }; - -JSCallee::JSCallee(VM& vm, JSGlobalObject* globalObject, Structure* structure) - : Base(vm, structure) - , m_scope(vm, this, globalObject) -{ -} - -JSCallee::JSCallee(VM& vm, JSScope* scope, Structure* structure) - : Base(vm, structure) -{ - setScope(vm, scope); -} - -void JSCallee::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); -} - -void JSCallee::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - JSCallee* thisObject = jsCast<JSCallee*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - Base::visitChildren(thisObject, visitor); - - visitor.append(&thisObject->m_scope); -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSCallee.h b/Source/JavaScriptCore/runtime/JSCallee.h deleted file mode 100644 index 1545eddc7..000000000 --- a/Source/JavaScriptCore/runtime/JSCallee.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2014 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 JSCallee_h -#define JSCallee_h - -#include "JSGlobalObject.h" -#include "JSObject.h" -#include "JSScope.h" - -namespace JSC { - -class JSGlobalObject; -class LLIntOffsetsExtractor; - - -class JSCallee : public JSNonFinalObject { - friend class JIT; -#if ENABLE(DFG_JIT) - friend class DFG::SpeculativeJIT; - friend class DFG::JITCompiler; -#endif - friend class VM; - -public: - typedef JSNonFinalObject Base; - const static unsigned StructureFlags = Base::StructureFlags | ImplementsHasInstance; - - static JSCallee* create(VM& vm, JSGlobalObject* globalObject, JSScope* scope) - { - JSCallee* callee = new (NotNull, allocateCell<JSCallee>(vm.heap)) JSCallee(vm, scope, globalObject->calleeStructure()); - callee->finishCreation(vm); - return callee; - } - - JSScope* scope() - { - return m_scope.get(); - } - - // This method may be called for host functions, in which case it - // will return an arbitrary value. This should only be used for - // optimized paths in which the return value does not matter for - // host functions, and checking whether the function is a host - // function is deemed too expensive. - JSScope* scopeUnchecked() - { - return m_scope.get(); - } - - void setScope(VM& vm, JSScope* scope) - { - m_scope.set(vm, this, scope); - } - - DECLARE_EXPORT_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - ASSERT(globalObject); - return Structure::create(vm, globalObject, prototype, TypeInfo(JSCalleeType, StructureFlags), info()); - } - - static inline ptrdiff_t offsetOfScopeChain() - { - return OBJECT_OFFSETOF(JSCallee, m_scope); - } - -protected: - JS_EXPORT_PRIVATE JSCallee(VM&, JSGlobalObject*, Structure*); - JSCallee(VM&, JSScope*, Structure*); - - void finishCreation(VM&); - using Base::finishCreation; - - static void visitChildren(JSCell*, SlotVisitor&); - -private: - friend class LLIntOffsetsExtractor; - - WriteBarrier<JSScope> m_scope; -}; - -} // namespace JSC - -#endif // JSCallee_h diff --git a/Source/JavaScriptCore/runtime/JSCell.cpp b/Source/JavaScriptCore/runtime/JSCell.cpp index 2c403c813..f472a9679 100644 --- a/Source/JavaScriptCore/runtime/JSCell.cpp +++ b/Source/JavaScriptCore/runtime/JSCell.cpp @@ -28,12 +28,11 @@ #include "JSString.h" #include "JSObject.h" #include "NumberObject.h" -#include "JSCInlines.h" +#include "Operations.h" #include <wtf/MathExtras.h> namespace JSC { -COMPILE_ASSERT(sizeof(JSCell) == sizeof(uint64_t), jscell_is_eight_bytes); STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSCell); void JSCell::destroy(JSCell* cell) @@ -41,16 +40,6 @@ void JSCell::destroy(JSCell* cell) cell->JSCell::~JSCell(); } -void JSCell::dump(PrintStream& out) const -{ - methodTable()->dumpToStream(this, out); -} - -void JSCell::dumpToStream(const JSCell* cell, PrintStream& out) -{ - out.printf("<%p, %s>", cell, cell->className()); -} - void JSCell::copyBackingStore(JSCell*, CopyVisitor&, CopyToken) { } @@ -96,35 +85,35 @@ ConstructType JSCell::getConstructData(JSCell*, ConstructData& constructData) void JSCell::put(JSCell* cell, ExecState* exec, PropertyName identifier, JSValue value, PutPropertySlot& slot) { - if (cell->isString() || cell->isSymbol()) { + if (cell->isString()) { JSValue(cell).putToPrimitive(exec, identifier, value, slot); return; } JSObject* thisObject = cell->toObject(exec, exec->lexicalGlobalObject()); - thisObject->methodTable(exec->vm())->put(thisObject, exec, identifier, value, slot); + thisObject->methodTable()->put(thisObject, exec, identifier, value, slot); } void JSCell::putByIndex(JSCell* cell, ExecState* exec, unsigned identifier, JSValue value, bool shouldThrow) { - if (cell->isString() || cell->isSymbol()) { + if (cell->isString()) { PutPropertySlot slot(cell, shouldThrow); JSValue(cell).putToPrimitive(exec, Identifier::from(exec, identifier), value, slot); return; } JSObject* thisObject = cell->toObject(exec, exec->lexicalGlobalObject()); - thisObject->methodTable(exec->vm())->putByIndex(thisObject, exec, identifier, value, shouldThrow); + thisObject->methodTable()->putByIndex(thisObject, exec, identifier, value, shouldThrow); } bool JSCell::deleteProperty(JSCell* cell, ExecState* exec, PropertyName identifier) { JSObject* thisObject = cell->toObject(exec, exec->lexicalGlobalObject()); - return thisObject->methodTable(exec->vm())->deleteProperty(thisObject, exec, identifier); + return thisObject->methodTable()->deleteProperty(thisObject, exec, identifier); } bool JSCell::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned identifier) { JSObject* thisObject = cell->toObject(exec, exec->lexicalGlobalObject()); - return thisObject->methodTable(exec->vm())->deletePropertyByIndex(thisObject, exec, identifier); + return thisObject->methodTable()->deletePropertyByIndex(thisObject, exec, identifier); } JSValue JSCell::toThis(JSCell* cell, ExecState* exec, ECMAMode ecmaMode) @@ -138,8 +127,6 @@ JSValue JSCell::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredTyp { if (isString()) return static_cast<const JSString*>(this)->toPrimitive(exec, preferredType); - if (isSymbol()) - return static_cast<const Symbol*>(this)->toPrimitive(exec, preferredType); return static_cast<const JSObject*>(this)->toPrimitive(exec, preferredType); } @@ -147,8 +134,6 @@ bool JSCell::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value) { if (isString()) return static_cast<const JSString*>(this)->getPrimitiveNumber(exec, number, value); - if (isSymbol()) - return static_cast<const Symbol*>(this)->getPrimitiveNumber(exec, number, value); return static_cast<const JSObject*>(this)->getPrimitiveNumber(exec, number, value); } @@ -156,8 +141,6 @@ double JSCell::toNumber(ExecState* exec) const { if (isString()) return static_cast<const JSString*>(this)->toNumber(exec); - if (isSymbol()) - return static_cast<const Symbol*>(this)->toNumber(exec); return static_cast<const JSObject*>(this)->toNumber(exec); } @@ -165,8 +148,6 @@ JSObject* JSCell::toObject(ExecState* exec, JSGlobalObject* globalObject) const { if (isString()) return static_cast<const JSString*>(this)->toObject(exec, globalObject); - if (isSymbol()) - return static_cast<const Symbol*>(this)->toObject(exec, globalObject); ASSERT(isObject()); return jsCast<JSObject*>(const_cast<JSCell*>(this)); } @@ -210,7 +191,7 @@ String JSCell::className(const JSObject*) return String(); } -const char* JSCell::className() const +const char* JSCell::className() { return classInfo()->className; } @@ -244,20 +225,4 @@ PassRefPtr<ArrayBufferView> JSCell::getTypedArrayImpl(JSArrayBufferView*) return 0; } -uint32_t JSCell::getEnumerableLength(ExecState*, JSObject*) -{ - RELEASE_ASSERT_NOT_REACHED(); - return 0; -} - -void JSCell::getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode) -{ - RELEASE_ASSERT_NOT_REACHED(); -} - -void JSCell::getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode) -{ - RELEASE_ASSERT_NOT_REACHED(); -} - } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h index 6d648ad26..de85a4bdc 100644 --- a/Source/JavaScriptCore/runtime/JSCell.h +++ b/Source/JavaScriptCore/runtime/JSCell.h @@ -25,11 +25,8 @@ #include "CallData.h" #include "ConstructData.h" -#include "EnumerationMode.h" #include "Heap.h" -#include "IndexingType.h" #include "JSLock.h" -#include "JSTypeInfo.h" #include "SlotVisitor.h" #include "TypedArrayType.h" #include "WriteBarrier.h" @@ -39,7 +36,6 @@ namespace JSC { class CopyVisitor; class ExecState; -class Identifier; class JSArrayBufferView; class JSDestructibleObject; class JSGlobalObject; @@ -48,6 +44,11 @@ class PropertyDescriptor; class PropertyNameArray; class Structure; +enum EnumerationMode { + ExcludeDontEnumProperties, + IncludeDontEnumProperties +}; + template<typename T> void* allocateCell(Heap&); template<typename T> void* allocateCell(Heap&, size_t); @@ -73,8 +74,7 @@ public: static const unsigned StructureFlags = 0; static const bool needsDestruction = false; - - static JSCell* seenMultipleCalleeObjects() { return bitwise_cast<JSCell*>(static_cast<uintptr_t>(1)); } + static const bool hasImmortalStructure = false; enum CreatingEarlyCellTag { CreatingEarlyCell }; JSCell(CreatingEarlyCellTag); @@ -86,27 +86,17 @@ protected: public: // Querying the type. bool isString() const; - bool isSymbol() const; bool isObject() const; bool isGetterSetter() const; - bool isCustomGetterSetter() const; bool isProxy() const; bool inherits(const ClassInfo*) const; bool isAPIValueWrapper() const; - JSType type() const; - IndexingType indexingType() const; - StructureID structureID() const { return m_structureID; } Structure* structure() const; - Structure* structure(VM&) const; void setStructure(VM&, Structure*); - void clearStructure() { m_structureID = 0; } - - TypeInfo::InlineTypeFlags inlineTypeFlags() const { return m_flags; } + void clearStructure() { m_structure.clear(); } - const char* className() const; - - VM* vm() const; + const char* className(); // Extracting the value. JS_EXPORT_PRIVATE bool getString(ExecState*, String&) const; @@ -114,12 +104,6 @@ public: JS_EXPORT_PRIVATE JSObject* getObject(); // NULL if not an object const JSObject* getObject() const; // NULL if not an object - // Returns information about how to call/construct this cell as a function/constructor. May tell - // you that the cell is not callable or constructor (default is that it's not either). If it - // says that the function is callable, and the TypeOfShouldCallGetCallData type flag is set, and - // this is an object, then typeof will return "function" instead of "object". These methods - // cannot change their minds and must be thread-safe. They are sometimes called from compiler - // threads. JS_EXPORT_PRIVATE static CallType getCallData(JSCell*, CallData&); JS_EXPORT_PRIVATE static ConstructType getConstructData(JSCell*, ConstructData&); @@ -131,15 +115,13 @@ public: JS_EXPORT_PRIVATE double toNumber(ExecState*) const; JS_EXPORT_PRIVATE JSObject* toObject(ExecState*, JSGlobalObject*) const; - void dump(PrintStream&) const; - JS_EXPORT_PRIVATE static void dumpToStream(const JSCell*, PrintStream&); static void visitChildren(JSCell*, SlotVisitor&); JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken); // Object operations, with the toObject operation included. const ClassInfo* classInfo() const; const MethodTable* methodTable() const; - const MethodTable* methodTable(VM&) const; + const MethodTable* methodTableForDestruction() const; static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); @@ -151,65 +133,22 @@ public: void zap() { *reinterpret_cast<uintptr_t**>(this) = 0; } bool isZapped() const { return !*reinterpret_cast<uintptr_t* const*>(this); } - static bool canUseFastGetOwnProperty(const Structure&); - JSValue fastGetOwnProperty(VM&, Structure&, PropertyName); - - enum GCData : uint8_t { - Marked = 0, // The object has survived a GC and is in the old gen. - NotMarked = 1, // The object is new and in the eden gen. - MarkedAndRemembered = 2, // The object is in the GC's remembered set. - - // The object being in the GC's remembered set implies that it is also - // Marked. This is because objects are only added to the remembered sets - // by write barriers, and write barriers are only interested in old gen - // objects that point to potential eden gen objects. - }; - - void setMarked() { m_gcData = Marked; } - void setRemembered(bool remembered) - { - ASSERT(m_gcData == (remembered ? Marked : MarkedAndRemembered)); - m_gcData = remembered ? MarkedAndRemembered : Marked; - } - bool isMarked() const - { - switch (m_gcData) { - case Marked: - case MarkedAndRemembered: - return true; - case NotMarked: - return false; - } - RELEASE_ASSERT_NOT_REACHED(); - return false; - } - bool isRemembered() const { return m_gcData == MarkedAndRemembered; } - - static ptrdiff_t structureIDOffset() - { - return OBJECT_OFFSETOF(JSCell, m_structureID); - } - - static ptrdiff_t typeInfoFlagsOffset() - { - return OBJECT_OFFSETOF(JSCell, m_flags); - } - - static ptrdiff_t typeInfoTypeOffset() - { - return OBJECT_OFFSETOF(JSCell, m_type); - } + JSValue fastGetOwnProperty(ExecState*, const String&); - static ptrdiff_t indexingTypeOffset() + static ptrdiff_t structureOffset() { - return OBJECT_OFFSETOF(JSCell, m_indexingType); + return OBJECT_OFFSETOF(JSCell, m_structure); } - static ptrdiff_t gcDataOffset() + void* structureAddress() { - return OBJECT_OFFSETOF(JSCell, m_gcData); + return &m_structure; } - + +#if ENABLE(GC_VALIDATION) + Structure* unvalidatedStructure() const { return m_structure.unvalidatedGet(); } +#endif + static const TypedArrayType TypedArrayStorageType = NotTypedArray; protected: @@ -221,11 +160,6 @@ protected: 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 uint32_t getEnumerableLength(ExecState*, JSObject*); - static NO_RETURN_DUE_TO_CRASH void getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - static NO_RETURN_DUE_TO_CRASH void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - static String className(const JSObject*); JS_EXPORT_PRIVATE static bool customHasInstance(JSObject*, ExecState*, JSValue); static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow); @@ -236,42 +170,34 @@ protected: private: friend class LLIntOffsetsExtractor; - - StructureID m_structureID; - IndexingType m_indexingType; - JSType m_type; - TypeInfo::InlineTypeFlags m_flags; - uint8_t m_gcData; + + WriteBarrier<Structure> m_structure; }; template<typename To, typename From> inline To jsCast(From* from) { - ASSERT_WITH_SECURITY_IMPLICATION(!from || from->JSCell::inherits(std::remove_pointer<To>::type::info())); + ASSERT(!from || from->JSCell::inherits(std::remove_pointer<To>::type::info())); return static_cast<To>(from); } template<typename To> inline To jsCast(JSValue from) { - ASSERT_WITH_SECURITY_IMPLICATION(from.isCell() && from.asCell()->JSCell::inherits(std::remove_pointer<To>::type::info())); + ASSERT(from.isCell() && from.asCell()->JSCell::inherits(std::remove_pointer<To>::type::info())); return static_cast<To>(from.asCell()); } template<typename To, typename From> inline To jsDynamicCast(From* from) { - if (LIKELY(from->inherits(std::remove_pointer<To>::type::info()))) - return static_cast<To>(from); - return nullptr; + return from->inherits(std::remove_pointer<To>::type::info()) ? static_cast<To>(from) : 0; } template<typename To> inline To jsDynamicCast(JSValue from) { - if (LIKELY(from.isCell() && from.asCell()->inherits(std::remove_pointer<To>::type::info()))) - return static_cast<To>(from.asCell()); - return nullptr; + return from.isCell() && from.asCell()->inherits(std::remove_pointer<To>::type::info()) ? static_cast<To>(from.asCell()) : 0; } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSCellInlines.h b/Source/JavaScriptCore/runtime/JSCellInlines.h index c4019ff4e..f7c844645 100644 --- a/Source/JavaScriptCore/runtime/JSCellInlines.h +++ b/Source/JavaScriptCore/runtime/JSCellInlines.h @@ -30,28 +30,20 @@ #include "DeferGC.h" #include "Handle.h" #include "JSCell.h" -#include "JSDestructibleObject.h" #include "JSObject.h" #include "JSString.h" -#include "MarkedBlock.h" #include "Structure.h" -#include "Symbol.h" #include <wtf/CompilationThread.h> namespace JSC { inline JSCell::JSCell(CreatingEarlyCellTag) - : m_gcData(NotMarked) { ASSERT(!isCompilationThread()); } -inline JSCell::JSCell(VM&, Structure* structure) - : m_structureID(structure->id()) - , m_indexingType(structure->indexingType()) - , m_type(structure->typeInfo().type()) - , m_flags(structure->typeInfo().inlineTypeFlags()) - , m_gcData(NotMarked) +inline JSCell::JSCell(VM& vm, Structure* structure) + : m_structure(vm, this, structure) { ASSERT(!isCompilationThread()); } @@ -64,7 +56,7 @@ inline void JSCell::finishCreation(VM& vm) #else UNUSED_PARAM(vm); #endif - ASSERT(m_structureID); + ASSERT(m_structure); } inline void JSCell::finishCreation(VM& vm, Structure* structure, CreatingEarlyCellTag) @@ -72,57 +64,23 @@ inline void JSCell::finishCreation(VM& vm, Structure* structure, CreatingEarlyCe #if ENABLE(GC_VALIDATION) ASSERT(vm.isInitializingObject()); vm.setInitializingObjectClass(0); - if (structure) { -#endif - m_structureID = structure->id(); - m_indexingType = structure->indexingType(); - m_type = structure->typeInfo().type(); - m_flags = structure->typeInfo().inlineTypeFlags(); -#if ENABLE(GC_VALIDATION) - } -#else - UNUSED_PARAM(vm); + if (structure) #endif + m_structure.setEarlyValue(vm, this, structure); // Very first set of allocations won't have a real structure. - ASSERT(m_structureID || !vm.structureStructure); -} - -inline JSType JSCell::type() const -{ - return m_type; -} - -inline IndexingType JSCell::indexingType() const -{ - return m_indexingType; + ASSERT(m_structure || !vm.structureStructure); } inline Structure* JSCell::structure() const { - return Heap::heap(this)->structureIDTable().get(m_structureID); -} - -inline Structure* JSCell::structure(VM& vm) const -{ - return vm.heap.structureIDTable().get(m_structureID); + return m_structure.get(); } inline void JSCell::visitChildren(JSCell* cell, SlotVisitor& visitor) { - Structure* structure = cell->structure(visitor.vm()); - visitor.appendUnbarrieredPointer(&structure); -} + MARK_LOG_PARENT(visitor, cell); -inline VM* JSCell::vm() const -{ - return MarkedBlock::blockFor(this)->vm(); -} - -inline VM& ExecState::vm() const -{ - ASSERT(callee()); - ASSERT(callee()->vm()); - return *calleeAsValue().asCell()->vm(); + visitor.append(&cell->m_structure); } template<typename T> @@ -130,7 +88,13 @@ void* allocateCell(Heap& heap, size_t size) { ASSERT(!DisallowGC::isGCDisallowedOnCurrentThread()); ASSERT(size >= sizeof(T)); - JSCell* result = static_cast<JSCell*>(heap.allocateObjectOfType<T>(size)); + 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)); #if ENABLE(GC_VALIDATION) ASSERT(!heap.vm()->isInitializingObject()); heap.vm()->setInitializingObjectClass(T::info()); @@ -152,69 +116,50 @@ inline bool isZapped(const JSCell* cell) inline bool JSCell::isObject() const { - return TypeInfo::isObject(m_type); + return m_structure->isObject(); } inline bool JSCell::isString() const { - return m_type == StringType; -} - -inline bool JSCell::isSymbol() const -{ - return m_type == SymbolType; + return m_structure->typeInfo().type() == StringType; } inline bool JSCell::isGetterSetter() const { - return m_type == GetterSetterType; -} - -inline bool JSCell::isCustomGetterSetter() const -{ - return m_type == CustomGetterSetterType; + return m_structure->typeInfo().type() == GetterSetterType; } inline bool JSCell::isProxy() const { - return m_type == ImpureProxyType || m_type == PureForwardingProxyType; + return structure()->typeInfo().type() == ProxyType; } inline bool JSCell::isAPIValueWrapper() const { - return m_type == APIValueWrapperType; + return m_structure->typeInfo().type() == APIValueWrapperType; } inline void JSCell::setStructure(VM& vm, Structure* structure) { - ASSERT(structure->classInfo() == this->structure()->classInfo()); - ASSERT(!this->structure() - || this->structure()->transitionWatchpointSetHasBeenInvalidated() - || Heap::heap(this)->structureIDTable().get(structure->id()) == structure); - vm.heap.writeBarrier(this, structure); - m_structureID = structure->id(); - m_flags = structure->typeInfo().inlineTypeFlags(); - m_type = structure->typeInfo().type(); - m_indexingType = structure->indexingType(); + 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::methodTable() const +inline const MethodTable* JSCell::methodTableForDestruction() const { - VM& vm = *Heap::heap(this)->vm(); - Structure* structure = this->structure(vm); - if (Structure* rootStructure = structure->structure(vm)) - RELEASE_ASSERT(rootStructure == rootStructure->structure(vm)); - - return &structure->classInfo()->methodTable; + return &classInfo()->methodTable; } -inline const MethodTable* JSCell::methodTable(VM& vm) const +inline const MethodTable* JSCell::methodTable() const { - Structure* structure = this->structure(vm); - if (Structure* rootStructure = structure->structure(vm)) - RELEASE_ASSERT(rootStructure == rootStructure->structure(vm)); + if (Structure* rootStructure = m_structure->structure()) + RELEASE_ASSERT(rootStructure == rootStructure->structure()); - return &structure->classInfo()->methodTable; + return &classInfo()->methodTable; } inline bool JSCell::inherits(const ClassInfo* info) const @@ -222,43 +167,33 @@ inline bool JSCell::inherits(const ClassInfo* info) const return classInfo()->isSubClassOf(info); } -ALWAYS_INLINE JSValue JSCell::fastGetOwnProperty(VM& vm, Structure& structure, PropertyName name) +// 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) { - ASSERT(canUseFastGetOwnProperty(structure)); - PropertyOffset offset = structure.get(vm, name); - if (offset != invalidOffset) - return asObject(this)->locationForOffset(offset)->get(); + 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::canUseFastGetOwnProperty(const Structure& structure) -{ - return !structure.hasGetterSetterProperties() - && !structure.hasCustomGetterSetterProperties() - && !structure.typeInfo().overridesGetOwnPropertySlot(); -} - -inline const ClassInfo* JSCell::classInfo() const -{ - MarkedBlock* block = MarkedBlock::blockFor(this); - if (block->needsDestruction() && !(inlineTypeFlags() & StructureIsImmortal)) - return static_cast<const JSDestructibleObject*>(this)->classInfo(); - return structure(*block->vm())->classInfo(); -} - inline bool JSCell::toBoolean(ExecState* exec) const { - if (isString()) + if (isString()) return static_cast<const JSString*>(this)->toBoolean(); return !structure()->masqueradesAsUndefined(exec->lexicalGlobalObject()); } inline TriState JSCell::pureToBoolean() const { - if (isString()) + if (isString()) return static_cast<const JSString*>(this)->toBoolean() ? TrueTriState : FalseTriState; - if (isSymbol()) - return TrueTriState; return MixedTriState; } diff --git a/Source/JavaScriptCore/runtime/JSDataView.cpp b/Source/JavaScriptCore/runtime/JSDataView.cpp index 513d4c6b3..77640cdaf 100644 --- a/Source/JavaScriptCore/runtime/JSDataView.cpp +++ b/Source/JavaScriptCore/runtime/JSDataView.cpp @@ -29,12 +29,12 @@ #include "ArrayBufferView.h" #include "DataView.h" #include "Error.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { const ClassInfo JSDataView::s_info = { - "DataView", &Base::s_info, 0, CREATE_METHOD_TABLE(JSDataView)}; + "DataView", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSDataView)}; JSDataView::JSDataView(VM& vm, ConstructionContext& context, ArrayBuffer* buffer) : Base(vm, context) @@ -47,13 +47,10 @@ JSDataView* JSDataView::create( unsigned byteOffset, unsigned byteLength) { RefPtr<ArrayBuffer> buffer = passedBuffer; - if (!ArrayBufferView::verifySubRangeLength(buffer, byteOffset, byteLength, sizeof(uint8_t))) { - throwVMError(exec, createRangeError(exec, ASCIILiteral("Length out of range of buffer"))); - return nullptr; - } - if (!ArrayBufferView::verifyByteOffsetAlignment(byteOffset, sizeof(uint8_t))) { - exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Byte offset is not aligned"))); - return nullptr; + if (!ArrayBufferView::verifySubRange<uint8_t>(buffer, byteOffset, byteLength)) { + throwVMError( + exec, createRangeError(exec, "Byte offset and length out of range of buffer")); + return 0; } VM& vm = exec->vm(); ConstructionContext context( @@ -116,7 +113,7 @@ Structure* JSDataView::createStructure( VM& vm, JSGlobalObject* globalObject, JSValue prototype) { return Structure::create( - vm, globalObject, prototype, TypeInfo(DataViewType, StructureFlags), info(), + vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), NonArray); } diff --git a/Source/JavaScriptCore/runtime/JSDataViewPrototype.cpp b/Source/JavaScriptCore/runtime/JSDataViewPrototype.cpp index dd5b44e5b..cd7e88313 100644 --- a/Source/JavaScriptCore/runtime/JSDataViewPrototype.cpp +++ b/Source/JavaScriptCore/runtime/JSDataViewPrototype.cpp @@ -29,13 +29,18 @@ #include "Error.h" #include "JSDataView.h" #include "Lookup.h" -#include "JSCInlines.h" +#include "Operations.h" #include "ToNativeFromValue.h" #include "TypedArrayAdaptors.h" #include <wtf/FlipBytes.h> namespace JSC { +const ClassInfo JSDataViewPrototype::s_info = { + "DataViewPrototype", &Base::s_info, 0, ExecState::dataViewTable, + CREATE_METHOD_TABLE(JSDataViewPrototype) +}; + /* Source for JSDataViewPrototype.lut.h @begin dataViewTable getInt8 dataViewProtoFuncGetInt8 DontEnum|Function 0 @@ -57,34 +62,6 @@ namespace JSC { @end */ -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt8(ExecState*); -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt16(ExecState*); -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt32(ExecState*); -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint8(ExecState*); -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint16(ExecState*); -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint32(ExecState*); -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat32(ExecState*); -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat64(ExecState*); -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt8(ExecState*); -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt16(ExecState*); -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt32(ExecState*); -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint8(ExecState*); -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint16(ExecState*); -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint32(ExecState*); -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat32(ExecState*); -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat64(ExecState*); - -} - -#include "JSDataViewPrototype.lut.h" - -namespace JSC { - -const ClassInfo JSDataViewPrototype::s_info = { - "DataViewPrototype", &Base::s_info, &dataViewTable, - CREATE_METHOD_TABLE(JSDataViewPrototype) -}; - JSDataViewPrototype::JSDataViewPrototype(VM& vm, Structure* structure) : Base(vm, structure) { @@ -110,7 +87,7 @@ bool JSDataViewPrototype::getOwnPropertySlot( JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { return getStaticFunctionSlot<JSObject>( - exec, dataViewTable, jsCast<JSDataViewPrototype*>(object), + exec, ExecState::dataViewTable(exec->vm()), jsCast<JSDataViewPrototype*>(object), propertyName, slot); } @@ -119,10 +96,10 @@ EncodedJSValue getData(ExecState* exec) { JSDataView* dataView = jsDynamicCast<JSDataView*>(exec->thisValue()); if (!dataView) - return throwVMError(exec, createTypeError(exec, ASCIILiteral("Receiver of DataView method must be a DataView"))); + return throwVMError(exec, createTypeError(exec, "Receiver of DataView method must be a DataView")); if (!exec->argumentCount()) - return throwVMError(exec, createTypeError(exec, ASCIILiteral("Need at least one argument (the byteOffset)"))); + return throwVMError(exec, createTypeError(exec, "Need at least one argument (the byteOffset)")); unsigned byteOffset = exec->uncheckedArgument(0).toUInt32(exec); if (exec->hadException()) @@ -138,25 +115,14 @@ EncodedJSValue getData(ExecState* exec) unsigned byteLength = dataView->length(); if (elementSize > byteLength || byteOffset > byteLength - elementSize) - return throwVMError(exec, createRangeError(exec, ASCIILiteral("Out of bounds access"))); - - const unsigned dataSize = sizeof(typename Adaptor::Type); - union { - typename Adaptor::Type value; - uint8_t rawBytes[dataSize]; - } u = { }; - - uint8_t* dataPtr = static_cast<uint8_t*>(dataView->vector()) + byteOffset; - - if (needToFlipBytesIfLittleEndian(littleEndian)) { - for (unsigned i = dataSize; i--;) - u.rawBytes[i] = *dataPtr++; - } else { - for (unsigned i = 0; i < dataSize; i++) - u.rawBytes[i] = *dataPtr++; - } - - return JSValue::encode(Adaptor::toJSValue(u.value)); + return throwVMError(exec, createRangeError(exec, "Out of bounds access")); + + typename Adaptor::Type value = *reinterpret_cast<typename Adaptor::Type*>(static_cast<uint8_t*>(dataView->vector()) + byteOffset); + + if (needToFlipBytesIfLittleEndian(littleEndian)) + value = flipBytes(value); + + return JSValue::encode(Adaptor::toJSValue(value)); } template<typename Adaptor> @@ -164,22 +130,16 @@ EncodedJSValue setData(ExecState* exec) { JSDataView* dataView = jsDynamicCast<JSDataView*>(exec->thisValue()); if (!dataView) - return throwVMError(exec, createTypeError(exec, ASCIILiteral("Receiver of DataView method must be a DataView"))); + return throwVMError(exec, createTypeError(exec, "Receiver of DataView method must be a DataView")); if (exec->argumentCount() < 2) - return throwVMError(exec, createTypeError(exec, ASCIILiteral("Need at least two argument (the byteOffset and value)"))); + return throwVMError(exec, createTypeError(exec, "Need at least two argument (the byteOffset and value)")); unsigned byteOffset = exec->uncheckedArgument(0).toUInt32(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); - - const unsigned dataSize = sizeof(typename Adaptor::Type); - union { - typename Adaptor::Type value; - uint8_t rawBytes[dataSize]; - } u; - - u.value = toNativeFromValue<Adaptor>(exec, exec->uncheckedArgument(1)); + + typename Adaptor::Type value = toNativeFromValue<Adaptor>(exec, exec->uncheckedArgument(1)); if (exec->hadException()) return JSValue::encode(jsUndefined()); @@ -193,107 +153,97 @@ EncodedJSValue setData(ExecState* exec) unsigned byteLength = dataView->length(); if (elementSize > byteLength || byteOffset > byteLength - elementSize) - return throwVMError(exec, createRangeError(exec, ASCIILiteral("Out of bounds access"))); - - uint8_t* dataPtr = static_cast<uint8_t*>(dataView->vector()) + byteOffset; - - if (needToFlipBytesIfLittleEndian(littleEndian)) { - for (unsigned i = dataSize; i--;) - *dataPtr++ = u.rawBytes[i]; - } else { - for (unsigned i = 0; i < dataSize; i++) - *dataPtr++ = u.rawBytes[i]; - } - + return throwVMError(exec, createRangeError(exec, "Out of bounds access")); + + if (needToFlipBytesIfLittleEndian(littleEndian)) + value = flipBytes(value); + + *reinterpret_cast<typename Adaptor::Type*>(static_cast<uint8_t*>(dataView->vector()) + byteOffset) = value; + return JSValue::encode(jsUndefined()); } -#if COMPILER(CLANG) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wmissing-prototypes" -#endif - -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt8(ExecState* exec) +static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt8(ExecState* exec) { return getData<Int8Adaptor>(exec); } -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt16(ExecState* exec) +static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt16(ExecState* exec) { return getData<Int16Adaptor>(exec); } -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt32(ExecState* exec) +static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt32(ExecState* exec) { return getData<Int32Adaptor>(exec); } -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint8(ExecState* exec) +static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint8(ExecState* exec) { return getData<Uint8Adaptor>(exec); } -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint16(ExecState* exec) +static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint16(ExecState* exec) { return getData<Uint16Adaptor>(exec); } -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint32(ExecState* exec) +static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint32(ExecState* exec) { return getData<Uint32Adaptor>(exec); } -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat32(ExecState* exec) +static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat32(ExecState* exec) { return getData<Float32Adaptor>(exec); } -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat64(ExecState* exec) +static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat64(ExecState* exec) { return getData<Float64Adaptor>(exec); } -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt8(ExecState* exec) +static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt8(ExecState* exec) { return setData<Int8Adaptor>(exec); } -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt16(ExecState* exec) +static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt16(ExecState* exec) { return setData<Int16Adaptor>(exec); } -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt32(ExecState* exec) +static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt32(ExecState* exec) { return setData<Int32Adaptor>(exec); } -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint8(ExecState* exec) +static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint8(ExecState* exec) { return setData<Uint8Adaptor>(exec); } -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint16(ExecState* exec) +static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint16(ExecState* exec) { return setData<Uint16Adaptor>(exec); } -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint32(ExecState* exec) +static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint32(ExecState* exec) { return setData<Uint32Adaptor>(exec); } -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat32(ExecState* exec) +static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat32(ExecState* exec) { return setData<Float32Adaptor>(exec); } -EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat64(ExecState* exec) +static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat64(ExecState* exec) { return setData<Float64Adaptor>(exec); } -#if COMPILER(CLANG) -#pragma clang diagnostic pop -#endif } // namespace JSC + +#include "JSDataViewPrototype.lut.h" + diff --git a/Source/JavaScriptCore/runtime/JSDataViewPrototype.h b/Source/JavaScriptCore/runtime/JSDataViewPrototype.h index bc72455cc..9d2ba2c6d 100644 --- a/Source/JavaScriptCore/runtime/JSDataViewPrototype.h +++ b/Source/JavaScriptCore/runtime/JSDataViewPrototype.h @@ -33,7 +33,6 @@ namespace JSC { class JSDataViewPrototype : public JSNonFinalObject { public: typedef JSNonFinalObject Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; protected: JSDataViewPrototype(VM&, Structure*); @@ -47,6 +46,8 @@ public: protected: static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | Base::StructureFlags; }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSDateMath.cpp b/Source/JavaScriptCore/runtime/JSDateMath.cpp index 1482e312f..31923d1a5 100644 --- a/Source/JavaScriptCore/runtime/JSDateMath.cpp +++ b/Source/JavaScriptCore/runtime/JSDateMath.cpp @@ -74,7 +74,7 @@ #include "JSObject.h" #include "JSScope.h" -#include "JSCInlines.h" +#include "Operations.h" #include <algorithm> #include <limits.h> @@ -229,7 +229,7 @@ double parseDateFromNullTerminatedCharacters(VM& vm, const char* dateString) int offset; double localTimeMS = WTF::parseDateFromNullTerminatedCharacters(dateString, haveTZ, offset); if (std::isnan(localTimeMS)) - return std::numeric_limits<double>::quiet_NaN(); + return QNaN; // fall back to local timezone. if (!haveTZ) diff --git a/Source/JavaScriptCore/runtime/JSDateMath.h b/Source/JavaScriptCore/runtime/JSDateMath.h index 4e4d16ff5..20a71c93b 100644 --- a/Source/JavaScriptCore/runtime/JSDateMath.h +++ b/Source/JavaScriptCore/runtime/JSDateMath.h @@ -50,11 +50,11 @@ namespace JSC { class VM; -JS_EXPORT_PRIVATE void msToGregorianDateTime(VM&, double, WTF::TimeType outputTimeType, GregorianDateTime&); -JS_EXPORT_PRIVATE double gregorianDateTimeToMS(VM&, const GregorianDateTime&, double, WTF::TimeType inputTimeType); -JS_EXPORT_PRIVATE double getUTCOffset(VM&); -JS_EXPORT_PRIVATE double parseDateFromNullTerminatedCharacters(VM&, const char* dateString); -JS_EXPORT_PRIVATE double parseDate(VM&, const WTF::String&); +void msToGregorianDateTime(VM&, double, WTF::TimeType outputTimeType, GregorianDateTime&); +double gregorianDateTimeToMS(VM&, const GregorianDateTime&, double, WTF::TimeType inputTimeType); +double getUTCOffset(VM&); +double parseDateFromNullTerminatedCharacters(VM&, const char* dateString); +double parseDate(VM&, const WTF::String&); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSDestructibleObject.h b/Source/JavaScriptCore/runtime/JSDestructibleObject.h index d687b8420..27dc06da5 100644 --- a/Source/JavaScriptCore/runtime/JSDestructibleObject.h +++ b/Source/JavaScriptCore/runtime/JSDestructibleObject.h @@ -29,6 +29,17 @@ 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/JSEnvironmentRecord.h b/Source/JavaScriptCore/runtime/JSEnvironmentRecord.h deleted file mode 100644 index fae8f6acf..000000000 --- a/Source/JavaScriptCore/runtime/JSEnvironmentRecord.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2007, 2008, 2012, 2015 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 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 JSEnvironmentRecord_h -#define JSEnvironmentRecord_h - -#include "JSObject.h" -#include "JSSymbolTableObject.h" -#include "Register.h" -#include "SymbolTable.h" - -namespace JSC { - -class LLIntOffsetsExtractor; -class Register; - -class JSEnvironmentRecord : public JSSymbolTableObject { - friend class JIT; - friend class LLIntOffsetsExtractor; - -public: - typedef JSSymbolTableObject Base; - static const unsigned StructureFlags = Base::StructureFlags; - - WriteBarrierBase<Unknown>* variables() - { - return bitwise_cast<WriteBarrierBase<Unknown>*>(bitwise_cast<char*>(this) + offsetOfVariables()); - } - - bool isValid(ScopeOffset offset) - { - return !!offset && offset.offset() < symbolTable()->scopeSize(); - } - - WriteBarrierBase<Unknown>& variableAt(ScopeOffset offset) - { - ASSERT(isValid(offset)); - return variables()[offset.offset()]; - } - - static size_t offsetOfVariables() - { - return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(JSEnvironmentRecord)); - } - - static ptrdiff_t offsetOfVariable(ScopeOffset offset) - { - return offsetOfVariables() + offset.offset() * sizeof(WriteBarrier<Unknown>); - } - - DECLARE_INFO; - - static size_t allocationSizeForScopeSize(unsigned scopeSize) - { - return offsetOfVariables() + scopeSize * sizeof(WriteBarrier<Unknown>); - } - - static size_t allocationSize(SymbolTable* symbolTable) - { - return allocationSizeForScopeSize(symbolTable->scopeSize()); - } - -protected: - JSEnvironmentRecord( - VM& vm, - Structure* structure, - JSScope* scope, - SymbolTable* symbolTable) - : Base(vm, structure, scope, symbolTable) - { - } - - void finishCreationUninitialized(VM& vm) - { - Base::finishCreation(vm); - } - - void finishCreation(VM& vm, JSValue value) - { - finishCreationUninitialized(vm); - ASSERT(value == jsUndefined() || value == jsTDZValue()); - for (unsigned i = symbolTable()->scopeSize(); i--;) { - // Filling this with undefined/TDZEmptyValue is useful because that's what variables start out as. - variableAt(ScopeOffset(i)).setStartingValue(value); - } - } - - static void visitChildren(JSCell*, SlotVisitor&); -}; - -} // namespace JSC - -#endif // JSEnvironmentRecord_h diff --git a/Source/JavaScriptCore/runtime/JSExportMacros.h b/Source/JavaScriptCore/runtime/JSExportMacros.h index bd46591b4..77e4b0a33 100644 --- a/Source/JavaScriptCore/runtime/JSExportMacros.h +++ b/Source/JavaScriptCore/runtime/JSExportMacros.h @@ -10,10 +10,10 @@ * 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 + * 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 INC. OR + * 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 @@ -30,6 +30,7 @@ #ifndef JSExportMacros_h #define JSExportMacros_h +#include <wtf/Platform.h> #include <wtf/ExportMacros.h> // See note in wtf/Platform.h for more info on EXPORT_MACROS. @@ -47,7 +48,7 @@ #else // !USE(EXPORT_MACROS) -#if OS(WINDOWS) && !COMPILER(GCC_OR_CLANG) +#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 0f7354ed7..241964610 100644 --- a/Source/JavaScriptCore/runtime/JSFunction.cpp +++ b/Source/JavaScriptCore/runtime/JSFunction.cpp @@ -1,10 +1,9 @@ /* * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) * Copyright (C) 2007 Maks Orlovich - * Copyright (C) 2015 Canon 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 @@ -26,22 +25,22 @@ #include "config.h" #include "JSFunction.h" -#include "ClonedArguments.h" +#include "Arguments.h" #include "CodeBlock.h" #include "CommonIdentifiers.h" #include "CallFrame.h" +#include "CallFrameInlines.h" #include "ExceptionHelpers.h" #include "FunctionPrototype.h" #include "GetterSetter.h" #include "JSArray.h" -#include "JSBoundFunction.h" -#include "JSCInlines.h" -#include "JSFunctionInlines.h" +#include "JSBoundFunction.h" #include "JSGlobalObject.h" #include "JSNotAnObject.h" #include "Interpreter.h" #include "ObjectConstructor.h" #include "ObjectPrototype.h" +#include "Operations.h" #include "Parser.h" #include "PropertyNameArray.h" #include "StackVisitor.h" @@ -53,70 +52,51 @@ EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState* exec) return throwVMError(exec, createNotAConstructorError(exec, exec->callee())); } -const ClassInfo JSFunction::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(JSFunction) }; +const ClassInfo JSFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFunction) }; bool JSFunction::isHostFunctionNonInline() const { return isHostFunction(); } -JSFunction* JSFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope) -{ - JSFunction* result = createImpl(vm, executable, scope); - executable->singletonFunction()->notifyWrite(vm, result, "Allocating a function"); - return result; -} - -static inline NativeExecutable* getNativeExecutable(VM& vm, NativeFunction nativeFunction, Intrinsic intrinsic, NativeFunction nativeConstructor) +JSFunction* JSFunction::create(VM& vm, JSGlobalObject* globalObject, int length, const String& name, NativeFunction nativeFunction, Intrinsic intrinsic, NativeFunction nativeConstructor) { + NativeExecutable* executable; #if !ENABLE(JIT) UNUSED_PARAM(intrinsic); #else if (intrinsic != NoIntrinsic && vm.canUseJIT()) { ASSERT(nativeConstructor == callHostFunctionAsConstructor); - return vm.getHostFunction(nativeFunction, intrinsic); - } + executable = vm.getHostFunction(nativeFunction, intrinsic); + } else #endif - return vm.getHostFunction(nativeFunction, nativeConstructor); -} + executable = vm.getHostFunction(nativeFunction, nativeConstructor); -JSFunction* JSFunction::create(VM& vm, JSGlobalObject* globalObject, int length, const String& name, NativeFunction nativeFunction, Intrinsic intrinsic, NativeFunction nativeConstructor) -{ - NativeExecutable* executable = getNativeExecutable(vm, nativeFunction, intrinsic, nativeConstructor); JSFunction* function = new (NotNull, allocateCell<JSFunction>(vm.heap)) JSFunction(vm, globalObject, globalObject->functionStructure()); // Can't do this during initialization because getHostFunction might do a GC allocation. function->finishCreation(vm, executable, length, name); return function; } -class JSStdFunction : public JSFunction { -public: - JSStdFunction(VM& vm, JSGlobalObject* object, Structure* structure, NativeStdFunction&& function) - : JSFunction(vm, object, structure) - , stdFunction(WTF::move(function)) { } - - NativeStdFunction stdFunction; -}; - -static EncodedJSValue JSC_HOST_CALL runStdFunction(ExecState* state) -{ - JSStdFunction* jsFunction = jsCast<JSStdFunction*>(state->callee()); - ASSERT(jsFunction); - return jsFunction->stdFunction(state); -} - -JSFunction* JSFunction::create(VM& vm, JSGlobalObject* globalObject, int length, const String& name, NativeStdFunction&& nativeStdFunction, Intrinsic intrinsic, NativeFunction nativeConstructor) +void JSFunction::destroy(JSCell* cell) { - NativeExecutable* executable = getNativeExecutable(vm, runStdFunction, intrinsic, nativeConstructor); - JSStdFunction* function = new (NotNull, allocateCell<JSStdFunction>(vm.heap)) JSStdFunction(vm, globalObject, globalObject->functionStructure(), WTF::move(nativeStdFunction)); - // Can't do this during initialization because getHostFunction might do a GC allocation. - function->finishCreation(vm, executable, length, name); - return function; + static_cast<JSFunction*>(cell)->JSFunction::~JSFunction(); } JSFunction::JSFunction(VM& vm, JSGlobalObject* globalObject, Structure* structure) - : Base(vm, globalObject, structure) + : Base(vm, structure) , m_executable() + , m_scope(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 + // 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_allocationProfileWatchpoint(ClearWatchpoint) { } @@ -129,48 +109,14 @@ void JSFunction::finishCreation(VM& vm, NativeExecutable* executable, int length putDirect(vm, vm.propertyNames->length, jsNumber(length), DontDelete | ReadOnly | DontEnum); } -JSFunction* JSFunction::createBuiltinFunction(VM& vm, FunctionExecutable* executable, JSGlobalObject* globalObject) -{ - JSFunction* function = create(vm, executable, globalObject); - function->putDirect(vm, vm.propertyNames->name, jsString(&vm, executable->name().string()), DontDelete | ReadOnly | DontEnum); - function->putDirect(vm, vm.propertyNames->length, jsNumber(executable->parameterCount()), DontDelete | ReadOnly | DontEnum); - return function; -} - -JSFunction* JSFunction::createBuiltinFunction(VM& vm, FunctionExecutable* executable, JSGlobalObject* globalObject, const String& name) +ObjectAllocationProfile* JSFunction::createAllocationProfile(ExecState* exec, size_t inlineCapacity) { - JSFunction* function = create(vm, executable, globalObject); - function->putDirect(vm, vm.propertyNames->name, jsString(&vm, name), DontDelete | ReadOnly | DontEnum); - function->putDirect(vm, vm.propertyNames->length, jsNumber(executable->parameterCount()), DontDelete | ReadOnly | DontEnum); - return function; -} - -FunctionRareData* JSFunction::allocateAndInitializeRareData(ExecState* exec, size_t inlineCapacity) -{ - ASSERT(!m_rareData); VM& vm = exec->vm(); JSObject* prototype = jsDynamicCast<JSObject*>(get(exec, vm.propertyNames->prototype)); if (!prototype) prototype = globalObject()->objectPrototype(); - FunctionRareData* rareData = FunctionRareData::create(vm, prototype, inlineCapacity); - - // A DFG compilation thread may be trying to read the rare data - // We want to ensure that it sees it properly allocated - WTF::storeStoreFence(); - - m_rareData.set(vm, this, rareData); - return m_rareData.get(); -} - -FunctionRareData* JSFunction::initializeRareData(ExecState* exec, size_t inlineCapacity) -{ - ASSERT(!!m_rareData); - VM& vm = exec->vm(); - JSObject* prototype = jsDynamicCast<JSObject*>(get(exec, vm.propertyNames->prototype)); - if (!prototype) - prototype = globalObject()->objectPrototype(); - m_rareData->initialize(globalObject()->vm(), prototype, inlineCapacity); - return m_rareData.get(); + m_allocationProfile.initialize(globalObject()->vm(), this, prototype, inlineCapacity); + return &m_allocationProfile; } String JSFunction::name(ExecState* exec) @@ -196,7 +142,7 @@ const String JSFunction::calculatedDisplayName(ExecState* exec) return explicitName; const String actualName = name(exec); - if (!actualName.isEmpty() || isHostOrBuiltinFunction()) + if (!actualName.isEmpty() || isHostFunction()) return actualName; return jsExecutable()->inferredName().string(); @@ -204,20 +150,22 @@ const String JSFunction::calculatedDisplayName(ExecState* exec) const SourceCode* JSFunction::sourceCode() const { - if (isHostOrBuiltinFunction()) + if (isHostFunction()) return 0; return &jsExecutable()->source(); } - + void JSFunction::visitChildren(JSCell* cell, SlotVisitor& visitor) { JSFunction* thisObject = jsCast<JSFunction*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); Base::visitChildren(thisObject, visitor); + visitor.append(&thisObject->m_scope); visitor.append(&thisObject->m_executable); - if (thisObject->m_rareData) - visitor.append(&thisObject->m_rareData); + thisObject->m_allocationProfile.visitAggregate(visitor); } CallType JSFunction::getCallData(JSCell* cell, CallData& callData) @@ -264,9 +212,9 @@ static JSValue retrieveArguments(ExecState* exec, JSFunction* functionObj) return functor.result(); } -EncodedJSValue JSFunction::argumentsGetter(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) +EncodedJSValue JSFunction::argumentsGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName) { - JSFunction* thisObj = jsCast<JSFunction*>(slotBase); + JSFunction* thisObj = jsCast<JSFunction*>(JSValue::decode(slotBase)); ASSERT(!thisObj->isHostFunction()); return JSValue::encode(retrieveArguments(exec, thisObj)); @@ -319,35 +267,31 @@ static JSValue retrieveCallerFunction(ExecState* exec, JSFunction* functionObj) return functor.result(); } -EncodedJSValue JSFunction::callerGetter(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) +EncodedJSValue JSFunction::callerGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName) { - JSFunction* thisObj = jsCast<JSFunction*>(slotBase); + JSFunction* thisObj = jsCast<JSFunction*>(JSValue::decode(slotBase)); ASSERT(!thisObj->isHostFunction()); JSValue caller = retrieveCallerFunction(exec, thisObj); // See ES5.1 15.3.5.4 - Function.caller may not be used to retrieve a strict caller. - if (!caller.isObject() || !asObject(caller)->inherits(JSFunction::info())) { - // It isn't a JSFunction, but if it is a JSCallee from a program or call eval, return null. - if (jsDynamicCast<JSCallee*>(caller)) - return JSValue::encode(jsNull()); + if (!caller.isObject() || !asObject(caller)->inherits(JSFunction::info())) return JSValue::encode(caller); - } JSFunction* function = jsCast<JSFunction*>(caller); - if (function->isHostOrBuiltinFunction() || !function->jsExecutable()->isStrictMode()) + if (function->isHostFunction() || !function->jsExecutable()->isStrictMode()) return JSValue::encode(caller); return JSValue::encode(throwTypeError(exec, ASCIILiteral("Function.caller used to retrieve strict caller"))); } -EncodedJSValue JSFunction::lengthGetter(ExecState*, JSObject* slotBase, EncodedJSValue, PropertyName) +EncodedJSValue JSFunction::lengthGetter(ExecState*, EncodedJSValue slotBase, EncodedJSValue, PropertyName) { - JSFunction* thisObj = jsCast<JSFunction*>(slotBase); + JSFunction* thisObj = jsCast<JSFunction*>(JSValue::decode(slotBase)); ASSERT(!thisObj->isHostFunction()); return JSValue::encode(jsNumber(thisObj->jsExecutable()->parameterCount())); } -EncodedJSValue JSFunction::nameGetter(ExecState*, JSObject* slotBase, EncodedJSValue, PropertyName) +EncodedJSValue JSFunction::nameGetter(ExecState*, EncodedJSValue slotBase, EncodedJSValue, PropertyName) { - JSFunction* thisObj = jsCast<JSFunction*>(slotBase); + JSFunction* thisObj = jsCast<JSFunction*>(JSValue::decode(slotBase)); ASSERT(!thisObj->isHostFunction()); return JSValue::encode(thisObj->jsExecutable()->nameValue()); } @@ -355,7 +299,7 @@ EncodedJSValue JSFunction::nameGetter(ExecState*, JSObject* slotBase, EncodedJSV bool JSFunction::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { JSFunction* thisObject = jsCast<JSFunction*>(object); - if (thisObject->isHostOrBuiltinFunction()) + if (thisObject->isHostFunction()) return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); if (propertyName == exec->propertyNames().prototype) { @@ -417,16 +361,15 @@ bool JSFunction::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyN void JSFunction::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { JSFunction* thisObject = jsCast<JSFunction*>(object); - if (!thisObject->isHostOrBuiltinFunction() && mode.includeDontEnumProperties()) { - VM& vm = exec->vm(); + if (!thisObject->isHostFunction() && (mode == IncludeDontEnumProperties)) { // Make sure prototype has been reified. PropertySlot slot(thisObject); - thisObject->methodTable(vm)->getOwnPropertySlot(thisObject, exec, vm.propertyNames->prototype, slot); + thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, exec->propertyNames().prototype, slot); - propertyNames.add(vm.propertyNames->arguments); - propertyNames.add(vm.propertyNames->caller); - propertyNames.add(vm.propertyNames->length); - propertyNames.add(vm.propertyNames->name); + propertyNames.add(exec->propertyNames().arguments); + propertyNames.add(exec->propertyNames().caller); + propertyNames.add(exec->propertyNames().length); + propertyNames.add(exec->propertyNames().name); } Base::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode); } @@ -434,7 +377,7 @@ void JSFunction::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, void JSFunction::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { JSFunction* thisObject = jsCast<JSFunction*>(cell); - if (thisObject->isHostOrBuiltinFunction()) { + if (thisObject->isHostFunction()) { Base::put(thisObject, exec, propertyName, value, slot); return; } @@ -442,10 +385,10 @@ void JSFunction::put(JSCell* cell, ExecState* exec, PropertyName propertyName, J // Make sure prototype has been reified, such that it can only be overwritten // following the rules set out in ECMA-262 8.12.9. PropertySlot slot(thisObject); - thisObject->methodTable(exec->vm())->getOwnPropertySlot(thisObject, exec, propertyName, slot); - if (thisObject->m_rareData) - thisObject->m_rareData->clear("Store to prototype property of a function"); - // Don't allow this to be cached, since a [[Put]] must clear m_rareData. + thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot); + thisObject->m_allocationProfile.clear(); + thisObject->m_allocationProfileWatchpoint.fireAll(); + // Don't allow this to be cached, since a [[Put]] must clear m_allocationProfile. PutPropertySlot dontCache(thisObject); Base::put(thisObject, exec, propertyName, value, dontCache); return; @@ -469,7 +412,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->isHostOrBuiltinFunction() && !exec->vm().isInDefineOwnProperty() + if (!thisObject->isHostFunction() && !exec->vm().isInDefineOwnProperty() && (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length || propertyName == exec->propertyNames().name @@ -482,16 +425,16 @@ bool JSFunction::deleteProperty(JSCell* cell, ExecState* exec, PropertyName prop bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException) { JSFunction* thisObject = jsCast<JSFunction*>(object); - if (thisObject->isHostOrBuiltinFunction()) + if (thisObject->isHostFunction()) return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException); if (propertyName == exec->propertyNames().prototype) { // Make sure prototype has been reified, such that it can only be overwritten // following the rules set out in ECMA-262 8.12.9. PropertySlot slot(thisObject); - thisObject->methodTable(exec->vm())->getOwnPropertySlot(thisObject, exec, propertyName, slot); - if (thisObject->m_rareData) - thisObject->m_rareData->clear("Store to prototype property of a function"); + thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot); + thisObject->m_allocationProfile.clear(); + thisObject->m_allocationProfileWatchpoint.fireAll(); return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException); } @@ -521,7 +464,7 @@ bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, PropertyNa if (descriptor.configurablePresent() && descriptor.configurable()) { if (throwException) - exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change configurable attribute of unconfigurable property."))); + exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to configurable attribute of unconfigurable property."))); return false; } if (descriptor.enumerablePresent() && descriptor.enumerable()) { @@ -551,17 +494,11 @@ bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, PropertyNa ConstructType JSFunction::getConstructData(JSCell* cell, ConstructData& constructData) { JSFunction* thisObject = jsCast<JSFunction*>(cell); - if (thisObject->isHostFunction()) { constructData.native.function = thisObject->nativeConstructor(); return ConstructTypeHost; } - - FunctionExecutable* functionExecutable = thisObject->jsExecutable(); - if (functionExecutable->constructAbility() == ConstructAbility::CannotConstruct) - return ConstructTypeNone; - - constructData.js.functionExecutable = functionExecutable; + constructData.js.functionExecutable = thisObject->jsExecutable(); constructData.js.scope = thisObject->scope(); return ConstructTypeJS; } diff --git a/Source/JavaScriptCore/runtime/JSFunction.h b/Source/JavaScriptCore/runtime/JSFunction.h index 0b87d75c9..7cd14b8c2 100644 --- a/Source/JavaScriptCore/runtime/JSFunction.h +++ b/Source/JavaScriptCore/runtime/JSFunction.h @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) * Copyright (C) 2007 Maks Orlovich * @@ -24,159 +24,163 @@ #ifndef JSFunction_h #define JSFunction_h -#include "FunctionRareData.h" #include "InternalFunction.h" -#include "JSCallee.h" +#include "JSDestructibleObject.h" #include "JSScope.h" +#include "ObjectAllocationProfile.h" #include "Watchpoint.h" namespace JSC { -class ExecutableBase; -class FunctionExecutable; -class FunctionPrototype; -class JSLexicalEnvironment; -class JSGlobalObject; -class LLIntOffsetsExtractor; -class NativeExecutable; -class SourceCode; -namespace DFG { -class SpeculativeJIT; -class JITCompiler; -} - -typedef std::function<EncodedJSValue (ExecState*)> NativeStdFunction; - -JS_EXPORT_PRIVATE EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState*); - -JS_EXPORT_PRIVATE String getCalculatedDisplayName(CallFrame*, JSObject*); - -class JSFunction : public JSCallee { - friend class JIT; - friend class DFG::SpeculativeJIT; - friend class DFG::JITCompiler; - friend class VM; - -public: - typedef JSCallee Base; - const static unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames; - - static size_t allocationSize(size_t inlineCapacity) - { - ASSERT_UNUSED(inlineCapacity, !inlineCapacity); - return sizeof(JSFunction); + class ExecutableBase; + class FunctionExecutable; + class FunctionPrototype; + class JSActivation; + class JSGlobalObject; + class LLIntOffsetsExtractor; + class NativeExecutable; + class SourceCode; + namespace DFG { + class SpeculativeJIT; + class JITCompiler; } - JS_EXPORT_PRIVATE static JSFunction* create(VM&, JSGlobalObject*, int length, const String& name, NativeFunction, Intrinsic = NoIntrinsic, NativeFunction nativeConstructor = callHostFunctionAsConstructor); - - static JSFunction* createWithInvalidatedReallocationWatchpoint(VM&, FunctionExecutable*, JSScope*); - JS_EXPORT_PRIVATE static JSFunction* create(VM&, JSGlobalObject*, int length, const String& name, NativeStdFunction&&, Intrinsic = NoIntrinsic, NativeFunction nativeConstructor = callHostFunctionAsConstructor); - - static JSFunction* create(VM&, FunctionExecutable*, JSScope*); - - static JSFunction* createBuiltinFunction(VM&, FunctionExecutable*, JSGlobalObject*); - static JSFunction* createBuiltinFunction(VM&, FunctionExecutable*, JSGlobalObject*, const String& name); - - JS_EXPORT_PRIVATE String name(ExecState*); - JS_EXPORT_PRIVATE String displayName(ExecState*); - const String calculatedDisplayName(ExecState*); - - ExecutableBase* executable() const { return m_executable.get(); } + JS_EXPORT_PRIVATE EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState*); - // To call either of these methods include Executable.h - bool isHostFunction() const; - FunctionExecutable* jsExecutable() const; - - JS_EXPORT_PRIVATE const SourceCode* sourceCode() const; - - DECLARE_EXPORT_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - ASSERT(globalObject); - return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info()); - } - - NativeFunction nativeFunction(); - NativeFunction nativeConstructor(); - - static ConstructType getConstructData(JSCell*, ConstructData&); - static CallType getCallData(JSCell*, CallData&); - - static inline ptrdiff_t offsetOfExecutable() - { - return OBJECT_OFFSETOF(JSFunction, m_executable); - } - - static inline ptrdiff_t offsetOfRareData() - { - return OBJECT_OFFSETOF(JSFunction, m_rareData); - } - - FunctionRareData* rareData(ExecState* exec, unsigned inlineCapacity) - { - if (UNLIKELY(!m_rareData)) - return allocateAndInitializeRareData(exec, inlineCapacity); - if (UNLIKELY(!m_rareData->isInitialized())) - return initializeRareData(exec, inlineCapacity); - return m_rareData.get(); - } - - FunctionRareData* rareData() - { - FunctionRareData* rareData = m_rareData.get(); - - // The JS thread may be concurrently creating the rare data - // If we see it, we want to ensure it has been properly created - WTF::loadLoadFence(); - - return rareData; - } - - bool isHostOrBuiltinFunction() const; - bool isBuiltinFunction() const; - JS_EXPORT_PRIVATE bool isHostFunctionNonInline() const; - bool isClassConstructorFunction() const; - -protected: - JS_EXPORT_PRIVATE JSFunction(VM&, JSGlobalObject*, Structure*); - JSFunction(VM&, FunctionExecutable*, JSScope*); - - void finishCreation(VM&, NativeExecutable*, int length, const String& name); - using Base::finishCreation; - - FunctionRareData* allocateAndInitializeRareData(ExecState*, size_t inlineCapacity); - FunctionRareData* initializeRareData(ExecState*, size_t inlineCapacity); - - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); - static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode = EnumerationMode()); - static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow); - - static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); - - static bool deleteProperty(JSCell*, ExecState*, PropertyName); - - static void visitChildren(JSCell*, SlotVisitor&); - -private: - static JSFunction* createImpl(VM& vm, FunctionExecutable* executable, JSScope* scope) - { - JSFunction* function = new (NotNull, allocateCell<JSFunction>(vm.heap)) JSFunction(vm, executable, scope); - ASSERT(function->structure()->globalObject()); - function->finishCreation(vm); - return function; - } + JS_EXPORT_PRIVATE String getCalculatedDisplayName(CallFrame*, JSObject*); - friend class LLIntOffsetsExtractor; - - static EncodedJSValue argumentsGetter(ExecState*, JSObject*, EncodedJSValue, PropertyName); - static EncodedJSValue callerGetter(ExecState*, JSObject*, EncodedJSValue, PropertyName); - static EncodedJSValue lengthGetter(ExecState*, JSObject*, EncodedJSValue, PropertyName); - static EncodedJSValue nameGetter(ExecState*, JSObject*, EncodedJSValue, PropertyName); - - WriteBarrier<ExecutableBase> m_executable; - WriteBarrier<FunctionRareData> m_rareData; -}; + class JSFunction : public JSDestructibleObject { + friend class JIT; + friend class DFG::SpeculativeJIT; + friend class DFG::JITCompiler; + friend class VM; + + public: + typedef JSDestructibleObject Base; + + JS_EXPORT_PRIVATE static JSFunction* create(VM&, JSGlobalObject*, int length, const String& name, NativeFunction, Intrinsic = NoIntrinsic, NativeFunction nativeConstructor = callHostFunctionAsConstructor); + + static JSFunction* create(VM& vm, FunctionExecutable* executable, JSScope* scope) + { + JSFunction* function = new (NotNull, allocateCell<JSFunction>(vm.heap)) JSFunction(vm, executable, scope); + ASSERT(function->structure()->globalObject()); + function->finishCreation(vm); + return function; + } + + static void destroy(JSCell*); + + JS_EXPORT_PRIVATE String name(ExecState*); + JS_EXPORT_PRIVATE String displayName(ExecState*); + const String calculatedDisplayName(ExecState*); + + JSScope* scope() + { + ASSERT(!isHostFunctionNonInline()); + return m_scope.get(); + } + // This method may be called for host functins, in which case it + // will return an arbitrary value. This should only be used for + // optimized paths in which the return value does not matter for + // host functions, and checking whether the function is a host + // function is deemed too expensive. + JSScope* scopeUnchecked() + { + return m_scope.get(); + } + void setScope(VM& vm, JSScope* scope) + { + ASSERT(!isHostFunctionNonInline()); + m_scope.set(vm, this, scope); + } + + ExecutableBase* executable() const { return m_executable.get(); } + + // To call either of these methods include Executable.h + inline bool isHostFunction() const; + FunctionExecutable* jsExecutable() const; + + JS_EXPORT_PRIVATE const SourceCode* sourceCode() const; + + DECLARE_EXPORT_INFO; + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + ASSERT(globalObject); + return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info()); + } + + NativeFunction nativeFunction(); + NativeFunction nativeConstructor(); + + static ConstructType getConstructData(JSCell*, ConstructData&); + static CallType getCallData(JSCell*, CallData&); + + static inline ptrdiff_t offsetOfScopeChain() + { + return OBJECT_OFFSETOF(JSFunction, m_scope); + } + + static inline ptrdiff_t offsetOfExecutable() + { + return OBJECT_OFFSETOF(JSFunction, m_executable); + } + + static inline ptrdiff_t offsetOfAllocationProfile() + { + return OBJECT_OFFSETOF(JSFunction, m_allocationProfile); + } + + ObjectAllocationProfile* allocationProfile(ExecState* exec, unsigned inlineCapacity) + { + if (UNLIKELY(m_allocationProfile.isNull())) + return createAllocationProfile(exec, inlineCapacity); + return &m_allocationProfile; + } + + Structure* allocationStructure() { return m_allocationProfile.structure(); } + + InlineWatchpointSet& allocationProfileWatchpointSet() + { + return m_allocationProfileWatchpoint; + } + + protected: + const static unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags; + + JS_EXPORT_PRIVATE JSFunction(VM&, JSGlobalObject*, Structure*); + JSFunction(VM&, FunctionExecutable*, JSScope*); + + void finishCreation(VM&, NativeExecutable*, int length, const String& name); + using Base::finishCreation; + + ObjectAllocationProfile* createAllocationProfile(ExecState*, size_t inlineCapacity); + + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode = ExcludeDontEnumProperties); + static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow); + + static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); + + static bool deleteProperty(JSCell*, ExecState*, PropertyName); + + static void visitChildren(JSCell*, SlotVisitor&); + + private: + friend class LLIntOffsetsExtractor; + + JS_EXPORT_PRIVATE bool isHostFunctionNonInline() const; + + static EncodedJSValue argumentsGetter(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); + static EncodedJSValue callerGetter(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); + static EncodedJSValue lengthGetter(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); + static EncodedJSValue nameGetter(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); + + WriteBarrier<ExecutableBase> m_executable; + WriteBarrier<JSScope> m_scope; + ObjectAllocationProfile m_allocationProfile; + InlineWatchpointSet m_allocationProfileWatchpoint; + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSFunctionInlines.h b/Source/JavaScriptCore/runtime/JSFunctionInlines.h index f6c6d58ec..fe4e114ad 100644 --- a/Source/JavaScriptCore/runtime/JSFunctionInlines.h +++ b/Source/JavaScriptCore/runtime/JSFunctionInlines.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. + * 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 @@ -31,17 +31,11 @@ namespace JSC { -inline JSFunction* JSFunction::createWithInvalidatedReallocationWatchpoint( - VM& vm, FunctionExecutable* executable, JSScope* scope) -{ - ASSERT(executable->singletonFunction()->hasBeenInvalidated()); - return createImpl(vm, executable, scope); -} - inline JSFunction::JSFunction(VM& vm, FunctionExecutable* executable, JSScope* scope) - : Base(vm, scope, scope->globalObject()->functionStructure()) + : Base(vm, scope->globalObject()->functionStructure()) , m_executable(vm, this, executable) - , m_rareData() + , m_scope(vm, this, scope) + , m_allocationProfileWatchpoint(ClearWatchpoint) // See comment in JSFunction.cpp concerning the reason for using ClearWatchpoint as opposed to IsWatched. { } @@ -57,41 +51,18 @@ inline bool JSFunction::isHostFunction() const return m_executable->isHostFunction(); } -inline bool JSFunction::isBuiltinFunction() const -{ - return !isHostFunction() && jsExecutable()->isBuiltinFunction(); -} - -inline bool JSFunction::isHostOrBuiltinFunction() const -{ - return isHostFunction() || isBuiltinFunction(); -} - -inline bool JSFunction::isClassConstructorFunction() const -{ - return !isHostFunction() && jsExecutable()->isClassConstructorFunction(); -} - inline NativeFunction JSFunction::nativeFunction() { - ASSERT(isHostFunctionNonInline()); + ASSERT(isHostFunction()); return static_cast<NativeExecutable*>(m_executable.get())->function(); } inline NativeFunction JSFunction::nativeConstructor() { - ASSERT(isHostFunctionNonInline()); + ASSERT(isHostFunction()); return static_cast<NativeExecutable*>(m_executable.get())->constructor(); } -inline bool isHostFunction(JSValue value, NativeFunction nativeFunction) -{ - JSFunction* function = jsCast<JSFunction*>(getJSFunction(value)); - if (!function || !function->isHostFunction()) - return false; - return function->nativeFunction() == nativeFunction; -} - } // namespace JSC #endif // JSFunctionInlines_h diff --git a/Source/JavaScriptCore/runtime/JSGenericTypedArrayView.h b/Source/JavaScriptCore/runtime/JSGenericTypedArrayView.h index a3a756cf5..895acbfab 100644 --- a/Source/JavaScriptCore/runtime/JSGenericTypedArrayView.h +++ b/Source/JavaScriptCore/runtime/JSGenericTypedArrayView.h @@ -87,8 +87,6 @@ template<typename Adaptor> class JSGenericTypedArrayView : public JSArrayBufferView { public: typedef JSArrayBufferView Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetPropertyNames | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero; - static const unsigned elementSize = sizeof(typename Adaptor::Type); protected: @@ -156,15 +154,11 @@ public: setIndexQuicklyToNativeValue(i, toNativeFromValue<Adaptor>(value)); } - bool setIndex(ExecState* exec, unsigned i, JSValue jsValue) + bool setIndexQuickly(ExecState* exec, unsigned i, JSValue jsValue) { typename Adaptor::Type value = toNativeFromValue<Adaptor>(exec, jsValue); if (exec->hadException()) return false; - - if (i >= m_length) - return false; - setIndexQuicklyToNativeValue(i, value); return true; } @@ -192,7 +186,7 @@ public: static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(vm, globalObject, prototype, TypeInfo(typeForTypedArrayType(Adaptor::typeValue), StructureFlags), info(), NonArray); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), NonArray); } static const ClassInfo s_info; // This is never accessed directly, since that would break linkage on some compilers. @@ -230,6 +224,8 @@ public: protected: friend struct TypedArrayClassInfos; + + static const unsigned StructureFlags = OverridesGetPropertyNames | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | Base::StructureFlags; static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); @@ -260,11 +256,11 @@ private: }; template<typename Adaptor> -inline RefPtr<typename Adaptor::ViewType> toNativeTypedView(JSValue value) +inline PassRefPtr<typename Adaptor::ViewType> toNativeTypedView(JSValue value) { typename Adaptor::JSViewType* wrapper = jsDynamicCast<typename Adaptor::JSViewType*>(value); if (!wrapper) - return nullptr; + return 0; return wrapper->typedImpl(); } diff --git a/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h index e9ed1e998..6db86274c 100644 --- a/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h +++ b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h @@ -49,7 +49,7 @@ JSGenericTypedArrayView<Adaptor>* JSGenericTypedArrayView<Adaptor>::create( { ConstructionContext context(exec->vm(), structure, length, sizeof(typename Adaptor::Type)); if (!context) { - exec->vm().throwException(exec, createOutOfMemoryError(exec)); + exec->vm().throwException(exec, createOutOfMemoryError(structure->globalObject())); return 0; } JSGenericTypedArrayView* result = @@ -67,7 +67,7 @@ JSGenericTypedArrayView<Adaptor>* JSGenericTypedArrayView<Adaptor>::createUninit exec->vm(), structure, length, sizeof(typename Adaptor::Type), ConstructionContext::DontInitialize); if (!context) { - exec->vm().throwException(exec, createOutOfMemoryError(exec)); + exec->vm().throwException(exec, createOutOfMemoryError(structure->globalObject())); return 0; } JSGenericTypedArrayView* result = @@ -83,14 +83,10 @@ JSGenericTypedArrayView<Adaptor>* JSGenericTypedArrayView<Adaptor>::create( unsigned byteOffset, unsigned length) { RefPtr<ArrayBuffer> buffer = passedBuffer; - size_t size = sizeof(typename Adaptor::Type); - if (!ArrayBufferView::verifySubRangeLength(buffer, byteOffset, length, size)) { - exec->vm().throwException(exec, createRangeError(exec, "Length out of range of buffer")); - return nullptr; - } - if (!ArrayBufferView::verifyByteOffsetAlignment(byteOffset, size)) { - exec->vm().throwException(exec, createRangeError(exec, "Byte offset is not aligned")); - return nullptr; + if (!ArrayBufferView::verifySubRange<typename Adaptor::Type>(buffer, byteOffset, length)) { + exec->vm().throwException( + exec, createRangeError(exec, "Byte offset and length out of range of buffer")); + return 0; } ConstructionContext context(exec->vm(), structure, buffer, byteOffset, length); ASSERT(context); @@ -270,8 +266,7 @@ bool JSGenericTypedArrayView<Adaptor>::set( return false; // We could optimize this case. But right now, we don't. for (unsigned i = 0; i < length; ++i) { - JSValue value = object->get(exec, i); - if (!setIndex(exec, offset + i, value)) + if (!setIndexQuickly(exec, offset + i, object->get(exec, i))) return false; } return true; @@ -302,9 +297,9 @@ bool JSGenericTypedArrayView<Adaptor>::getOwnPropertySlot( return true; } - Optional<uint32_t> index = parseIndex(propertyName); - if (index && thisObject->canGetIndexQuickly(index.value())) { - slot.setValue(thisObject, DontDelete | ReadOnly, thisObject->getIndexQuickly(index.value())); + unsigned index = propertyName.asIndex(); + if (index != PropertyName::NotAnIndex && thisObject->canGetIndexQuickly(index)) { + slot.setValue(thisObject, DontDelete | ReadOnly, thisObject->getIndexQuickly(index)); return true; } @@ -324,8 +319,9 @@ void JSGenericTypedArrayView<Adaptor>::put( return; } - if (Optional<uint32_t> index = parseIndex(propertyName)) { - putByIndex(thisObject, exec, index.value(), value, slot.isStrictMode()); + unsigned index = propertyName.asIndex(); + if (index != PropertyName::NotAnIndex) { + putByIndex(thisObject, exec, index, value, slot.isStrictMode()); return; } @@ -342,7 +338,8 @@ bool JSGenericTypedArrayView<Adaptor>::defineOwnProperty( // This is matching Firefox behavior. In particular, it rejects all attempts to // defineOwnProperty for indexed properties on typed arrays, even if they're out // of bounds. - if (propertyName == exec->propertyNames().length || parseIndex(propertyName)) + if (propertyName == exec->propertyNames().length + || propertyName.asIndex() != PropertyName::NotAnIndex) return reject(exec, shouldThrow, "Attempting to write to a read-only typed array property."); return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow); @@ -354,7 +351,8 @@ bool JSGenericTypedArrayView<Adaptor>::deleteProperty( { JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell); - if (propertyName == exec->propertyNames().length || parseIndex(propertyName)) + if (propertyName == exec->propertyNames().length + || propertyName.asIndex() != PropertyName::NotAnIndex) return false; return Base::deleteProperty(thisObject, exec, propertyName); @@ -391,7 +389,13 @@ void JSGenericTypedArrayView<Adaptor>::putByIndex( return; } - thisObject->setIndex(exec, propertyName, value); + if (!thisObject->canSetIndexQuickly(propertyName)) { + // Yes, really. Firefox returns without throwing anything if you store beyond + // the bounds. + return; + } + + thisObject->setIndexQuickly(exec, propertyName, value); } template<typename Adaptor> @@ -412,7 +416,7 @@ void JSGenericTypedArrayView<Adaptor>::getOwnNonIndexPropertyNames( { JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object); - if (mode.includeDontEnumProperties()) + if (mode == IncludeDontEnumProperties) array.add(exec->propertyNames().length); Base::getOwnNonIndexPropertyNames(thisObject, exec, array, mode); @@ -423,11 +427,9 @@ void JSGenericTypedArrayView<Adaptor>::getOwnPropertyNames( JSObject* object, ExecState* exec, PropertyNameArray& array, EnumerationMode mode) { JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object); - - if (array.includeStringProperties()) { - for (unsigned i = 0; i < thisObject->m_length; ++i) - array.add(Identifier::from(exec, i)); - } + + for (unsigned i = 0; i < thisObject->m_length; ++i) + array.add(Identifier::from(exec, i)); return Base::getOwnPropertyNames(object, exec, array, mode); } @@ -445,7 +447,7 @@ void JSGenericTypedArrayView<Adaptor>::visitChildren(JSCell* cell, SlotVisitor& } case OversizeTypedArray: { - visitor.reportExtraMemoryVisited(thisObject, thisObject->byteSize()); + visitor.reportExtraMemoryUsage(thisObject, thisObject->byteSize()); break; } diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp index cee9bbd94..2c274c1a7 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2009, 2014, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2007, 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 @@ -7,13 +7,13 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * 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 Inc. ("Apple") nor the names of + * 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. + * 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 @@ -30,21 +30,20 @@ #include "config.h" #include "JSGlobalObject.h" +#include "Arguments.h" +#include "ArgumentsIteratorConstructor.h" +#include "ArgumentsIteratorPrototype.h" #include "ArrayConstructor.h" +#include "ArrayIteratorConstructor.h" #include "ArrayIteratorPrototype.h" #include "ArrayPrototype.h" #include "BooleanConstructor.h" #include "BooleanPrototype.h" -#include "BuiltinNames.h" -#include "ClonedArguments.h" #include "CodeBlock.h" #include "CodeCache.h" -#include "ConsolePrototype.h" #include "DateConstructor.h" #include "DatePrototype.h" #include "Debugger.h" -#include "DebuggerScope.h" -#include "DirectArguments.h" #include "Error.h" #include "ErrorConstructor.h" #include "ErrorPrototype.h" @@ -53,112 +52,92 @@ #include "GetterSetter.h" #include "HeapIterationScope.h" #include "Interpreter.h" -#include "IteratorPrototype.h" #include "JSAPIWrapperObject.h" +#include "JSActivation.h" +#include "JSArgumentsIterator.h" #include "JSArrayBuffer.h" #include "JSArrayBufferConstructor.h" #include "JSArrayBufferPrototype.h" #include "JSArrayIterator.h" #include "JSBoundFunction.h" -#include "JSCInlines.h" #include "JSCallbackConstructor.h" #include "JSCallbackFunction.h" #include "JSCallbackObject.h" -#include "JSConsole.h" #include "JSDataView.h" #include "JSDataViewPrototype.h" -#include "JSDollarVM.h" -#include "JSDollarVMPrototype.h" #include "JSFunction.h" #include "JSGenericTypedArrayViewConstructorInlines.h" #include "JSGenericTypedArrayViewInlines.h" #include "JSGenericTypedArrayViewPrototypeInlines.h" #include "JSGlobalObjectFunctions.h" -#include "JSJob.h" -#include "JSLexicalEnvironment.h" #include "JSLock.h" #include "JSMap.h" #include "JSMapIterator.h" +#include "JSNameScope.h" #include "JSONObject.h" -#include "JSPromise.h" -#include "JSPromiseConstructor.h" -#include "JSPromisePrototype.h" -#include "JSPropertyNameIterator.h" #include "JSSet.h" #include "JSSetIterator.h" -#include "JSStringIterator.h" -#include "JSTemplateRegistryKey.h" #include "JSTypedArrayConstructors.h" #include "JSTypedArrayPrototypes.h" #include "JSTypedArrays.h" -#include "JSWASMModule.h" #include "JSWeakMap.h" -#include "JSWeakSet.h" #include "JSWithScope.h" #include "LegacyProfiler.h" #include "Lookup.h" #include "MapConstructor.h" +#include "MapIteratorConstructor.h" #include "MapIteratorPrototype.h" #include "MapPrototype.h" #include "MathObject.h" #include "Microtask.h" +#include "NameConstructor.h" +#include "NameInstance.h" +#include "NamePrototype.h" #include "NativeErrorConstructor.h" #include "NativeErrorPrototype.h" -#include "NullGetterFunction.h" -#include "NullSetterFunction.h" #include "NumberConstructor.h" #include "NumberPrototype.h" #include "ObjCCallbackFunction.h" #include "ObjectConstructor.h" #include "ObjectPrototype.h" +#include "Operations.h" #include "ParserError.h" -#include "ReflectObject.h" #include "RegExpConstructor.h" #include "RegExpMatchesArray.h" #include "RegExpObject.h" #include "RegExpPrototype.h" -#include "ScopedArguments.h" #include "SetConstructor.h" +#include "SetIteratorConstructor.h" #include "SetIteratorPrototype.h" #include "SetPrototype.h" #include "StrictEvalActivation.h" #include "StringConstructor.h" -#include "StringIteratorPrototype.h" #include "StringPrototype.h" -#include "Symbol.h" -#include "SymbolConstructor.h" -#include "SymbolPrototype.h" -#include "VariableWriteFireDetail.h" -#include "WeakGCMapInlines.h" #include "WeakMapConstructor.h" #include "WeakMapPrototype.h" -#include "WeakSetConstructor.h" -#include "WeakSetPrototype.h" -#if ENABLE(INTL) -#include "IntlObject.h" -#endif // ENABLE(INTL) +#if ENABLE(PROMISES) +#include "JSPromise.h" +#include "JSPromiseConstructor.h" +#include "JSPromisePrototype.h" +#endif // ENABLE(PROMISES) #if ENABLE(REMOTE_INSPECTOR) #include "JSGlobalObjectDebuggable.h" -#include "JSGlobalObjectInspectorController.h" -#endif - -#if ENABLE(WEB_REPLAY) -#include "EmptyInputCursor.h" -#include "JSReplayInputs.h" +#include "RemoteInspector.h" #endif #include "JSGlobalObject.lut.h" namespace JSC { -const ClassInfo JSGlobalObject::s_info = { "GlobalObject", &Base::s_info, &globalObjectTable, CREATE_METHOD_TABLE(JSGlobalObject) }; +const ClassInfo JSGlobalObject::s_info = { "GlobalObject", &Base::s_info, 0, ExecState::globalObjectTable, CREATE_METHOD_TABLE(JSGlobalObject) }; -const GlobalObjectMethodTable JSGlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptRuntimeFlags, nullptr, &shouldInterruptScriptBeforeTimeout }; +const GlobalObjectMethodTable JSGlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptExperimentsEnabled, 0, &shouldInterruptScriptBeforeTimeout }; /* Source for JSGlobalObject.lut.h @begin globalObjectTable + parseInt globalFuncParseInt DontEnum|Function 2 parseFloat globalFuncParseFloat DontEnum|Function 1 isNaN globalFuncIsNaN DontEnum|Function 1 isFinite globalFuncIsFinite DontEnum|Function 1 @@ -171,52 +150,19 @@ const GlobalObjectMethodTable JSGlobalObject::s_globalObjectMethodTable = { &all @end */ -static EncodedJSValue JSC_HOST_CALL getTemplateObject(ExecState* exec) -{ - JSValue thisValue = exec->thisValue(); - ASSERT(thisValue.inherits(JSTemplateRegistryKey::info())); - return JSValue::encode(exec->lexicalGlobalObject()->templateRegistry().getTemplateObject(exec, jsCast<JSTemplateRegistryKey*>(thisValue)->templateRegistryKey())); -} - - -static EncodedJSValue JSC_HOST_CALL enqueueJob(ExecState* exec) -{ - VM& vm = exec->vm(); - JSGlobalObject* globalObject = exec->lexicalGlobalObject(); - - JSValue job = exec->argument(0); - JSValue arguments = exec->argument(1); - ASSERT(arguments.inherits(JSArray::info())); - - globalObject->queueMicrotask(createJSJob(vm, job, jsCast<JSArray*>(arguments))); - - return JSValue::encode(jsUndefined()); -} - JSGlobalObject::JSGlobalObject(VM& vm, Structure* structure, const GlobalObjectMethodTable* globalObjectMethodTable) : Base(vm, structure, 0) - , m_vm(vm) -#if ENABLE(WEB_REPLAY) - , m_inputCursor(EmptyInputCursor::create()) -#endif , m_masqueradesAsUndefinedWatchpoint(adoptRef(new WatchpointSet(IsWatched))) , m_havingABadTimeWatchpoint(adoptRef(new WatchpointSet(IsWatched))) , m_varInjectionWatchpoint(adoptRef(new WatchpointSet(IsWatched))) , m_weakRandom(Options::forceWeakRandomSeed() ? Options::forcedWeakRandomSeed() : static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0))) - , m_templateRegistry(vm) , m_evalEnabled(true) - , m_runtimeFlags() - , m_consoleClient(nullptr) , m_globalObjectMethodTable(globalObjectMethodTable ? globalObjectMethodTable : &s_globalObjectMethodTable) { } JSGlobalObject::~JSGlobalObject() { -#if ENABLE(REMOTE_INSPECTOR) - m_inspectorController->globalObjectDestroyed(); -#endif - if (m_debugger) m_debugger->detach(this, Debugger::GlobalObjectIsDestructing); @@ -230,52 +176,102 @@ void JSGlobalObject::destroy(JSCell* cell) } void JSGlobalObject::setGlobalThis(VM& vm, JSObject* globalThis) -{ +{ m_globalThis.set(vm, this, globalThis); } -void JSGlobalObject::init(VM& vm) +void JSGlobalObject::init(JSObject* thisValue) { - ASSERT(vm.currentThreadIsHoldingAPILock()); + ASSERT(vm().currentThreadIsHoldingAPILock()); - JSGlobalObject::globalExec()->init(0, 0, CallFrame::noCaller(), 0, 0); + setGlobalThis(vm(), thisValue); + JSGlobalObject::globalExec()->init(0, 0, this, CallFrame::noCaller(), 0, 0); m_debugger = 0; #if ENABLE(REMOTE_INSPECTOR) - m_inspectorController = std::make_unique<Inspector::JSGlobalObjectInspectorController>(*this); m_inspectorDebuggable = std::make_unique<JSGlobalObjectDebuggable>(*this); m_inspectorDebuggable->init(); - m_consoleClient = m_inspectorController->consoleClient(); + m_inspectorDebuggable->setRemoteDebuggingAllowed(true); #endif - ExecState* exec = JSGlobalObject::globalExec(); + reset(prototype()); +} - m_functionPrototype.set(vm, this, FunctionPrototype::create(vm, FunctionPrototype::createStructure(vm, this, jsNull()))); // The real prototype will be set once ObjectPrototype is created. - m_calleeStructure.set(vm, this, JSCallee::createStructure(vm, this, jsNull())); +void JSGlobalObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) +{ + JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(cell); + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); + + if (symbolTablePut(thisObject, exec, propertyName, value, slot.isStrictMode())) + return; + Base::put(thisObject, exec, propertyName, value, slot); +} + +bool JSGlobalObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow) +{ + JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(object); + PropertySlot slot(thisObject); + // silently ignore attempts to add accessors aliasing vars. + if (descriptor.isAccessorDescriptor() && symbolTableGet(thisObject, propertyName, slot)) + return false; + return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow); +} + +JSGlobalObject::NewGlobalVar JSGlobalObject::addGlobalVar(const Identifier& ident, ConstantMode constantMode) +{ + ConcurrentJITLocker locker(symbolTable()->m_lock); + int index = symbolTable()->size(locker); + SymbolTableEntry newEntry(index, (constantMode == IsConstant) ? ReadOnly : 0); + if (constantMode == IsVariable) + newEntry.prepareToWatch(); + SymbolTable::Map::AddResult result = symbolTable()->add(locker, ident.impl(), newEntry); + if (result.isNewEntry) + addRegisters(1); + else + index = result.iterator->value.getIndex(); + NewGlobalVar var; + var.registerNumber = index; + var.set = result.iterator->value.watchpointSet(); + return var; +} + +void JSGlobalObject::addFunction(ExecState* exec, const Identifier& propertyName, JSValue value) +{ + removeDirect(exec->vm(), propertyName); // Newly declared functions overwrite existing properties. + NewGlobalVar var = addGlobalVar(propertyName, IsVariable); + registerAt(var.registerNumber).set(exec->vm(), this, value); + if (var.set) + var.set->notifyWrite(value); +} + +static inline JSObject* lastInPrototypeChain(JSObject* object) +{ + JSObject* o = object; + while (o->prototype().isObject()) + o = asObject(o->prototype()); + return o; +} - // Need to create the callee structure (above) before creating the callee. - m_globalCallee.set(vm, this, JSCallee::create(vm, this, this)); - exec->setCallee(m_globalCallee.get()); +void JSGlobalObject::reset(JSValue prototype) +{ + ExecState* exec = JSGlobalObject::globalExec(); + VM& vm = exec->vm(); + m_functionPrototype.set(vm, this, FunctionPrototype::create(vm, FunctionPrototype::createStructure(vm, this, jsNull()))); // The real prototype will be set once ObjectPrototype is created. m_functionStructure.set(vm, this, JSFunction::createStructure(vm, this, m_functionPrototype.get())); m_boundFunctionStructure.set(vm, this, JSBoundFunction::createStructure(vm, this, m_functionPrototype.get())); - m_namedFunctionStructure.set(vm, this, Structure::addPropertyTransition(vm, m_functionStructure.get(), vm.propertyNames->name, DontDelete | ReadOnly | DontEnum, m_functionNameOffset)); + m_namedFunctionStructure.set(vm, this, Structure::addPropertyTransition(vm, m_functionStructure.get(), vm.propertyNames->name, DontDelete | ReadOnly | DontEnum, 0, m_functionNameOffset)); m_internalFunctionStructure.set(vm, this, InternalFunction::createStructure(vm, this, m_functionPrototype.get())); JSFunction* callFunction = 0; JSFunction* applyFunction = 0; m_functionPrototype->addFunctionProperties(exec, this, &callFunction, &applyFunction); m_callFunction.set(vm, this, callFunction); m_applyFunction.set(vm, this, applyFunction); - m_arrayProtoValuesFunction.set(vm, this, JSFunction::create(vm, this, 0, vm.propertyNames->values.string(), arrayProtoFuncValues)); - m_initializePromiseFunction.set(vm, this, JSFunction::createBuiltinFunction(vm, operationsPromiseInitializePromiseCodeGenerator(vm), this)); - m_newPromiseDeferredFunction.set(vm, this, JSFunction::createBuiltinFunction(vm, operationsPromiseNewPromiseDeferredCodeGenerator(vm), this)); - m_nullGetterFunction.set(vm, this, NullGetterFunction::create(vm, NullGetterFunction::createStructure(vm, this, m_functionPrototype.get()))); - m_nullSetterFunction.set(vm, this, NullSetterFunction::create(vm, NullSetterFunction::createStructure(vm, this, m_functionPrototype.get()))); m_objectPrototype.set(vm, this, ObjectPrototype::create(vm, this, ObjectPrototype::createStructure(vm, this, jsNull()))); - GetterSetter* protoAccessor = GetterSetter::create(vm, this); - protoAccessor->setGetter(vm, this, JSFunction::create(vm, this, 0, String(), globalFuncProtoGetter)); - protoAccessor->setSetter(vm, this, JSFunction::create(vm, this, 0, String(), globalFuncProtoSetter)); + GetterSetter* protoAccessor = GetterSetter::create(vm); + protoAccessor->setGetter(vm, JSFunction::create(vm, this, 0, String(), globalFuncProtoGetter)); + protoAccessor->setSetter(vm, JSFunction::create(vm, this, 0, String(), globalFuncProtoSetter)); m_objectPrototype->putDirectNonIndexAccessor(vm, vm.propertyNames->underscoreProto, protoAccessor, Accessor | DontEnum); m_functionPrototype->structure()->setPrototypeWithoutTransition(vm, m_objectPrototype.get()); @@ -300,25 +296,23 @@ void JSGlobalObject::init(VM& vm) m_typedArrays[toIndex(TypeFloat32)].structure.set(vm, this, JSFloat32Array::createStructure(vm, this, m_typedArrays[toIndex(TypeFloat32)].prototype.get())); m_typedArrays[toIndex(TypeFloat64)].structure.set(vm, this, JSFloat64Array::createStructure(vm, this, m_typedArrays[toIndex(TypeFloat64)].prototype.get())); m_typedArrays[toIndex(TypeDataView)].structure.set(vm, this, JSDataView::createStructure(vm, this, m_typedArrays[toIndex(TypeDataView)].prototype.get())); - - m_lexicalEnvironmentStructure.set(vm, this, JSLexicalEnvironment::createStructure(vm, this)); + + m_nameScopeStructure.set(vm, this, JSNameScope::createStructure(vm, this, jsNull())); + m_activationStructure.set(vm, this, JSActivation::createStructure(vm, this, jsNull())); m_strictEvalActivationStructure.set(vm, this, StrictEvalActivation::createStructure(vm, this, jsNull())); - m_debuggerScopeStructure.set(m_vm, this, DebuggerScope::createStructure(m_vm, this)); m_withScopeStructure.set(vm, this, JSWithScope::createStructure(vm, this, jsNull())); - + m_nullPrototypeObjectStructure.set(vm, this, JSFinalObject::createStructure(vm, this, jsNull(), JSFinalObject::defaultInlineCapacity())); - + m_callbackFunctionStructure.set(vm, this, JSCallbackFunction::createStructure(vm, this, m_functionPrototype.get())); - m_directArgumentsStructure.set(vm, this, DirectArguments::createStructure(vm, this, m_objectPrototype.get())); - m_scopedArgumentsStructure.set(vm, this, ScopedArguments::createStructure(vm, this, m_objectPrototype.get())); - m_outOfBandArgumentsStructure.set(vm, this, ClonedArguments::createStructure(vm, this, m_objectPrototype.get())); + m_argumentsStructure.set(vm, this, Arguments::createStructure(vm, this, m_objectPrototype.get())); m_callbackConstructorStructure.set(vm, this, JSCallbackConstructor::createStructure(vm, this, m_objectPrototype.get())); m_callbackObjectStructure.set(vm, this, JSCallbackObject<JSDestructibleObject>::createStructure(vm, this, m_objectPrototype.get())); #if JSC_OBJC_API_ENABLED m_objcCallbackFunctionStructure.set(vm, this, ObjCCallbackFunction::createStructure(vm, this, m_functionPrototype.get())); m_objcWrapperObjectStructure.set(vm, this, JSCallbackObject<JSAPIWrapperObject>::createStructure(vm, this, m_objectPrototype.get())); #endif - + m_arrayPrototype.set(vm, this, ArrayPrototype::create(vm, this, ArrayPrototype::createStructure(vm, this, m_objectPrototype.get()))); m_originalArrayStructureForIndexingShape[UndecidedShape >> IndexingShapeShift].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), ArrayWithUndecided)); @@ -329,65 +323,45 @@ void JSGlobalObject::init(VM& vm) m_originalArrayStructureForIndexingShape[SlowPutArrayStorageShape >> IndexingShapeShift].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), ArrayWithSlowPutArrayStorage)); for (unsigned i = 0; i < NumberOfIndexingShapes; ++i) m_arrayStructureForIndexingShapeDuringAllocation[i] = m_originalArrayStructureForIndexingShape[i]; + + m_regExpMatchesArrayStructure.set(vm, this, RegExpMatchesArray::createStructure(vm, this, m_arrayPrototype.get())); RegExp* emptyRegex = RegExp::create(vm, "", NoFlags); m_regExpPrototype.set(vm, this, RegExpPrototype::create(vm, RegExpPrototype::createStructure(vm, this, m_objectPrototype.get()), emptyRegex)); m_regExpStructure.set(vm, this, RegExpObject::createStructure(vm, this, m_regExpPrototype.get())); - m_regExpMatchesArrayStructure.set(vm, this, createRegExpMatchesArrayStructure(vm, *this)); - + +#if ENABLE(PROMISES) m_promisePrototype.set(vm, this, JSPromisePrototype::create(exec, this, JSPromisePrototype::createStructure(vm, this, m_objectPrototype.get()))); m_promiseStructure.set(vm, this, JSPromise::createStructure(vm, this, m_promisePrototype.get())); - -#if ENABLE(WEBASSEMBLY) - m_wasmModuleStructure.set(vm, this, JSWASMModule::createStructure(vm, this)); -#endif - - m_parseIntFunction.set(vm, this, JSFunction::create(vm, this, 2, vm.propertyNames->parseInt.string(), globalFuncParseInt, NoIntrinsic)); - putDirectWithoutTransition(vm, vm.propertyNames->parseInt, m_parseIntFunction.get(), DontEnum | Function); +#endif // ENABLE(PROMISES) #define CREATE_PROTOTYPE_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName) \ -m_ ## lowerName ## Prototype.set(vm, this, capitalName##Prototype::create(vm, this, capitalName##Prototype::createStructure(vm, this, m_objectPrototype.get()))); \ -m_ ## properName ## Structure.set(vm, this, instanceType::createStructure(vm, this, m_ ## lowerName ## Prototype.get())); - - FOR_EACH_SIMPLE_BUILTIN_TYPE(CREATE_PROTOTYPE_FOR_SIMPLE_TYPE) - -#undef CREATE_PROTOTYPE_FOR_SIMPLE_TYPE + m_ ## lowerName ## Prototype.set(vm, this, capitalName##Prototype::create(vm, this, capitalName##Prototype::createStructure(vm, this, m_objectPrototype.get()))); \ + m_ ## properName ## Structure.set(vm, this, instanceType::createStructure(vm, this, m_ ## lowerName ## Prototype.get())); - m_iteratorPrototype.set(vm, this, IteratorPrototype::create(vm, this, IteratorPrototype::createStructure(vm, this, m_objectPrototype.get()))); + FOR_EACH_SIMPLE_BUILTIN_TYPE(CREATE_PROTOTYPE_FOR_SIMPLE_TYPE) -#define CREATE_PROTOTYPE_FOR_DERIVED_ITERATOR_TYPE(capitalName, lowerName, properName, instanceType, jsName) \ -m_ ## lowerName ## Prototype.set(vm, this, capitalName##Prototype::create(vm, this, capitalName##Prototype::createStructure(vm, this, m_iteratorPrototype.get()))); \ -m_ ## properName ## Structure.set(vm, this, instanceType::createStructure(vm, this, m_ ## lowerName ## Prototype.get())); - - FOR_EACH_BUILTIN_DERIVED_ITERATOR_TYPE(CREATE_PROTOTYPE_FOR_DERIVED_ITERATOR_TYPE) - m_propertyNameIteratorStructure.set(vm, this, JSPropertyNameIterator::createStructure(vm, this, m_iteratorPrototype.get())); - -#undef CREATE_PROTOTYPE_FOR_DERIVED_ITERATOR_TYPE +#undef CREATE_PROTOTYPE_FOR_SIMPLE_TYPE // Constructors - - ObjectConstructor* objectConstructor = ObjectConstructor::create(vm, this, ObjectConstructor::createStructure(vm, this, m_functionPrototype.get()), m_objectPrototype.get()); - m_objectConstructor.set(vm, this, objectConstructor); - - JSFunction* definePropertyFunction = m_objectConstructor->addDefineProperty(exec, this); - m_definePropertyFunction.set(vm, this, definePropertyFunction); + JSCell* objectConstructor = ObjectConstructor::create(vm, ObjectConstructor::createStructure(vm, this, m_functionPrototype.get()), m_objectPrototype.get()); JSCell* functionConstructor = FunctionConstructor::create(vm, FunctionConstructor::createStructure(vm, this, m_functionPrototype.get()), m_functionPrototype.get()); JSCell* arrayConstructor = ArrayConstructor::create(vm, ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_arrayPrototype.get()); - + m_regExpConstructor.set(vm, this, RegExpConstructor::create(vm, RegExpConstructor::createStructure(vm, this, m_functionPrototype.get()), m_regExpPrototype.get())); - + #define CREATE_CONSTRUCTOR_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName) \ -capitalName ## Constructor* lowerName ## Constructor = capitalName ## Constructor::create(vm, capitalName ## Constructor::createStructure(vm, this, m_functionPrototype.get()), m_ ## lowerName ## Prototype.get()); \ -m_ ## lowerName ## Prototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, lowerName ## Constructor, DontEnum); \ + capitalName ## Constructor* lowerName ## Constructor = capitalName ## Constructor::create(vm, capitalName ## Constructor::createStructure(vm, this, m_functionPrototype.get()), m_ ## lowerName ## Prototype.get()); \ + m_ ## lowerName ## Prototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, lowerName ## Constructor, DontEnum); \ FOR_EACH_SIMPLE_BUILTIN_TYPE(CREATE_CONSTRUCTOR_FOR_SIMPLE_TYPE) - + #undef CREATE_CONSTRUCTOR_FOR_SIMPLE_TYPE - + m_errorConstructor.set(vm, this, errorConstructor); - + Structure* nativeErrorPrototypeStructure = NativeErrorPrototype::createStructure(vm, this, m_errorPrototype.get()); Structure* nativeErrorStructure = NativeErrorConstructor::createStructure(vm, this, m_functionPrototype.get()); m_evalErrorConstructor.set(vm, this, NativeErrorConstructor::create(vm, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("EvalError"))); @@ -397,13 +371,15 @@ m_ ## lowerName ## Prototype->putDirectWithoutTransition(vm, vm.propertyNames->c m_typeErrorConstructor.set(vm, this, NativeErrorConstructor::create(vm, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("TypeError"))); m_URIErrorConstructor.set(vm, this, NativeErrorConstructor::create(vm, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("URIError"))); m_promiseConstructor.set(vm, this, JSPromiseConstructor::create(vm, JSPromiseConstructor::createStructure(vm, this, m_functionPrototype.get()), m_promisePrototype.get())); - + m_objectPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, objectConstructor, DontEnum); m_functionPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, functionConstructor, DontEnum); m_arrayPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, arrayConstructor, DontEnum); m_regExpPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, m_regExpConstructor.get(), DontEnum); +#if ENABLE(PROMISES) m_promisePrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, m_promiseConstructor.get(), DontEnum); - +#endif + putDirectWithoutTransition(vm, vm.propertyNames->Object, objectConstructor, DontEnum); putDirectWithoutTransition(vm, vm.propertyNames->Function, functionConstructor, DontEnum); putDirectWithoutTransition(vm, vm.propertyNames->Array, arrayConstructor, DontEnum); @@ -415,97 +391,48 @@ m_ ## lowerName ## Prototype->putDirectWithoutTransition(vm, vm.propertyNames->c putDirectWithoutTransition(vm, vm.propertyNames->TypeError, m_typeErrorConstructor.get(), DontEnum); putDirectWithoutTransition(vm, vm.propertyNames->URIError, m_URIErrorConstructor.get(), DontEnum); putDirectWithoutTransition(vm, vm.propertyNames->Promise, m_promiseConstructor.get(), DontEnum); - - + + #define PUT_CONSTRUCTOR_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName) \ -putDirectWithoutTransition(vm, vm.propertyNames-> jsName, lowerName ## Constructor, DontEnum); \ + putDirectWithoutTransition(vm, vm.propertyNames-> jsName, lowerName ## Constructor, DontEnum); \ - FOR_EACH_SIMPLE_BUILTIN_TYPE_WITH_CONSTRUCTOR(PUT_CONSTRUCTOR_FOR_SIMPLE_TYPE) + FOR_EACH_SIMPLE_BUILTIN_TYPE(PUT_CONSTRUCTOR_FOR_SIMPLE_TYPE) #undef PUT_CONSTRUCTOR_FOR_SIMPLE_TYPE PrototypeMap& prototypeMap = vm.prototypeMap; Structure* iteratorResultStructure = prototypeMap.emptyObjectStructureForPrototype(m_objectPrototype.get(), JSFinalObject::defaultInlineCapacity()); PropertyOffset offset; - iteratorResultStructure = Structure::addPropertyTransition(vm, iteratorResultStructure, vm.propertyNames->done, 0, offset); - iteratorResultStructure = Structure::addPropertyTransition(vm, iteratorResultStructure, vm.propertyNames->value, 0, offset); + iteratorResultStructure = Structure::addPropertyTransition(vm, iteratorResultStructure, vm.propertyNames->done, 0, 0, offset); + iteratorResultStructure = Structure::addPropertyTransition(vm, iteratorResultStructure, vm.propertyNames->value, 0, 0, offset); m_iteratorResultStructure.set(vm, this, iteratorResultStructure); - + m_evalFunction.set(vm, this, JSFunction::create(vm, this, 1, vm.propertyNames->eval.string(), globalFuncEval)); putDirectWithoutTransition(vm, vm.propertyNames->eval, m_evalFunction.get(), DontEnum); - -#if ENABLE(INTL) - putDirectWithoutTransition(vm, vm.propertyNames->Intl, IntlObject::create(vm, this, IntlObject::createStructure(vm, this, m_objectPrototype.get())), DontEnum); -#endif // ENABLE(INTL) + putDirectWithoutTransition(vm, vm.propertyNames->JSON, JSONObject::create(vm, JSONObject::createStructure(vm, this, m_objectPrototype.get())), DontEnum); putDirectWithoutTransition(vm, vm.propertyNames->Math, MathObject::create(vm, this, MathObject::createStructure(vm, this, m_objectPrototype.get())), DontEnum); - putDirectWithoutTransition(vm, vm.propertyNames->Reflect, ReflectObject::create(vm, this, ReflectObject::createStructure(vm, this, m_objectPrototype.get())), DontEnum); std::array<InternalFunction*, NUMBER_OF_TYPED_ARRAY_TYPES> typedArrayConstructors; - typedArrayConstructors[toIndex(TypeInt8)] = JSInt8ArrayConstructor::create(vm, JSInt8ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeInt8)].prototype.get(), ASCIILiteral("Int8Array")); - typedArrayConstructors[toIndex(TypeInt16)] = JSInt16ArrayConstructor::create(vm, JSInt16ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeInt16)].prototype.get(), ASCIILiteral("Int16Array")); - typedArrayConstructors[toIndex(TypeInt32)] = JSInt32ArrayConstructor::create(vm, JSInt32ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeInt32)].prototype.get(), ASCIILiteral("Int32Array")); - typedArrayConstructors[toIndex(TypeUint8)] = JSUint8ArrayConstructor::create(vm, JSUint8ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeUint8)].prototype.get(), ASCIILiteral("Uint8Array")); - typedArrayConstructors[toIndex(TypeUint8Clamped)] = JSUint8ClampedArrayConstructor::create(vm, JSUint8ClampedArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeUint8Clamped)].prototype.get(), ASCIILiteral("Uint8ClampedArray")); - typedArrayConstructors[toIndex(TypeUint16)] = JSUint16ArrayConstructor::create(vm, JSUint16ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeUint16)].prototype.get(), ASCIILiteral("Uint16Array")); - typedArrayConstructors[toIndex(TypeUint32)] = JSUint32ArrayConstructor::create(vm, JSUint32ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeUint32)].prototype.get(), ASCIILiteral("Uint32Array")); - typedArrayConstructors[toIndex(TypeFloat32)] = JSFloat32ArrayConstructor::create(vm, JSFloat32ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeFloat32)].prototype.get(), ASCIILiteral("Float32Array")); - typedArrayConstructors[toIndex(TypeFloat64)] = JSFloat64ArrayConstructor::create(vm, JSFloat64ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeFloat64)].prototype.get(), ASCIILiteral("Float64Array")); - typedArrayConstructors[toIndex(TypeDataView)] = JSDataViewConstructor::create(vm, JSDataViewConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeDataView)].prototype.get(), ASCIILiteral("DataView")); - + typedArrayConstructors[toIndex(TypeInt8)] = JSInt8ArrayConstructor::create(vm, JSInt8ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeInt8)].prototype.get(), "Int8Array"); + typedArrayConstructors[toIndex(TypeInt16)] = JSInt16ArrayConstructor::create(vm, JSInt16ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeInt16)].prototype.get(), "Int16Array"); + typedArrayConstructors[toIndex(TypeInt32)] = JSInt32ArrayConstructor::create(vm, JSInt32ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeInt32)].prototype.get(), "Int32Array"); + typedArrayConstructors[toIndex(TypeUint8)] = JSUint8ArrayConstructor::create(vm, JSUint8ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeUint8)].prototype.get(), "Uint8Array"); + typedArrayConstructors[toIndex(TypeUint8Clamped)] = JSUint8ClampedArrayConstructor::create(vm, JSUint8ClampedArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeUint8Clamped)].prototype.get(), "Uint8ClampedArray"); + typedArrayConstructors[toIndex(TypeUint16)] = JSUint16ArrayConstructor::create(vm, JSUint16ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeUint16)].prototype.get(), "Uint16Array"); + typedArrayConstructors[toIndex(TypeUint32)] = JSUint32ArrayConstructor::create(vm, JSUint32ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeUint32)].prototype.get(), "Uint32Array"); + typedArrayConstructors[toIndex(TypeFloat32)] = JSFloat32ArrayConstructor::create(vm, JSFloat32ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeFloat32)].prototype.get(), "Float32Array"); + typedArrayConstructors[toIndex(TypeFloat64)] = JSFloat64ArrayConstructor::create(vm, JSFloat64ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeFloat64)].prototype.get(), "Float64Array"); + typedArrayConstructors[toIndex(TypeDataView)] = JSDataViewConstructor::create(vm, JSDataViewConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeDataView)].prototype.get(), "DataView"); + for (unsigned typedArrayIndex = NUMBER_OF_TYPED_ARRAY_TYPES; typedArrayIndex--;) { m_typedArrays[typedArrayIndex].prototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, typedArrayConstructors[typedArrayIndex], DontEnum); - putDirectWithoutTransition(vm, Identifier::fromString(exec, typedArrayConstructors[typedArrayIndex]->name(exec)), typedArrayConstructors[typedArrayIndex], DontEnum); + putDirectWithoutTransition(vm, Identifier(exec, typedArrayConstructors[typedArrayIndex]->name(exec)), typedArrayConstructors[typedArrayIndex], DontEnum); } - - JSFunction* builtinLog = JSFunction::create(vm, this, 1, vm.propertyNames->emptyIdentifier.string(), globalFuncBuiltinLog); - - JSFunction* privateFuncAbs = JSFunction::create(vm, this, 0, String(), mathProtoFuncAbs, AbsIntrinsic); - JSFunction* privateFuncFloor = JSFunction::create(vm, this, 0, String(), mathProtoFuncFloor, FloorIntrinsic); - JSFunction* privateFuncIsFinite = JSFunction::create(vm, this, 0, String(), globalFuncIsFinite); - - JSFunction* privateFuncGetTemplateObject = JSFunction::create(vm, this, 0, String(), getTemplateObject); - JSFunction* privateFuncToLength = JSFunction::createBuiltinFunction(vm, globalObjectToLengthCodeGenerator(vm), this); - JSFunction* privateFuncToInteger = JSFunction::createBuiltinFunction(vm, globalObjectToIntegerCodeGenerator(vm), this); GlobalPropertyInfo staticGlobals[] = { GlobalPropertyInfo(vm.propertyNames->NaN, jsNaN(), DontEnum | DontDelete | ReadOnly), GlobalPropertyInfo(vm.propertyNames->Infinity, jsNumber(std::numeric_limits<double>::infinity()), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->undefinedKeyword, jsUndefined(), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->undefinedPrivateName, jsUndefined(), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->ObjectPrivateName, objectConstructor, DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->ownEnumerablePropertyKeysPrivateName, JSFunction::create(vm, this, 0, String(), ownEnumerablePropertyKeys), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->getTemplateObjectPrivateName, privateFuncGetTemplateObject, DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->enqueueJobPrivateName, JSFunction::create(vm, this, 0, String(), enqueueJob), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->TypeErrorPrivateName, m_typeErrorConstructor.get(), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->BuiltinLogPrivateName, builtinLog, DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->ArrayPrivateName, arrayConstructor, DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->NumberPrivateName, numberConstructor, DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->StringPrivateName, stringConstructor, DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->absPrivateName, privateFuncAbs, DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->floorPrivateName, privateFuncFloor, DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->getPrototypeOfPrivateName, privateFuncFloor, DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->getOwnPropertyNamesPrivateName, privateFuncFloor, DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->isFinitePrivateName, privateFuncIsFinite, DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->arrayIterationKindKeyPrivateName, jsNumber(ArrayIterateKey), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->arrayIterationKindValuePrivateName, jsNumber(ArrayIterateValue), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->arrayIterationKindKeyValuePrivateName, jsNumber(ArrayIterateKeyValue), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->builtinNames().symbolIteratorPrivateName(), Symbol::create(vm, static_cast<SymbolImpl&>(*vm.propertyNames->iteratorSymbol.impl())), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->PromisePrivateName, m_promiseConstructor.get(), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->promisePendingPrivateName, jsNumber(static_cast<unsigned>(JSPromise::Status::Pending)), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->promiseFulfilledPrivateName, jsNumber(static_cast<unsigned>(JSPromise::Status::Fulfilled)), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->promiseRejectedPrivateName, jsNumber(static_cast<unsigned>(JSPromise::Status::Rejected)), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->builtinNames().toLengthPrivateName(), privateFuncToLength, DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->builtinNames().toIntegerPrivateName(), privateFuncToInteger, DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->builtinNames().isObjectPrivateName(), JSFunction::createBuiltinFunction(vm, globalObjectIsObjectCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->builtinNames().isPromisePrivateName(), JSFunction::createBuiltinFunction(vm, operationsPromiseIsPromiseCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->builtinNames().newPromiseReactionPrivateName(), JSFunction::createBuiltinFunction(vm, operationsPromiseNewPromiseReactionCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->builtinNames().newPromiseCapabilityPrivateName(), JSFunction::createBuiltinFunction(vm, operationsPromiseNewPromiseCapabilityCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->builtinNames().triggerPromiseReactionsPrivateName(), JSFunction::createBuiltinFunction(vm, operationsPromiseTriggerPromiseReactionsCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->builtinNames().rejectPromisePrivateName(), JSFunction::createBuiltinFunction(vm, operationsPromiseRejectPromiseCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->builtinNames().fulfillPromisePrivateName(), JSFunction::createBuiltinFunction(vm, operationsPromiseFulfillPromiseCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->builtinNames().createResolvingFunctionsPrivateName(), JSFunction::createBuiltinFunction(vm, operationsPromiseCreateResolvingFunctionsCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->builtinNames().promiseReactionJobPrivateName(), JSFunction::createBuiltinFunction(vm, operationsPromisePromiseReactionJobCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->builtinNames().promiseResolveThenableJobPrivateName(), JSFunction::createBuiltinFunction(vm, operationsPromisePromiseResolveThenableJobCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly), + GlobalPropertyInfo(vm.propertyNames->undefinedKeyword, jsUndefined(), DontEnum | DontDelete | ReadOnly) }; addStaticGlobals(staticGlobals, WTF_ARRAY_LENGTH(staticGlobals)); @@ -514,72 +441,16 @@ putDirectWithoutTransition(vm, vm.propertyNames-> jsName, lowerName ## Construct m_specialPointers[Special::ObjectConstructor] = objectConstructor; m_specialPointers[Special::ArrayConstructor] = arrayConstructor; - m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::DefinePropertyFunction)] = m_definePropertyFunction.get(); - - ConsolePrototype* consolePrototype = ConsolePrototype::create(vm, this, ConsolePrototype::createStructure(vm, this, m_objectPrototype.get())); - m_consoleStructure.set(vm, this, JSConsole::createStructure(vm, this, consolePrototype)); - JSConsole* consoleObject = JSConsole::create(vm, m_consoleStructure.get()); - putDirectWithoutTransition(vm, Identifier::fromString(exec, "console"), consoleObject, DontEnum); + if (m_experimentsEnabled) { + NamePrototype* privateNamePrototype = NamePrototype::create(exec, NamePrototype::createStructure(vm, this, m_objectPrototype.get())); + m_privateNameStructure.set(vm, this, NameInstance::createStructure(vm, this, privateNamePrototype)); - if (UNLIKELY(Options::enableDollarVM())) { - JSDollarVMPrototype* dollarVMPrototype = JSDollarVMPrototype::create(vm, this, JSDollarVMPrototype::createStructure(vm, this, m_objectPrototype.get())); - m_dollarVMStructure.set(vm, this, JSDollarVM::createStructure(vm, this, dollarVMPrototype)); - JSDollarVM* dollarVM = JSDollarVM::create(vm, m_dollarVMStructure.get()); - putDirectWithoutTransition(vm, Identifier::fromString(exec, "$vm"), dollarVM, DontEnum); + JSCell* privateNameConstructor = NameConstructor::create(vm, NameConstructor::createStructure(vm, this, m_functionPrototype.get()), privateNamePrototype); + privateNamePrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, privateNameConstructor, DontEnum); + putDirectWithoutTransition(vm, Identifier(exec, "Name"), privateNameConstructor, DontEnum); } - resetPrototype(vm, prototype()); -} - -void JSGlobalObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) -{ - JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(cell); - ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); - - if (symbolTablePut(thisObject, exec, propertyName, value, slot.isStrictMode())) - return; - Base::put(thisObject, exec, propertyName, value, slot); -} - -bool JSGlobalObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow) -{ - JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(object); - PropertySlot slot(thisObject); - // silently ignore attempts to add accessors aliasing vars. - if (descriptor.isAccessorDescriptor() && symbolTableGet(thisObject, propertyName, slot)) - return false; - return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow); -} - -void JSGlobalObject::addGlobalVar(const Identifier& ident) -{ - ConcurrentJITLocker locker(symbolTable()->m_lock); - SymbolTableEntry entry = symbolTable()->get(locker, ident.impl()); - if (!entry.isNull()) - return; - - ScopeOffset offset = symbolTable()->takeNextScopeOffset(locker); - SymbolTableEntry newEntry(VarOffset(offset), 0); - newEntry.prepareToWatch(); - symbolTable()->add(locker, ident.impl(), newEntry); - - ScopeOffset offsetForAssert = addVariables(1); - RELEASE_ASSERT(offsetForAssert == offset); -} - -void JSGlobalObject::addFunction(ExecState* exec, const Identifier& propertyName) -{ - VM& vm = exec->vm(); - removeDirect(vm, propertyName); // Newly declared functions overwrite existing properties. - addGlobalVar(propertyName); -} - -static inline JSObject* lastInPrototypeChain(JSObject* object) -{ - JSObject* o = object; - while (o->prototype().isObject()) - o = asObject(o->prototype()); - return o; + resetPrototype(vm, prototype); } // Private namespace for helpers for JSGlobalObject::haveABadTime() @@ -588,11 +459,9 @@ namespace { class ObjectsWithBrokenIndexingFinder : public MarkedBlock::VoidFunctor { public: ObjectsWithBrokenIndexingFinder(MarkedArgumentBuffer&, JSGlobalObject*); - IterationStatus operator()(JSCell*); + void operator()(JSCell*); private: - void visit(JSCell*); - MarkedArgumentBuffer& m_foundObjects; JSGlobalObject* m_globalObject; }; @@ -607,13 +476,13 @@ ObjectsWithBrokenIndexingFinder::ObjectsWithBrokenIndexingFinder( inline bool hasBrokenIndexing(JSObject* object) { // This will change if we have more indexing types. - IndexingType type = object->indexingType(); + IndexingType type = object->structure()->indexingType(); // This could be made obviously more efficient, but isn't made so right now, because // we expect this to be an unlikely slow path anyway. - return hasUndecided(type) || hasInt32(type) || hasDouble(type) || hasContiguous(type) || hasArrayStorage(type); + return hasUndecided(type) || hasInt32(type) || hasDouble(type) || hasContiguous(type) || hasFastArrayStorage(type); } -inline void ObjectsWithBrokenIndexingFinder::visit(JSCell* cell) +void ObjectsWithBrokenIndexingFinder::operator()(JSCell* cell) { if (!cell->isObject()) return; @@ -645,12 +514,6 @@ inline void ObjectsWithBrokenIndexingFinder::visit(JSCell* cell) m_foundObjects.append(object); } -IterationStatus ObjectsWithBrokenIndexingFinder::operator()(JSCell* cell) -{ - visit(cell); - return IterationStatus::Continue; -} - } // end private namespace for helpers for JSGlobalObject::haveABadTime() void JSGlobalObject::haveABadTime(VM& vm) @@ -663,7 +526,7 @@ void JSGlobalObject::haveABadTime(VM& vm) // Make sure that all allocations or indexed storage transitions that are inlining // the assumption that it's safe to transition to a non-SlowPut array storage don't // do so anymore. - m_havingABadTimeWatchpoint->fireAll("Having a bad time"); + m_havingABadTimeWatchpoint->fireAll(); ASSERT(isHavingABadTime()); // The watchpoint is what tells us that we're having a bad time. // Make sure that all JSArray allocations that load the appropriate structure from @@ -689,20 +552,20 @@ void JSGlobalObject::haveABadTime(VM& vm) bool JSGlobalObject::objectPrototypeIsSane() { - return !hasIndexedProperties(m_objectPrototype->indexingType()) + return !hasIndexedProperties(m_objectPrototype->structure()->indexingType()) && m_objectPrototype->prototype().isNull(); } bool JSGlobalObject::arrayPrototypeChainIsSane() { - return !hasIndexedProperties(m_arrayPrototype->indexingType()) + return !hasIndexedProperties(m_arrayPrototype->structure()->indexingType()) && m_arrayPrototype->prototype() == m_objectPrototype.get() && objectPrototypeIsSane(); } bool JSGlobalObject::stringPrototypeChainIsSane() { - return !hasIndexedProperties(m_stringPrototype->indexingType()) + return !hasIndexedProperties(m_stringPrototype->structure()->indexingType()) && m_stringPrototype->prototype() == m_objectPrototype.get() && objectPrototypeIsSane(); } @@ -710,9 +573,9 @@ bool JSGlobalObject::stringPrototypeChainIsSane() void JSGlobalObject::createThrowTypeError(VM& vm) { JSFunction* thrower = JSFunction::create(vm, this, 0, String(), globalFuncThrowTypeError); - GetterSetter* getterSetter = GetterSetter::create(vm, this); - getterSetter->setGetter(vm, this, thrower); - getterSetter->setSetter(vm, this, thrower); + GetterSetter* getterSetter = GetterSetter::create(vm); + getterSetter->setGetter(vm, thrower); + getterSetter->setSetter(vm, thrower); m_throwTypeErrorGetterSetter.set(vm, this, getterSetter); } @@ -725,20 +588,18 @@ void JSGlobalObject::resetPrototype(VM& vm, JSValue prototype) JSObject* objectPrototype = m_objectPrototype.get(); if (oldLastInPrototypeChain != objectPrototype) oldLastInPrototypeChain->setPrototype(vm, objectPrototype); - - // Whenever we change the prototype of the global object, we need to create a new JSProxy with the correct prototype. - setGlobalThis(vm, JSProxy::create(vm, JSProxy::createStructure(vm, this, prototype, PureForwardingProxyType), this)); } void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) { JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); Base::visitChildren(thisObject, visitor); visitor.append(&thisObject->m_globalThis); - visitor.append(&thisObject->m_globalCallee); visitor.append(&thisObject->m_regExpConstructor); visitor.append(&thisObject->m_errorConstructor); visitor.append(&thisObject->m_evalErrorConstructor); @@ -747,36 +608,26 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) visitor.append(&thisObject->m_syntaxErrorConstructor); visitor.append(&thisObject->m_typeErrorConstructor); visitor.append(&thisObject->m_URIErrorConstructor); - visitor.append(&thisObject->m_objectConstructor); visitor.append(&thisObject->m_promiseConstructor); - visitor.append(&thisObject->m_nullGetterFunction); - visitor.append(&thisObject->m_nullSetterFunction); - - visitor.append(&thisObject->m_parseIntFunction); visitor.append(&thisObject->m_evalFunction); visitor.append(&thisObject->m_callFunction); visitor.append(&thisObject->m_applyFunction); - visitor.append(&thisObject->m_definePropertyFunction); - visitor.append(&thisObject->m_arrayProtoValuesFunction); - visitor.append(&thisObject->m_initializePromiseFunction); - visitor.append(&thisObject->m_newPromiseDeferredFunction); visitor.append(&thisObject->m_throwTypeErrorGetterSetter); visitor.append(&thisObject->m_objectPrototype); visitor.append(&thisObject->m_functionPrototype); visitor.append(&thisObject->m_arrayPrototype); visitor.append(&thisObject->m_errorPrototype); - visitor.append(&thisObject->m_iteratorPrototype); +#if ENABLE(PROMISES) visitor.append(&thisObject->m_promisePrototype); +#endif - visitor.append(&thisObject->m_debuggerScopeStructure); visitor.append(&thisObject->m_withScopeStructure); visitor.append(&thisObject->m_strictEvalActivationStructure); - visitor.append(&thisObject->m_lexicalEnvironmentStructure); - visitor.append(&thisObject->m_directArgumentsStructure); - visitor.append(&thisObject->m_scopedArgumentsStructure); - visitor.append(&thisObject->m_outOfBandArgumentsStructure); + visitor.append(&thisObject->m_activationStructure); + visitor.append(&thisObject->m_nameScopeStructure); + visitor.append(&thisObject->m_argumentsStructure); for (unsigned i = 0; i < NumberOfIndexingShapes; ++i) visitor.append(&thisObject->m_originalArrayStructureForIndexingShape[i]); for (unsigned i = 0; i < NumberOfIndexingShapes; ++i) @@ -785,34 +636,29 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) visitor.append(&thisObject->m_callbackConstructorStructure); visitor.append(&thisObject->m_callbackFunctionStructure); visitor.append(&thisObject->m_callbackObjectStructure); - visitor.append(&thisObject->m_propertyNameIteratorStructure); #if JSC_OBJC_API_ENABLED visitor.append(&thisObject->m_objcCallbackFunctionStructure); visitor.append(&thisObject->m_objcWrapperObjectStructure); #endif visitor.append(&thisObject->m_nullPrototypeObjectStructure); visitor.append(&thisObject->m_errorStructure); - visitor.append(&thisObject->m_calleeStructure); visitor.append(&thisObject->m_functionStructure); visitor.append(&thisObject->m_boundFunctionStructure); visitor.append(&thisObject->m_namedFunctionStructure); - visitor.append(&thisObject->m_symbolObjectStructure); - visitor.append(&thisObject->m_regExpStructure); + visitor.append(&thisObject->m_privateNameStructure); visitor.append(&thisObject->m_regExpMatchesArrayStructure); - visitor.append(&thisObject->m_consoleStructure); - visitor.append(&thisObject->m_dollarVMStructure); + visitor.append(&thisObject->m_regExpStructure); visitor.append(&thisObject->m_internalFunctionStructure); + +#if ENABLE(PROMISES) visitor.append(&thisObject->m_promiseStructure); -#if ENABLE(WEBASSEMBLY) - visitor.append(&thisObject->m_wasmModuleStructure); -#endif +#endif // ENABLE(PROMISES) #define VISIT_SIMPLE_TYPE(CapitalName, lowerName, properName, instanceType, jsName) \ visitor.append(&thisObject->m_ ## lowerName ## Prototype); \ visitor.append(&thisObject->m_ ## properName ## Structure); \ FOR_EACH_SIMPLE_BUILTIN_TYPE(VISIT_SIMPLE_TYPE) - FOR_EACH_BUILTIN_DERIVED_ITERATOR_TYPE(VISIT_SIMPLE_TYPE) #undef VISIT_SIMPLE_TYPE @@ -836,35 +682,30 @@ ExecState* JSGlobalObject::globalExec() void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count) { - ScopeOffset startOffset = addVariables(count); + addRegisters(count); for (int i = 0; i < count; ++i) { GlobalPropertyInfo& global = globals[i]; ASSERT(global.attributes & DontDelete); - ScopeOffset offset; - { - ConcurrentJITLocker locker(symbolTable()->m_lock); - offset = symbolTable()->takeNextScopeOffset(locker); - RELEASE_ASSERT(offset = startOffset + i); - SymbolTableEntry newEntry(VarOffset(offset), global.attributes); - symbolTable()->add(locker, global.identifier.impl(), newEntry); - } - variableAt(offset).set(vm(), this, global.value); + int index = symbolTable()->size(); + SymbolTableEntry newEntry(index, global.attributes); + symbolTable()->add(global.identifier.impl(), newEntry); + registerAt(index).set(vm(), this, global.value); } } bool JSGlobalObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(object); - if (getStaticFunctionSlot<Base>(exec, globalObjectTable, thisObject, propertyName, slot)) + if (getStaticFunctionSlot<Base>(exec, ExecState::globalObjectTable(exec->vm()), thisObject, propertyName, slot)) return true; return symbolTableGet(thisObject, propertyName, slot); } void JSGlobalObject::clearRareData(JSCell* cell) { - jsCast<JSGlobalObject*>(cell)->m_rareData = nullptr; + jsCast<JSGlobalObject*>(cell)->m_rareData.clear(); } void slowValidateCell(JSGlobalObject* globalObject) @@ -876,39 +717,36 @@ void slowValidateCell(JSGlobalObject* globalObject) UnlinkedProgramCodeBlock* JSGlobalObject::createProgramCodeBlock(CallFrame* callFrame, ProgramExecutable* executable, JSObject** exception) { ParserError error; - JSParserStrictMode strictMode = executable->isStrictMode() ? JSParserStrictMode::Strict : JSParserStrictMode::NotStrict; + JSParserStrictness strictness = executable->isStrictMode() ? JSParseStrict : JSParseNormal; DebuggerMode debuggerMode = hasDebugger() ? DebuggerOn : DebuggerOff; ProfilerMode profilerMode = hasProfiler() ? ProfilerOn : ProfilerOff; - UnlinkedProgramCodeBlock* unlinkedCodeBlock = vm().codeCache()->getProgramCodeBlock( - vm(), executable, executable->source(), JSParserBuiltinMode::NotBuiltin, strictMode, - debuggerMode, profilerMode, error); + UnlinkedProgramCodeBlock* unlinkedCodeBlock = vm().codeCache()->getProgramCodeBlock(vm(), executable, executable->source(), strictness, debuggerMode, profilerMode, error); if (hasDebugger()) - debugger()->sourceParsed(callFrame, executable->source().provider(), error.line(), error.message()); + debugger()->sourceParsed(callFrame, executable->source().provider(), error.m_line, error.m_message); - if (error.isValid()) { + if (error.m_type != ParserError::ErrorNone) { *exception = error.toErrorObject(this, executable->source()); - return nullptr; + return 0; } return unlinkedCodeBlock; } -UnlinkedEvalCodeBlock* JSGlobalObject::createEvalCodeBlock(CallFrame* callFrame, EvalExecutable* executable, ThisTDZMode thisTDZMode, const VariableEnvironment* variablesUnderTDZ) +UnlinkedEvalCodeBlock* JSGlobalObject::createEvalCodeBlock(CallFrame* callFrame, EvalExecutable* executable) { ParserError error; - JSParserStrictMode strictMode = executable->isStrictMode() ? JSParserStrictMode::Strict : JSParserStrictMode::NotStrict; + JSParserStrictness strictness = executable->isStrictMode() ? JSParseStrict : JSParseNormal; DebuggerMode debuggerMode = hasDebugger() ? DebuggerOn : DebuggerOff; ProfilerMode profilerMode = hasProfiler() ? ProfilerOn : ProfilerOff; - UnlinkedEvalCodeBlock* unlinkedCodeBlock = vm().codeCache()->getEvalCodeBlock( - vm(), executable, executable->source(), JSParserBuiltinMode::NotBuiltin, strictMode, thisTDZMode, debuggerMode, profilerMode, error, variablesUnderTDZ); + UnlinkedEvalCodeBlock* unlinkedCodeBlock = vm().codeCache()->getEvalCodeBlock(vm(), executable, executable->source(), strictness, debuggerMode, profilerMode, error); if (hasDebugger()) - debugger()->sourceParsed(callFrame, executable->source().provider(), error.line(), error.message()); + debugger()->sourceParsed(callFrame, executable->source().provider(), error.m_line, error.m_message); - if (error.isValid()) { + if (error.m_type != ParserError::ErrorNone) { throwVMError(callFrame, error.toErrorObject(this, executable->source())); - return nullptr; + return 0; } return unlinkedCodeBlock; @@ -932,24 +770,6 @@ bool JSGlobalObject::remoteDebuggingEnabled() const #endif } -#if ENABLE(WEB_REPLAY) -void JSGlobalObject::setInputCursor(PassRefPtr<InputCursor> prpCursor) -{ - m_inputCursor = prpCursor; - ASSERT(m_inputCursor); - - InputCursor& cursor = inputCursor(); - // Save or set the random seed. This performed here rather than the constructor - // to avoid threading the input cursor through all the abstraction layers. - if (cursor.isCapturing()) - cursor.appendInput<SetRandomSeed>(m_weakRandom.seedUnsafe()); - else if (cursor.isReplaying()) { - if (SetRandomSeed* input = cursor.fetchInput<SetRandomSeed>()) - m_weakRandom.initializeSeed(static_cast<unsigned>(input->randomSeed())); - } -} -#endif - void JSGlobalObject::setName(const String& name) { m_name = name; @@ -961,12 +781,10 @@ void JSGlobalObject::setName(const String& name) void JSGlobalObject::queueMicrotask(PassRefPtr<Microtask> task) { - if (globalObjectMethodTable()->queueTaskToEventLoop) { + if (globalObjectMethodTable()->queueTaskToEventLoop) globalObjectMethodTable()->queueTaskToEventLoop(this, task); - return; - } - - vm().queueMicrotask(this, task); + else + WTFLogAlways("ERROR: Event loop not supported."); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h index 9986bcf62..b0cad3dc5 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.h +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2007 Eric Seidel <eric@webkit.org> - * Copyright (C) 2007, 2008, 2009, 2014, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009, 2014 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 @@ -23,41 +23,33 @@ #define JSGlobalObject_h #include "ArrayAllocationProfile.h" +#include "ConstantMode.h" #include "JSArray.h" #include "JSArrayBufferPrototype.h" #include "JSClassRef.h" -#include "JSProxy.h" #include "JSSegmentedVariableObject.h" #include "JSWeakObjectMapRefInternal.h" #include "NumberPrototype.h" -#include "RuntimeFlags.h" #include "SpecialPointer.h" #include "StringPrototype.h" #include "StructureChain.h" #include "StructureRareDataInlines.h" -#include "SymbolPrototype.h" -#include "TemplateRegistry.h" #include "VM.h" -#include "VariableEnvironment.h" #include "Watchpoint.h" #include <JavaScriptCore/JSBase.h> #include <array> #include <wtf/HashSet.h> +#include <wtf/OwnPtr.h> #include <wtf/PassRefPtr.h> #include <wtf/RandomNumber.h> struct OpaqueJSClass; struct OpaqueJSClassContextData; -namespace Inspector { -class JSGlobalObjectInspectorController; -} - namespace JSC { class ArrayPrototype; class BooleanPrototype; -class ConsoleClient; class Debugger; class ErrorConstructor; class ErrorPrototype; @@ -68,7 +60,6 @@ class FunctionExecutable; class FunctionPrototype; class GetterSetter; class GlobalCodeBlock; -class InputCursor; class JSGlobalObjectDebuggable; class JSPromiseConstructor; class JSPromisePrototype; @@ -76,54 +67,38 @@ class JSStack; class LLIntOffsetsExtractor; class Microtask; class NativeErrorConstructor; -class ObjectConstructor; class ProgramCodeBlock; class ProgramExecutable; class RegExpConstructor; class RegExpPrototype; class SourceCode; -class NullGetterFunction; -class NullSetterFunction; -enum class ThisTDZMode; struct ActivationStackNode; struct HashTable; #define DEFINE_STANDARD_BUILTIN(macro, upperName, lowerName) macro(upperName, lowerName, lowerName, JS ## upperName, upperName) - -#define FOR_EACH_SIMPLE_BUILTIN_TYPE_WITH_CONSTRUCTOR(macro) \ + +#define FOR_EACH_SIMPLE_BUILTIN_TYPE(macro) \ macro(Set, set, set, JSSet, Set) \ macro(Map, map, map, JSMap, Map) \ macro(Date, date, date, DateInstance, Date) \ macro(String, string, stringObject, StringObject, String) \ - macro(Symbol, symbol, symbolObject, SymbolObject, Symbol) \ macro(Boolean, boolean, booleanObject, BooleanObject, Boolean) \ macro(Number, number, numberObject, NumberObject, Number) \ macro(Error, error, error, ErrorInstance, Error) \ macro(JSArrayBuffer, arrayBuffer, arrayBuffer, JSArrayBuffer, ArrayBuffer) \ DEFINE_STANDARD_BUILTIN(macro, WeakMap, weakMap) \ - DEFINE_STANDARD_BUILTIN(macro, WeakSet, weakSet) \ - -#define FOR_EACH_BUILTIN_DERIVED_ITERATOR_TYPE(macro) \ DEFINE_STANDARD_BUILTIN(macro, ArrayIterator, arrayIterator) \ + DEFINE_STANDARD_BUILTIN(macro, ArgumentsIterator, argumentsIterator) \ DEFINE_STANDARD_BUILTIN(macro, MapIterator, mapIterator) \ DEFINE_STANDARD_BUILTIN(macro, SetIterator, setIterator) \ - DEFINE_STANDARD_BUILTIN(macro, StringIterator, stringIterator) \ -#define FOR_EACH_BUILTIN_ITERATOR_TYPE(macro) \ - DEFINE_STANDARD_BUILTIN(macro, Iterator, iterator) \ - FOR_EACH_BUILTIN_DERIVED_ITERATOR_TYPE(macro) \ - -#define FOR_EACH_SIMPLE_BUILTIN_TYPE(macro) \ - FOR_EACH_SIMPLE_BUILTIN_TYPE_WITH_CONSTRUCTOR(macro) \ #define DECLARE_SIMPLE_BUILTIN_TYPE(capitalName, lowerName, properName, instanceType, jsName) \ class JS ## capitalName; \ class capitalName ## Prototype; \ class capitalName ## Constructor; -class IteratorPrototype; FOR_EACH_SIMPLE_BUILTIN_TYPE(DECLARE_SIMPLE_BUILTIN_TYPE) -FOR_EACH_BUILTIN_DERIVED_ITERATOR_TYPE(DECLARE_SIMPLE_BUILTIN_TYPE) #undef DECLARE_SIMPLE_BUILTIN_TYPE @@ -142,8 +117,8 @@ struct GlobalObjectMethodTable { typedef bool (*ShouldInterruptScriptFunctionPtr)(const JSGlobalObject*); ShouldInterruptScriptFunctionPtr shouldInterruptScript; - typedef RuntimeFlags (*JavaScriptRuntimeFlagsFunctionPtr)(const JSGlobalObject*); - JavaScriptRuntimeFlagsFunctionPtr javaScriptRuntimeFlags; + typedef bool (*JavaScriptExperimentsEnabledFunctionPtr)(const JSGlobalObject*); + JavaScriptExperimentsEnabledFunctionPtr javaScriptExperimentsEnabled; typedef void (*QueueTaskToEventLoopFunctionPtr)(const JSGlobalObject*, PassRefPtr<Microtask>); QueueTaskToEventLoopFunctionPtr queueTaskToEventLoop; @@ -174,7 +149,6 @@ protected: WriteBarrier<JSObject> m_globalThis; - WriteBarrier<JSObject> m_globalCallee; WriteBarrier<RegExpConstructor> m_regExpConstructor; WriteBarrier<ErrorConstructor> m_errorConstructor; WriteBarrier<NativeErrorConstructor> m_evalErrorConstructor; @@ -184,36 +158,23 @@ protected: WriteBarrier<NativeErrorConstructor> m_typeErrorConstructor; WriteBarrier<NativeErrorConstructor> m_URIErrorConstructor; WriteBarrier<JSPromiseConstructor> m_promiseConstructor; - WriteBarrier<ObjectConstructor> m_objectConstructor; - - WriteBarrier<NullGetterFunction> m_nullGetterFunction; - WriteBarrier<NullSetterFunction> m_nullSetterFunction; - - WriteBarrier<JSFunction> m_parseIntFunction; WriteBarrier<JSFunction> m_evalFunction; WriteBarrier<JSFunction> m_callFunction; WriteBarrier<JSFunction> m_applyFunction; - WriteBarrier<JSFunction> m_definePropertyFunction; - WriteBarrier<JSFunction> m_arrayProtoValuesFunction; - WriteBarrier<JSFunction> m_initializePromiseFunction; - WriteBarrier<JSFunction> m_newPromiseDeferredFunction; WriteBarrier<GetterSetter> m_throwTypeErrorGetterSetter; WriteBarrier<ObjectPrototype> m_objectPrototype; WriteBarrier<FunctionPrototype> m_functionPrototype; WriteBarrier<ArrayPrototype> m_arrayPrototype; WriteBarrier<RegExpPrototype> m_regExpPrototype; - WriteBarrier<IteratorPrototype> m_iteratorPrototype; WriteBarrier<JSPromisePrototype> m_promisePrototype; - WriteBarrier<Structure> m_debuggerScopeStructure; WriteBarrier<Structure> m_withScopeStructure; WriteBarrier<Structure> m_strictEvalActivationStructure; - WriteBarrier<Structure> m_lexicalEnvironmentStructure; - WriteBarrier<Structure> m_directArgumentsStructure; - WriteBarrier<Structure> m_scopedArgumentsStructure; - WriteBarrier<Structure> m_outOfBandArgumentsStructure; + 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]; @@ -223,35 +184,31 @@ protected: WriteBarrier<Structure> m_callbackConstructorStructure; WriteBarrier<Structure> m_callbackFunctionStructure; WriteBarrier<Structure> m_callbackObjectStructure; - WriteBarrier<Structure> m_propertyNameIteratorStructure; #if JSC_OBJC_API_ENABLED WriteBarrier<Structure> m_objcCallbackFunctionStructure; WriteBarrier<Structure> m_objcWrapperObjectStructure; #endif WriteBarrier<Structure> m_nullPrototypeObjectStructure; - WriteBarrier<Structure> m_calleeStructure; WriteBarrier<Structure> m_functionStructure; WriteBarrier<Structure> m_boundFunctionStructure; WriteBarrier<Structure> m_namedFunctionStructure; PropertyOffset m_functionNameOffset; WriteBarrier<Structure> m_privateNameStructure; + WriteBarrier<Structure> m_regExpMatchesArrayStructure; WriteBarrier<Structure> m_regExpStructure; - WriteBarrier<Structure> m_consoleStructure; - WriteBarrier<Structure> m_dollarVMStructure; WriteBarrier<Structure> m_internalFunctionStructure; + WriteBarrier<Structure> m_iteratorResultStructure; - WriteBarrier<Structure> m_regExpMatchesArrayStructure; + +#if ENABLE(PROMISES) WriteBarrier<Structure> m_promiseStructure; -#if ENABLE(WEBASSEMBLY) - WriteBarrier<Structure> m_wasmModuleStructure; -#endif +#endif // ENABLE(PROMISES) #define DEFINE_STORAGE_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName) \ WriteBarrier<capitalName ## Prototype> m_ ## lowerName ## Prototype; \ WriteBarrier<Structure> m_ ## properName ## Structure; FOR_EACH_SIMPLE_BUILTIN_TYPE(DEFINE_STORAGE_FOR_SIMPLE_TYPE) - FOR_EACH_BUILTIN_DERIVED_ITERATOR_TYPE(DEFINE_STORAGE_FOR_SIMPLE_TYPE) #undef DEFINE_STORAGE_FOR_SIMPLE_TYPE @@ -261,22 +218,14 @@ protected: }; std::array<TypedArrayData, NUMBER_OF_TYPED_ARRAY_TYPES> m_typedArrays; - - JSCell* m_specialPointers[Special::TableSize]; // Special pointers used by the LLInt and JIT. - JSCell* m_linkTimeConstants[LinkTimeConstantCount]; + + void* m_specialPointers[Special::TableSize]; // Special pointers used by the LLInt and JIT. String m_name; Debugger* m_debugger; - VM& m_vm; - -#if ENABLE(WEB_REPLAY) - RefPtr<InputCursor> m_inputCursor; -#endif - #if ENABLE(REMOTE_INSPECTOR) - std::unique_ptr<Inspector::JSGlobalObjectInspectorController> m_inspectorController; std::unique_ptr<JSGlobalObjectDebuggable> m_inspectorDebuggable; #endif @@ -284,16 +233,13 @@ protected: RefPtr<WatchpointSet> m_havingABadTimeWatchpoint; RefPtr<WatchpointSet> m_varInjectionWatchpoint; - std::unique_ptr<JSGlobalObjectRareData> m_rareData; + OwnPtr<JSGlobalObjectRareData> m_rareData; WeakRandom m_weakRandom; - TemplateRegistry m_templateRegistry; - bool m_evalEnabled; String m_evalDisabledErrorMessage; - RuntimeFlags m_runtimeFlags; - ConsoleClient* m_consoleClient; + bool m_experimentsEnabled; static JS_EXPORTDATA const GlobalObjectMethodTable s_globalObjectMethodTable; const GlobalObjectMethodTable* m_globalObjectMethodTable; @@ -302,12 +248,11 @@ protected: { if (m_rareData) return; - m_rareData = std::make_unique<JSGlobalObjectRareData>(); + m_rareData = adoptPtr(new JSGlobalObjectRareData); } public: typedef JSSegmentedVariableObject Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames; static JSGlobalObject* create(VM& vm, Structure* structure) { @@ -321,7 +266,6 @@ public: bool hasDebugger() const { return m_debugger; } bool hasProfiler() const { return globalObjectMethodTable()->supportsProfiling(this); } - const RuntimeFlags& runtimeFlags() const { return m_runtimeFlags; } protected: JS_EXPORT_PRIVATE explicit JSGlobalObject(VM&, Structure*, const GlobalObjectMethodTable* = 0); @@ -330,21 +274,23 @@ protected: { Base::finishCreation(vm); structure()->setGlobalObject(vm, this); - m_runtimeFlags = m_globalObjectMethodTable->javaScriptRuntimeFlags(this); - init(vm); - setGlobalThis(vm, JSProxy::create(vm, JSProxy::createStructure(vm, this, prototype(), PureForwardingProxyType), this)); + m_experimentsEnabled = m_globalObjectMethodTable->javaScriptExperimentsEnabled(this); + init(this); } void finishCreation(VM& vm, JSObject* thisValue) { Base::finishCreation(vm); structure()->setGlobalObject(vm, this); - m_runtimeFlags = m_globalObjectMethodTable->javaScriptRuntimeFlags(this); - init(vm); - setGlobalThis(vm, thisValue); + m_experimentsEnabled = m_globalObjectMethodTable->javaScriptExperimentsEnabled(this); + init(thisValue); } - void addGlobalVar(const Identifier&); + struct NewGlobalVar { + int registerNumber; + VariableWatchpointSet* set; + }; + NewGlobalVar addGlobalVar(const Identifier&, ConstantMode); public: JS_EXPORT_PRIVATE ~JSGlobalObject(); @@ -369,9 +315,14 @@ public: void addVar(ExecState* exec, const Identifier& propertyName) { if (!hasProperty(exec, propertyName)) - addGlobalVar(propertyName); + addGlobalVar(propertyName, IsVariable); + } + void addConst(ExecState* exec, const Identifier& propertyName) + { + if (!hasProperty(exec, propertyName)) + addGlobalVar(propertyName, IsConstant); } - void addFunction(ExecState*, const Identifier&); + void addFunction(ExecState*, const Identifier&, JSValue); // The following accessors return pristine values, even if a script // replaces the global object's associated property. @@ -379,7 +330,6 @@ public: RegExpConstructor* regExpConstructor() const { return m_regExpConstructor.get(); } ErrorConstructor* errorConstructor() const { return m_errorConstructor.get(); } - ObjectConstructor* objectConstructor() const { return m_objectConstructor.get(); } NativeErrorConstructor* evalErrorConstructor() const { return m_evalErrorConstructor.get(); } NativeErrorConstructor* rangeErrorConstructor() const { return m_rangeErrorConstructor.get(); } NativeErrorConstructor* referenceErrorConstructor() const { return m_referenceErrorConstructor.get(); } @@ -388,18 +338,9 @@ public: NativeErrorConstructor* URIErrorConstructor() const { return m_URIErrorConstructor.get(); } JSPromiseConstructor* promiseConstructor() const { return m_promiseConstructor.get(); } - NullGetterFunction* nullGetterFunction() const { return m_nullGetterFunction.get(); } - NullSetterFunction* nullSetterFunction() const { return m_nullSetterFunction.get(); } - - JSFunction* parseIntFunction() const { return m_parseIntFunction.get(); } - JSFunction* evalFunction() const { return m_evalFunction.get(); } JSFunction* callFunction() const { return m_callFunction.get(); } JSFunction* applyFunction() const { return m_applyFunction.get(); } - JSFunction* definePropertyFunction() const { return m_definePropertyFunction.get(); } - JSFunction* arrayProtoValuesFunction() const { return m_arrayProtoValuesFunction.get(); } - JSFunction* initializePromiseFunction() const { return m_initializePromiseFunction.get(); } - JSFunction* newPromiseDeferredFunction() const { return m_newPromiseDeferredFunction.get(); } GetterSetter* throwTypeErrorGetterSetter(VM& vm) { if (!m_throwTypeErrorGetterSetter) @@ -412,21 +353,17 @@ public: ArrayPrototype* arrayPrototype() const { return m_arrayPrototype.get(); } BooleanPrototype* booleanPrototype() const { return m_booleanPrototype.get(); } StringPrototype* stringPrototype() const { return m_stringPrototype.get(); } - SymbolPrototype* symbolPrototype() const { return m_symbolPrototype.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(); } - IteratorPrototype* iteratorPrototype() const { return m_iteratorPrototype.get(); } JSPromisePrototype* promisePrototype() const { return m_promisePrototype.get(); } - Structure* debuggerScopeStructure() const { return m_debuggerScopeStructure.get(); } Structure* withScopeStructure() const { return m_withScopeStructure.get(); } Structure* strictEvalActivationStructure() const { return m_strictEvalActivationStructure.get(); } - Structure* activationStructure() const { return m_lexicalEnvironmentStructure.get(); } - Structure* directArgumentsStructure() const { return m_directArgumentsStructure.get(); } - Structure* scopedArgumentsStructure() const { return m_scopedArgumentsStructure.get(); } - Structure* outOfBandArgumentsStructure() const { return m_outOfBandArgumentsStructure.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); @@ -451,7 +388,6 @@ public: Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); } Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); } Structure* callbackObjectStructure() const { return m_callbackObjectStructure.get(); } - Structure* propertyNameIteratorStructure() const { return m_propertyNameIteratorStructure.get(); } #if JSC_OBJC_API_ENABLED Structure* objcCallbackFunctionStructure() const { return m_objcCallbackFunctionStructure.get(); } Structure* objcWrapperObjectStructure() const { return m_objcWrapperObjectStructure.get(); } @@ -459,7 +395,6 @@ public: Structure* dateStructure() const { return m_dateStructure.get(); } Structure* nullPrototypeObjectStructure() const { return m_nullPrototypeObjectStructure.get(); } Structure* errorStructure() const { return m_errorStructure.get(); } - Structure* calleeStructure() const { return m_calleeStructure.get(); } Structure* functionStructure() const { return m_functionStructure.get(); } Structure* boundFunctionStructure() const { return m_boundFunctionStructure.get(); } Structure* namedFunctionStructure() const { return m_namedFunctionStructure.get(); } @@ -468,34 +403,20 @@ public: Structure* privateNameStructure() const { return m_privateNameStructure.get(); } Structure* internalFunctionStructure() const { return m_internalFunctionStructure.get(); } Structure* mapStructure() const { return m_mapStructure.get(); } + Structure* regExpMatchesArrayStructure() const { return m_regExpMatchesArrayStructure.get(); } Structure* regExpStructure() const { return m_regExpStructure.get(); } Structure* setStructure() const { return m_setStructure.get(); } Structure* stringObjectStructure() const { return m_stringObjectStructure.get(); } - Structure* symbolObjectStructure() const { return m_symbolObjectStructure.get(); } Structure* iteratorResultStructure() const { return m_iteratorResultStructure.get(); } static ptrdiff_t iteratorResultStructureOffset() { return OBJECT_OFFSETOF(JSGlobalObject, m_iteratorResultStructure); } - Structure* regExpMatchesArrayStructure() const { return m_regExpMatchesArrayStructure.get(); } + +#if ENABLE(PROMISES) Structure* promiseStructure() const { return m_promiseStructure.get(); } -#if ENABLE(WEBASSEMBLY) - Structure* wasmModuleStructure() const { return m_wasmModuleStructure.get(); } -#endif +#endif // ENABLE(PROMISES) JS_EXPORT_PRIVATE void setRemoteDebuggingEnabled(bool); JS_EXPORT_PRIVATE bool remoteDebuggingEnabled() const; -#if ENABLE(WEB_REPLAY) - JS_EXPORT_PRIVATE void setInputCursor(PassRefPtr<InputCursor>); - InputCursor& inputCursor() const { return *m_inputCursor; } -#endif - -#if ENABLE(REMOTE_INSPECTOR) - Inspector::JSGlobalObjectInspectorController& inspectorController() const { return *m_inspectorController.get(); } - JSGlobalObjectDebuggable& inspectorDebuggable() { return *m_inspectorDebuggable.get(); } -#endif - - void setConsoleClient(ConsoleClient* consoleClient) { m_consoleClient = consoleClient; } - ConsoleClient* consoleClient() const { return m_consoleClient; } - void setName(const String&); const String& name() const { return m_name; } @@ -505,7 +426,6 @@ public: Structure* properName ## Structure() { return m_ ## properName ## Structure.get(); } FOR_EACH_SIMPLE_BUILTIN_TYPE(DEFINE_ACCESSORS_FOR_SIMPLE_TYPE) - FOR_EACH_BUILTIN_DERIVED_ITERATOR_TYPE(DEFINE_ACCESSORS_FOR_SIMPLE_TYPE) #undef DEFINE_ACCESSORS_FOR_SIMPLE_TYPE @@ -521,17 +441,11 @@ public: return typedArrayStructure(type) == structure; } - JSCell* actualPointerFor(Special::Pointer pointer) + void* actualPointerFor(Special::Pointer pointer) { ASSERT(pointer < Special::TableSize); return m_specialPointers[pointer]; } - JSCell* jsCellForLinkTimeConstant(LinkTimeConstant type) - { - unsigned index = static_cast<unsigned>(type); - ASSERT(index < LinkTimeConstantCount); - return m_linkTimeConstants[index]; - } WatchpointSet* masqueradesAsUndefinedWatchpoint() { return m_masqueradesAsUndefinedWatchpoint.get(); } WatchpointSet* havingABadTimeWatchpoint() { return m_havingABadTimeWatchpoint.get(); } @@ -569,7 +483,7 @@ public: static bool shouldInterruptScript(const JSGlobalObject*) { return true; } static bool shouldInterruptScriptBeforeTimeout(const JSGlobalObject*) { return false; } - static RuntimeFlags javaScriptRuntimeFlags(const JSGlobalObject*) { return RuntimeFlags(); } + static bool javaScriptExperimentsEnabled(const JSGlobalObject*) { return false; } void queueMicrotask(PassRefPtr<Microtask>); @@ -583,14 +497,13 @@ public: void resetPrototype(VM&, JSValue prototype); - VM& vm() const { return m_vm; } + VM& vm() const { return *Heap::heap(this)->vm(); } JSObject* globalThis() const; + JS_EXPORT_PRIVATE void setGlobalThis(VM&, JSObject* globalThis); static Structure* createStructure(VM& vm, JSValue prototype) { - Structure* result = Structure::create(vm, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), info()); - result->setTransitionWatchpointIsLikelyToBeFired(true); - return result; + return Structure::create(vm, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), info()); } void registerWeakMap(OpaqueJSWeakObjectMap* map) @@ -611,15 +524,16 @@ public: return m_rareData->opaqueJSClassData; } - TemplateRegistry& templateRegistry() { return m_templateRegistry; } - double weakRandomNumber() { return m_weakRandom.get(); } unsigned weakRandomInteger() { return m_weakRandom.getUint32(); } UnlinkedProgramCodeBlock* createProgramCodeBlock(CallFrame*, ProgramExecutable*, JSObject** exception); - UnlinkedEvalCodeBlock* createEvalCodeBlock(CallFrame*, EvalExecutable*, ThisTDZMode, const VariableEnvironment*); + UnlinkedEvalCodeBlock* createEvalCodeBlock(CallFrame*, EvalExecutable*); protected: + + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags; + struct GlobalPropertyInfo { GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a) : identifier(i) @@ -638,10 +552,10 @@ protected: private: friend class LLIntOffsetsExtractor; - - JS_EXPORT_PRIVATE void setGlobalThis(VM&, JSObject* globalThis); - - JS_EXPORT_PRIVATE void init(VM&); + + // FIXME: Fold reset into init. + JS_EXPORT_PRIVATE void init(JSObject* thisValue); + void reset(JSValue prototype); void createThrowTypeError(VM&); @@ -667,13 +581,13 @@ inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, PropertyName inline bool JSGlobalObject::symbolTableHasProperty(PropertyName propertyName) { - SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.uid()); + SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.publicName()); return !entry.isNull(); } inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, unsigned initialLength = 0) { - return ArrayAllocationProfile::updateLastAllocationFor(profile, JSArray::create(exec->vm(), initialLength >= MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH ? globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage) : globalObject->arrayStructureForProfileDuringAllocation(profile), initialLength)); + 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) @@ -711,11 +625,6 @@ inline JSArray* constructArrayNegativeIndexed(ExecState* exec, ArrayAllocationPr return constructArrayNegativeIndexed(exec, profile, exec->lexicalGlobalObject(), values, length); } -inline JSObject* ExecState::globalThisValue() const -{ - return lexicalGlobalObject()->globalThis(); -} - inline JSObject* JSScope::globalThis() { return globalObject()->globalThis(); diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectDebuggable.cpp b/Source/JavaScriptCore/runtime/JSGlobalObjectDebuggable.cpp deleted file mode 100644 index eecc5ba03..000000000 --- a/Source/JavaScriptCore/runtime/JSGlobalObjectDebuggable.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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 "JSGlobalObjectDebuggable.h" - -#if ENABLE(REMOTE_INSPECTOR) - -#include "InspectorAgentBase.h" -#include "InspectorFrontendChannel.h" -#include "JSGlobalObject.h" -#include "JSLock.h" -#include "RemoteInspector.h" - -using namespace Inspector; - -namespace JSC { - -JSGlobalObjectDebuggable::JSGlobalObjectDebuggable(JSGlobalObject& globalObject) - : m_globalObject(globalObject) -{ -} - -String JSGlobalObjectDebuggable::name() const -{ - String name = m_globalObject.name(); - return name.isEmpty() ? ASCIILiteral("JSContext") : name; -} - -void JSGlobalObjectDebuggable::connect(FrontendChannel* frontendChannel, bool automaticInspection) -{ - JSLockHolder locker(&m_globalObject.vm()); - - m_globalObject.inspectorController().connectFrontend(frontendChannel, automaticInspection); -} - -void JSGlobalObjectDebuggable::disconnect() -{ - JSLockHolder locker(&m_globalObject.vm()); - - m_globalObject.inspectorController().disconnectFrontend(DisconnectReason::InspectorDestroyed); -} - -void JSGlobalObjectDebuggable::pause() -{ - JSLockHolder locker(&m_globalObject.vm()); - - m_globalObject.inspectorController().pause(); -} - -void JSGlobalObjectDebuggable::dispatchMessageFromRemoteFrontend(const String& message) -{ - JSLockHolder locker(&m_globalObject.vm()); - - m_globalObject.inspectorController().dispatchMessageFromFrontend(message); -} - -void JSGlobalObjectDebuggable::pauseWaitingForAutomaticInspection() -{ - JSC::JSLock::DropAllLocks dropAllLocks(&m_globalObject.vm()); - RemoteInspectorDebuggable::pauseWaitingForAutomaticInspection(); -} - -} // namespace JSC - -#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectDebuggable.h b/Source/JavaScriptCore/runtime/JSGlobalObjectDebuggable.h deleted file mode 100644 index 60ce58a44..000000000 --- a/Source/JavaScriptCore/runtime/JSGlobalObjectDebuggable.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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 JSGlobalObjectDebuggable_h -#define JSGlobalObjectDebuggable_h - -#if ENABLE(REMOTE_INSPECTOR) - -#include "JSGlobalObjectInspectorController.h" -#include "RemoteInspectorDebuggable.h" -#include <wtf/Noncopyable.h> - -namespace Inspector { -class FrontendChannel; -enum class DisconnectReason; -} - -namespace JSC { - -class JSGlobalObject; - -class JSGlobalObjectDebuggable final : public Inspector::RemoteInspectorDebuggable { - WTF_MAKE_FAST_ALLOCATED; - WTF_MAKE_NONCOPYABLE(JSGlobalObjectDebuggable); -public: - JSGlobalObjectDebuggable(JSGlobalObject&); - ~JSGlobalObjectDebuggable() { } - - virtual Inspector::RemoteInspectorDebuggable::DebuggableType type() const override { return Inspector::RemoteInspectorDebuggable::JavaScript; } - - virtual String name() const override; - virtual bool hasLocalDebugger() const override { return false; } - - virtual void connect(Inspector::FrontendChannel*, bool automaticInspection) override; - virtual void disconnect() override; - virtual void dispatchMessageFromRemoteFrontend(const String& message) override; - virtual void pause() override; - - virtual bool automaticInspectionAllowed() const override { return true; } - virtual void pauseWaitingForAutomaticInspection() override; - -private: - JSGlobalObject& m_globalObject; -}; - -} // namespace JSC - -#endif // ENABLE(REMOTE_INSPECTOR) - -#endif // !defined(JSGlobalObjectDebuggable_h) diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp index b7ee1251b..faecd7e85 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp @@ -26,6 +26,7 @@ #include "JSGlobalObjectFunctions.h" #include "CallFrame.h" +#include "CallFrameInlines.h" #include "Interpreter.h" #include "JSFunction.h" #include "JSGlobalObject.h" @@ -34,7 +35,7 @@ #include "Lexer.h" #include "LiteralParser.h" #include "Nodes.h" -#include "JSCInlines.h" +#include "Operations.h" #include "Parser.h" #include "StackVisitor.h" #include <wtf/dtoa.h> @@ -42,7 +43,6 @@ #include <stdlib.h> #include <wtf/ASCIICType.h> #include <wtf/Assertions.h> -#include <wtf/HexNumber.h> #include <wtf/MathExtras.h> #include <wtf/StringExtras.h> #include <wtf/text/StringBuilder.h> @@ -53,18 +53,9 @@ using namespace Unicode; namespace JSC { -template<unsigned charactersCount> -static Bitmap<256> makeCharacterBitmap(const char (&characters)[charactersCount]) +static JSValue encode(ExecState* exec, const char* doNotEscape) { - Bitmap<256> bitmap; - for (unsigned i = 0; i < charactersCount; ++i) - bitmap.set(characters[i]); - return bitmap; -} - -static JSValue encode(ExecState* exec, const Bitmap<256>& doNotEscape) -{ - CString cstr = exec->argument(0).toString(exec)->view(exec).get().utf8(StrictConversion); + CString cstr = exec->argument(0).toString(exec)->value(exec).utf8(StrictConversion); if (!cstr.data()) return exec->vm().throwException(exec, createURIError(exec, ASCIILiteral("String contained an illegal UTF-16 sequence."))); @@ -72,11 +63,12 @@ static JSValue encode(ExecState* exec, const Bitmap<256>& doNotEscape) const char* p = cstr.data(); for (size_t k = 0; k < cstr.length(); k++, p++) { char c = *p; - if (c && doNotEscape.get(static_cast<LChar>(c))) - builder.append(static_cast<LChar>(c)); + if (c && strchr(doNotEscape, c)) + builder.append(c); else { - builder.append(static_cast<LChar>('%')); - appendByteAsHex(c, builder); + char tmp[4]; + snprintf(tmp, sizeof(tmp), "%%%02X", static_cast<unsigned char>(c)); + builder.append(tmp); } } return builder.build(exec); @@ -84,7 +76,7 @@ static JSValue encode(ExecState* exec, const Bitmap<256>& doNotEscape) template <typename CharType> ALWAYS_INLINE -static JSValue decode(ExecState* exec, const CharType* characters, int length, const Bitmap<256>& doNotUnescape, bool strict) +static JSValue decode(ExecState* exec, const CharType* characters, int length, const char* doNotUnescape, bool strict) { JSStringBuilder builder; int k = 0; @@ -136,8 +128,11 @@ static JSValue decode(ExecState* exec, const CharType* characters, int length, c u = Lexer<UChar>::convertUnicode(p[2], p[3], p[4], p[5]); } } - if (charLen && (u == 0 || u >= 128 || !doNotUnescape.get(static_cast<LChar>(u)))) { - builder.append(u); + if (charLen && (u == 0 || u >= 128 || !strchr(doNotUnescape, u))) { + if (u < 256) + builder.append(static_cast<LChar>(u)); + else + builder.append(u); k += charLen; continue; } @@ -148,9 +143,10 @@ static JSValue decode(ExecState* exec, const CharType* characters, int length, c return builder.build(exec); } -static JSValue decode(ExecState* exec, const Bitmap<256>& doNotUnescape, bool strict) +static JSValue decode(ExecState* exec, const char* doNotUnescape, bool strict) { - StringView str = exec->argument(0).toString(exec)->view(exec); + JSStringBuilder builder; + String str = exec->argument(0).toString(exec)->value(exec); if (str.is8Bit()) return decode(exec, str.characters8(), str.length(), doNotUnescape, strict); @@ -194,7 +190,7 @@ static int parseDigit(unsigned short c, int radix) return digit; } -double parseIntOverflow(const LChar* s, unsigned length, int radix) +double parseIntOverflow(const LChar* s, int length, int radix) { double number = 0.0; double radixMultiplier = 1.0; @@ -216,7 +212,7 @@ double parseIntOverflow(const LChar* s, unsigned length, int radix) return number; } -static double parseIntOverflow(const UChar* s, unsigned length, int radix) +double parseIntOverflow(const UChar* s, int length, int radix) { double number = 0.0; double radixMultiplier = 1.0; @@ -238,17 +234,10 @@ static double parseIntOverflow(const UChar* s, unsigned length, int radix) return number; } -static double parseIntOverflow(StringView string, int radix) -{ - if (string.is8Bit()) - return parseIntOverflow(string.characters8(), string.length(), radix); - return parseIntOverflow(string.characters16(), string.length(), radix); -} - // ES5.1 15.1.2.2 template <typename CharType> ALWAYS_INLINE -static double parseInt(StringView s, const CharType* data, int radix) +static double parseInt(const String& s, const CharType* data, int radix) { // 1. Let inputString be ToString(string). // 2. Let S be a newly created substring of inputString consisting of the first character that is not a @@ -291,7 +280,7 @@ static double parseInt(StringView s, const CharType* data, int radix) // 8.a If R < 2 or R > 36, then return NaN. if (radix < 2 || radix > 36) - return PNaN; + return QNaN; // 13. Let mathInt be the mathematical integer value that is represented by Z in radix-R notation, using the letters // A-Z and a-z for digits with values 10 through 35. (However, if R is 10 and Z contains more than 20 significant @@ -314,22 +303,22 @@ static double parseInt(StringView s, const CharType* data, int radix) // 12. If Z is empty, return NaN. if (!sawDigit) - return PNaN; + return QNaN; // Alternate code path for certain large numbers. if (number >= mantissaOverflowLowerBound) { if (radix == 10) { size_t parsedLength; - number = parseDouble(s.substring(firstDigitPosition, p - firstDigitPosition), parsedLength); + number = parseDouble(s.deprecatedCharacters() + firstDigitPosition, p - firstDigitPosition, parsedLength); } else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32) - number = parseIntOverflow(s.substring(firstDigitPosition, p - firstDigitPosition), radix); + number = parseIntOverflow(s.substringSharingImpl(firstDigitPosition, p - firstDigitPosition).utf8().data(), p - firstDigitPosition, radix); } // 15. Return sign x number. return sign * number; } -static double parseInt(StringView s, int radix) +static double parseInt(const String& s, int radix) { if (s.is8Bit()) return parseInt(s, s.characters8(), radix); @@ -352,51 +341,7 @@ static bool isInfinity(const CharType* data, const CharType* end) && data[7] == 'y'; } -// See ecma-262 6th 11.8.3 -template <typename CharType> -static double jsBinaryIntegerLiteral(const CharType*& data, const CharType* end) -{ - // Binary number. - data += 2; - const CharType* firstDigitPosition = data; - double number = 0; - while (true) { - number = number * 2 + (*data - '0'); - ++data; - if (data == end) - break; - if (!isASCIIBinaryDigit(*data)) - break; - } - if (number >= mantissaOverflowLowerBound) - number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 2); - - return number; -} - -// See ecma-262 6th 11.8.3 -template <typename CharType> -static double jsOctalIntegerLiteral(const CharType*& data, const CharType* end) -{ - // Octal number. - data += 2; - const CharType* firstDigitPosition = data; - double number = 0; - while (true) { - number = number * 8 + (*data - '0'); - ++data; - if (data == end) - break; - if (!isASCIIOctalDigit(*data)) - break; - } - if (number >= mantissaOverflowLowerBound) - number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 8); - - return number; -} - -// See ecma-262 6th 11.8.3 +// See ecma-262 9.3.1 template <typename CharType> static double jsHexIntegerLiteral(const CharType*& data, const CharType* end) { @@ -418,7 +363,7 @@ static double jsHexIntegerLiteral(const CharType*& data, const CharType* end) return number; } -// See ecma-262 6th 11.8.3 +// See ecma-262 9.3.1 template <typename CharType> static double jsStrDecimalLiteral(const CharType*& data, const CharType* end) { @@ -456,7 +401,7 @@ static double jsStrDecimalLiteral(const CharType*& data, const CharType* end) } // Not a number. - return PNaN; + return QNaN; } template <typename CharType> @@ -475,16 +420,9 @@ static double toDouble(const CharType* characters, unsigned size) return 0.0; double number; - if (characters[0] == '0' && characters + 2 < endCharacters) { - if ((characters[1] | 0x20) == 'x' && isASCIIHexDigit(characters[2])) - number = jsHexIntegerLiteral(characters, endCharacters); - else if ((characters[1] | 0x20) == 'o' && isASCIIOctalDigit(characters[2])) - number = jsOctalIntegerLiteral(characters, endCharacters); - else if ((characters[1] | 0x20) == 'b' && isASCIIBinaryDigit(characters[2])) - number = jsBinaryIntegerLiteral(characters, endCharacters); - else - number = jsStrDecimalLiteral(characters, endCharacters); - } else + if (characters[0] == '0' && characters + 2 < endCharacters && (characters[1] | 0x20) == 'x' && isASCIIHexDigit(characters[2])) + number = jsHexIntegerLiteral(characters, endCharacters); + else number = jsStrDecimalLiteral(characters, endCharacters); // Allow trailing white space. @@ -493,13 +431,13 @@ static double toDouble(const CharType* characters, unsigned size) break; } if (characters != endCharacters) - return PNaN; + return QNaN; return number; } -// See ecma-262 6th 11.8.3 -double jsToNumber(StringView s) +// See ecma-262 9.3.1 +double jsToNumber(const String& s) { unsigned size = s.length(); @@ -509,7 +447,7 @@ double jsToNumber(StringView s) return c - '0'; if (isStrWhiteSpace(c)) return 0; - return PNaN; + return QNaN; } if (s.is8Bit()) @@ -517,7 +455,7 @@ double jsToNumber(StringView s) return toDouble(s.characters16(), size); } -static double parseFloat(StringView s) +static double parseFloat(const String& s) { unsigned size = s.length(); @@ -525,7 +463,7 @@ static double parseFloat(StringView s) UChar c = s[0]; if (isASCIIDigit(c)) return c - '0'; - return PNaN; + return QNaN; } if (s.is8Bit()) { @@ -540,7 +478,7 @@ static double parseFloat(StringView s) // Empty string. if (data == end) - return PNaN; + return QNaN; return jsStrDecimalLiteral(data, end); } @@ -556,7 +494,7 @@ static double parseFloat(StringView s) // Empty string. if (data == end) - return PNaN; + return QNaN; return jsStrDecimalLiteral(data, end); } @@ -580,8 +518,7 @@ EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec) } JSGlobalObject* calleeGlobalObject = exec->callee()->globalObject(); - VariableEnvironment emptyTDZVariables; // Indirect eval does not have access to the lexical scope. - EvalExecutable* eval = EvalExecutable::create(exec, makeSource(s), false, ThisTDZMode::CheckIfNeeded, &emptyTDZVariables); + EvalExecutable* eval = EvalExecutable::create(exec, makeSource(s), false); if (!eval) return JSValue::encode(jsUndefined()); @@ -611,7 +548,7 @@ EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec) } // If ToString throws, we shouldn't call ToInt32. - StringView s = value.toString(exec)->view(exec); + String s = value.toString(exec)->value(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); @@ -620,7 +557,7 @@ EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec) EncodedJSValue JSC_HOST_CALL globalFuncParseFloat(ExecState* exec) { - return JSValue::encode(jsNumber(parseFloat(exec->argument(0).toString(exec)->view(exec)))); + return JSValue::encode(jsNumber(parseFloat(exec->argument(0).toString(exec)->value(exec)))); } EncodedJSValue JSC_HOST_CALL globalFuncIsNaN(ExecState* exec) @@ -636,63 +573,59 @@ EncodedJSValue JSC_HOST_CALL globalFuncIsFinite(ExecState* exec) EncodedJSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState* exec) { - static Bitmap<256> doNotUnescapeWhenDecodingURI = makeCharacterBitmap( - "#$&+,/:;=?@" - ); + static const char do_not_unescape_when_decoding_URI[] = + "#$&+,/:;=?@"; - return JSValue::encode(decode(exec, doNotUnescapeWhenDecodingURI, true)); + return JSValue::encode(decode(exec, do_not_unescape_when_decoding_URI, true)); } EncodedJSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState* exec) { - static Bitmap<256> emptyBitmap; - return JSValue::encode(decode(exec, emptyBitmap, true)); + return JSValue::encode(decode(exec, "", true)); } EncodedJSValue JSC_HOST_CALL globalFuncEncodeURI(ExecState* exec) { - static Bitmap<256> doNotEscapeWhenEncodingURI = makeCharacterBitmap( + static const char do_not_escape_when_encoding_URI[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789" - "!#$&'()*+,-./:;=?@_~" - ); + "!#$&'()*+,-./:;=?@_~"; - return JSValue::encode(encode(exec, doNotEscapeWhenEncodingURI)); + return JSValue::encode(encode(exec, do_not_escape_when_encoding_URI)); } EncodedJSValue JSC_HOST_CALL globalFuncEncodeURIComponent(ExecState* exec) { - static Bitmap<256> doNotEscapeWhenEncodingURIComponent = makeCharacterBitmap( + static const char do_not_escape_when_encoding_URI_component[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789" - "!'()*-._~" - ); + "!'()*-._~"; - return JSValue::encode(encode(exec, doNotEscapeWhenEncodingURIComponent)); + return JSValue::encode(encode(exec, do_not_escape_when_encoding_URI_component)); } EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec) { - static Bitmap<256> doNotEscape = makeCharacterBitmap( + static const char do_not_escape[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789" - "*+-./@_" - ); + "*+-./@_"; JSStringBuilder builder; - StringView str = exec->argument(0).toString(exec)->view(exec); + String str = exec->argument(0).toString(exec)->value(exec); if (str.is8Bit()) { const LChar* c = str.characters8(); for (unsigned k = 0; k < str.length(); k++, c++) { int u = c[0]; - if (u && doNotEscape.get(static_cast<LChar>(u))) - builder.append(*c); + if (u && strchr(do_not_escape, static_cast<char>(u))) + builder.append(c, 1); else { - builder.append(static_cast<LChar>('%')); - appendByteAsHex(static_cast<LChar>(u), builder); + char tmp[4]; + snprintf(tmp, sizeof(tmp), "%%%02X", u); + builder.append(tmp); } } @@ -703,15 +636,15 @@ EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec) for (unsigned k = 0; k < str.length(); k++, c++) { int u = c[0]; if (u > 255) { - builder.append(static_cast<LChar>('%')); - builder.append(static_cast<LChar>('u')); - appendByteAsHex(u >> 8, builder); - appendByteAsHex(u & 0xFF, builder); - } else if (u != 0 && doNotEscape.get(static_cast<LChar>(u))) - builder.append(*c); + char tmp[7]; + snprintf(tmp, sizeof(tmp), "%%u%04X", u); + builder.append(tmp); + } else if (u != 0 && strchr(do_not_escape, static_cast<char>(u))) + builder.append(c, 1); else { - builder.append(static_cast<LChar>('%')); - appendByteAsHex(u, builder); + char tmp[4]; + snprintf(tmp, sizeof(tmp), "%%%02X", u); + builder.append(tmp); } } @@ -721,7 +654,7 @@ EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec) EncodedJSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec) { StringBuilder builder; - StringView str = exec->argument(0).toString(exec)->view(exec); + String str = exec->argument(0).toString(exec)->value(exec); int k = 0; int len = str.length(); @@ -806,9 +739,6 @@ private: EncodedJSValue JSC_HOST_CALL globalFuncProtoGetter(ExecState* exec) { - if (exec->thisValue().isUndefinedOrNull()) - return throwVMError(exec, createTypeError(exec, "Can't convert undefined or null to object")); - JSObject* thisObject = jsDynamicCast<JSObject*>(exec->thisValue().toThis(exec, NotStrictMode)); if (!thisObject) @@ -847,18 +777,8 @@ private: JSObject* m_thisObject; }; -bool checkProtoSetterAccessAllowed(ExecState* exec, JSObject* object) -{ - GlobalFuncProtoSetterFunctor functor(object); - exec->iterate(functor); - return functor.allowsAccess(); -} - EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState* exec) { - if (exec->thisValue().isUndefinedOrNull()) - return throwVMError(exec, createTypeError(exec, "Can't convert undefined or null to object")); - JSValue value = exec->argument(0); JSObject* thisObject = jsDynamicCast<JSObject*>(exec->thisValue().toThis(exec, NotStrictMode)); @@ -867,27 +787,20 @@ EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState* exec) if (!thisObject) return JSValue::encode(jsUndefined()); - if (!checkProtoSetterAccessAllowed(exec, thisObject)) + GlobalFuncProtoSetterFunctor functor(thisObject); + exec->iterate(functor); + if (!functor.allowsAccess()) return JSValue::encode(jsUndefined()); // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla. if (!value.isObject() && !value.isNull()) return JSValue::encode(jsUndefined()); - if (thisObject->prototype() == value) - return JSValue::encode(jsUndefined()); - if (!thisObject->isExtensible()) return throwVMError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError)); if (!thisObject->setPrototypeWithCycleCheck(exec, value)) - exec->vm().throwException(exec, createError(exec, ASCIILiteral("cyclic __proto__ value"))); - return JSValue::encode(jsUndefined()); -} - -EncodedJSValue JSC_HOST_CALL globalFuncBuiltinLog(ExecState* exec) -{ - dataLog(exec->argument(0).toWTFString(exec), "\n"); + exec->vm().throwException(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 b929f5143..f4512e405 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h +++ b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h @@ -25,8 +25,7 @@ #define JSGlobalObjectFunctions_h #include "JSCJSValue.h" -#include <unicode/uchar.h> -#include <wtf/text/LChar.h> +#include <wtf/unicode/Unicode.h> namespace JSC { @@ -51,14 +50,13 @@ EncodedJSValue JSC_HOST_CALL globalFuncUnescape(ExecState*); EncodedJSValue JSC_HOST_CALL globalFuncThrowTypeError(ExecState*); EncodedJSValue JSC_HOST_CALL globalFuncProtoGetter(ExecState*); EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState*); -EncodedJSValue JSC_HOST_CALL globalFuncBuiltinLog(ExecState*); - -bool checkProtoSetterAccessAllowed(ExecState*, JSObject*); static const double mantissaOverflowLowerBound = 9007199254740992.0; -double parseIntOverflow(const LChar*, unsigned length, int radix); +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(StringView); +double jsToNumber(const WTF::String&); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSJob.cpp b/Source/JavaScriptCore/runtime/JSJob.cpp deleted file mode 100644 index 92d2122ba..000000000 --- a/Source/JavaScriptCore/runtime/JSJob.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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 "JSJob.h" - -#include "Error.h" -#include "Exception.h" -#include "JSCJSValueInlines.h" -#include "JSCellInlines.h" -#include "JSGlobalObject.h" -#include "Microtask.h" -#include "SlotVisitorInlines.h" -#include "StrongInlines.h" - -namespace JSC { - -class JSJobMicrotask final : public Microtask { -public: - JSJobMicrotask(VM& vm, JSValue job, JSArray* arguments) - { - m_job.set(vm, job); - m_arguments.set(vm, arguments); - } - - virtual ~JSJobMicrotask() - { - } - -private: - virtual void run(ExecState*) override; - - Strong<Unknown> m_job; - Strong<JSArray> m_arguments; -}; - -Ref<Microtask> createJSJob(VM& vm, JSValue job, JSArray* arguments) -{ - return adoptRef(*new JSJobMicrotask(vm, job, arguments)); -} - -void JSJobMicrotask::run(ExecState* exec) -{ - CallData handlerCallData; - CallType handlerCallType = getCallData(m_job.get(), handlerCallData); - ASSERT(handlerCallType != CallTypeNone); - - MarkedArgumentBuffer handlerArguments; - for (unsigned index = 0, length = m_arguments->length(); index < length; ++index) - handlerArguments.append(m_arguments->JSArray::get(exec, index)); - call(exec, m_job.get(), handlerCallType, handlerCallData, jsUndefined(), handlerArguments); -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSLexicalEnvironment.cpp b/Source/JavaScriptCore/runtime/JSLexicalEnvironment.cpp deleted file mode 100644 index 47a81b5f3..000000000 --- a/Source/JavaScriptCore/runtime/JSLexicalEnvironment.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (C) 2008, 2009, 2014, 2015 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 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 "JSLexicalEnvironment.h" - -#include "Interpreter.h" -#include "JSFunction.h" -#include "JSCInlines.h" - -using namespace std; - -namespace JSC { - -const ClassInfo JSLexicalEnvironment::s_info = { "JSLexicalEnvironment", &Base::s_info, 0, CREATE_METHOD_TABLE(JSLexicalEnvironment) }; - -inline bool JSLexicalEnvironment::symbolTableGet(PropertyName propertyName, PropertySlot& slot) -{ - SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.uid()); - if (entry.isNull()) - return false; - - ScopeOffset offset = entry.scopeOffset(); - - // Defend against the inspector asking for a var after it has been optimized out. - if (!isValid(offset)) - return false; - - JSValue result = variableAt(offset).get(); - slot.setValue(this, DontEnum, result); - return true; -} - -inline bool JSLexicalEnvironment::symbolTablePut(ExecState* exec, PropertyName propertyName, JSValue value, bool shouldThrow) -{ - VM& vm = exec->vm(); - ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); - - WriteBarrierBase<Unknown>* reg; - WatchpointSet* set; - { - GCSafeConcurrentJITLocker locker(symbolTable()->m_lock, exec->vm().heap); - SymbolTable::Map::iterator iter = symbolTable()->find(locker, propertyName.uid()); - if (iter == symbolTable()->end(locker)) - return false; - ASSERT(!iter->value.isNull()); - if (iter->value.isReadOnly()) { - if (shouldThrow || isLexicalScope()) - throwTypeError(exec, StrictModeReadonlyPropertyWriteError); - return true; - } - ScopeOffset offset = iter->value.scopeOffset(); - // Defend against the inspector asking for a var after it has been optimized out. - if (!isValid(offset)) - return false; - set = iter->value.watchpointSet(); - reg = &variableAt(offset); - } - reg->set(vm, this, value); - if (set) - set->invalidate(VariableWriteFireDetail(this, propertyName)); // Don't mess around - if we had found this statically, we would have invalidated it. - return true; -} - -void JSLexicalEnvironment::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) -{ - JSLexicalEnvironment* thisObject = jsCast<JSLexicalEnvironment*>(object); - - { - ConcurrentJITLocker locker(thisObject->symbolTable()->m_lock); - SymbolTable::Map::iterator end = thisObject->symbolTable()->end(locker); - for (SymbolTable::Map::iterator it = thisObject->symbolTable()->begin(locker); it != end; ++it) { - if (it->value.getAttributes() & DontEnum && !mode.includeDontEnumProperties()) - continue; - if (!thisObject->isValid(it->value.scopeOffset())) - continue; - if (it->key->isSymbol() && !propertyNames.includeSymbolProperties()) - continue; - propertyNames.add(Identifier::fromUid(exec, it->key.get())); - } - } - // Skip the JSEnvironmentRecord implementation of getOwnNonIndexPropertyNames - JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode); -} - -inline bool JSLexicalEnvironment::symbolTablePutWithAttributes(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes) -{ - ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); - - WriteBarrierBase<Unknown>* reg; - { - ConcurrentJITLocker locker(symbolTable()->m_lock); - SymbolTable::Map::iterator iter = symbolTable()->find(locker, propertyName.uid()); - if (iter == symbolTable()->end(locker)) - return false; - SymbolTableEntry& entry = iter->value; - ASSERT(!entry.isNull()); - - ScopeOffset offset = entry.scopeOffset(); - if (!isValid(offset)) - return false; - - entry.setAttributes(attributes); - reg = &variableAt(offset); - } - reg->set(vm, this, value); - return true; -} - -bool JSLexicalEnvironment::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) -{ - JSLexicalEnvironment* thisObject = jsCast<JSLexicalEnvironment*>(object); - - if (thisObject->symbolTableGet(propertyName, slot)) - return true; - - unsigned attributes; - if (JSValue value = thisObject->getDirect(exec->vm(), propertyName, attributes)) { - slot.setValue(thisObject, attributes, value); - return true; - } - - // We don't call through to JSObject because there's no way to give a - // lexical environment object getter properties or a prototype. - ASSERT(!thisObject->hasGetterSetterProperties()); - ASSERT(thisObject->prototype().isNull()); - return false; -} - -void JSLexicalEnvironment::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) -{ - JSLexicalEnvironment* thisObject = jsCast<JSLexicalEnvironment*>(cell); - ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); - - if (thisObject->symbolTablePut(exec, propertyName, value, slot.isStrictMode())) - return; - - // We don't call through to JSObject because __proto__ and getter/setter - // properties are non-standard extensions that other implementations do not - // expose in the lexicalEnvironment object. - ASSERT(!thisObject->hasGetterSetterProperties()); - thisObject->putOwnDataProperty(exec->vm(), propertyName, value, slot); -} - -bool JSLexicalEnvironment::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) -{ - if (propertyName == exec->propertyNames().arguments) - return false; - - return Base::deleteProperty(cell, exec, propertyName); -} - -JSValue JSLexicalEnvironment::toThis(JSCell*, ExecState* exec, ECMAMode ecmaMode) -{ - if (ecmaMode == StrictMode) - return jsUndefined(); - return exec->globalThisValue(); -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSLexicalEnvironment.h b/Source/JavaScriptCore/runtime/JSLexicalEnvironment.h deleted file mode 100644 index 9516318d7..000000000 --- a/Source/JavaScriptCore/runtime/JSLexicalEnvironment.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2008, 2009, 2013-2015 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 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 JSLexicalEnvironment_h -#define JSLexicalEnvironment_h - -#include "CodeBlock.h" -#include "CopiedSpaceInlines.h" -#include "JSEnvironmentRecord.h" -#include "SymbolTable.h" - -namespace JSC { - -class Register; - -class JSLexicalEnvironment : public JSEnvironmentRecord { -private: - JSLexicalEnvironment(VM&, Structure*, JSScope*, SymbolTable*); - -public: - typedef JSEnvironmentRecord Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames; - - static JSLexicalEnvironment* create( - VM& vm, Structure* structure, JSScope* currentScope, SymbolTable* symbolTable, JSValue initialValue) - { - JSLexicalEnvironment* result = - new ( - NotNull, - allocateCell<JSLexicalEnvironment>(vm.heap, allocationSize(symbolTable))) - JSLexicalEnvironment(vm, structure, currentScope, symbolTable); - result->finishCreation(vm, initialValue); - return result; - } - - static JSLexicalEnvironment* create(VM& vm, JSGlobalObject* globalObject, JSScope* currentScope, SymbolTable* symbolTable, JSValue initialValue) - { - Structure* structure = globalObject->activationStructure(); - return create(vm, structure, currentScope, symbolTable, initialValue); - } - - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); - static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - - static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); - - static bool deleteProperty(JSCell*, ExecState*, PropertyName); - - static JSValue toThis(JSCell*, ExecState*, ECMAMode); - - DECLARE_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject) { return Structure::create(vm, globalObject, jsNull(), TypeInfo(ActivationObjectType, StructureFlags), info()); } - -private: - bool symbolTableGet(PropertyName, PropertySlot&); - bool symbolTablePut(ExecState*, PropertyName, JSValue, bool shouldThrow); - bool symbolTablePutWithAttributes(VM&, PropertyName, JSValue, unsigned attributes); -}; - -inline JSLexicalEnvironment::JSLexicalEnvironment(VM& vm, Structure* structure, JSScope* currentScope, SymbolTable* symbolTable) - : Base(vm, structure, currentScope, symbolTable) -{ -} - -inline JSLexicalEnvironment* asActivation(JSValue value) -{ - ASSERT(asObject(value)->inherits(JSLexicalEnvironment::info())); - return jsCast<JSLexicalEnvironment*>(asObject(value)); -} - -ALWAYS_INLINE JSLexicalEnvironment* Register::lexicalEnvironment() const -{ - return asActivation(jsValue()); -} - -} // namespace JSC - -#endif // JSLexicalEnvironment_h diff --git a/Source/JavaScriptCore/runtime/JSLock.cpp b/Source/JavaScriptCore/runtime/JSLock.cpp index 828df168c..7604075f8 100644 --- a/Source/JavaScriptCore/runtime/JSLock.cpp +++ b/Source/JavaScriptCore/runtime/JSLock.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005, 2008, 2012, 2014 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,25 +25,33 @@ #include "CallFrame.h" #include "JSGlobalObject.h" #include "JSObject.h" -#include "JSCInlines.h" -#include <thread> +#include "Operations.h" + +#if USE(PTHREADS) +#include <pthread.h> +#endif namespace JSC { -StaticLock GlobalJSLock::s_sharedInstanceMutex; +Mutex* GlobalJSLock::s_sharedInstanceLock = 0; GlobalJSLock::GlobalJSLock() { - s_sharedInstanceMutex.lock(); + s_sharedInstanceLock->lock(); } GlobalJSLock::~GlobalJSLock() { - s_sharedInstanceMutex.unlock(); + s_sharedInstanceLock->unlock(); +} + +void GlobalJSLock::initialize() +{ + s_sharedInstanceLock = new Mutex(); } JSLockHolder::JSLockHolder(ExecState* exec) - : m_vm(&exec->vm()) + : m_vm(exec ? &exec->vm() : 0) { init(); } @@ -62,24 +70,27 @@ JSLockHolder::JSLockHolder(VM& vm) void JSLockHolder::init() { - m_vm->apiLock().lock(); + if (m_vm) + m_vm->apiLock().lock(); } JSLockHolder::~JSLockHolder() { + if (!m_vm) + return; + RefPtr<JSLock> apiLock(&m_vm->apiLock()); - m_vm = nullptr; + m_vm.clear(); apiLock->unlock(); } JSLock::JSLock(VM* vm) - : m_ownerThreadID(std::thread::id()) + : m_ownerThread(0) , m_lockCount(0) , m_lockDropDepth(0) - , m_hasExclusiveThread(false) , m_vm(vm) - , m_entryAtomicStringTable(nullptr) { + m_spinLock.Init(); } JSLock::~JSLock() @@ -89,98 +100,39 @@ JSLock::~JSLock() void JSLock::willDestroyVM(VM* vm) { ASSERT_UNUSED(vm, m_vm == vm); - m_vm = nullptr; -} - -void JSLock::setExclusiveThread(std::thread::id threadId) -{ - RELEASE_ASSERT(!m_lockCount && m_ownerThreadID == std::thread::id()); - m_hasExclusiveThread = (threadId != std::thread::id()); - m_ownerThreadID = threadId; + m_vm = 0; } void JSLock::lock() { - lock(1); -} - -void JSLock::lock(intptr_t lockCount) -{ - ASSERT(lockCount > 0); - if (currentThreadIsHoldingLock()) { - m_lockCount += lockCount; - return; - } - - if (!m_hasExclusiveThread) { - m_lock.lock(); - m_ownerThreadID = std::this_thread::get_id(); + ThreadIdentifier currentThread = WTF::currentThread(); + { + SpinLockHolder holder(&m_spinLock); + if (m_ownerThread == currentThread && m_lockCount) { + m_lockCount++; + return; + } } - ASSERT(!m_lockCount); - m_lockCount = lockCount; - - didAcquireLock(); -} - -void JSLock::didAcquireLock() -{ - // FIXME: What should happen to the per-thread identifier table if we don't have a VM? - if (!m_vm) - return; - - RELEASE_ASSERT(!m_vm->stackPointerAtVMEntry()); - void* p = &p; // A proxy for the current stack pointer. - m_vm->setStackPointerAtVMEntry(p); - - WTFThreadData& threadData = wtfThreadData(); - m_vm->setLastStackTop(threadData.savedLastStackTop()); - - ASSERT(!m_entryAtomicStringTable); - m_entryAtomicStringTable = threadData.setCurrentAtomicStringTable(m_vm->atomicStringTable()); - ASSERT(m_entryAtomicStringTable); - m_vm->heap.machineThreads().addCurrentThread(); -} + m_lock.lock(); -void JSLock::unlock() -{ - unlock(1); -} - -void JSLock::unlock(intptr_t unlockCount) -{ - RELEASE_ASSERT(currentThreadIsHoldingLock()); - ASSERT(m_lockCount >= unlockCount); - - // Maintain m_lockCount while calling willReleaseLock() so that its callees know that - // they still have the lock. - if (unlockCount == m_lockCount) - willReleaseLock(); - - m_lockCount -= unlockCount; - - if (!m_lockCount) { - - if (!m_hasExclusiveThread) { - m_ownerThreadID = std::thread::id(); - m_lock.unlock(); - } + { + SpinLockHolder holder(&m_spinLock); + m_ownerThread = currentThread; + ASSERT(!m_lockCount); + m_lockCount = 1; } } -void JSLock::willReleaseLock() +void JSLock::unlock() { - if (m_vm) { - m_vm->drainMicrotasks(); + SpinLockHolder holder(&m_spinLock); + ASSERT(currentThreadIsHoldingLock()); - m_vm->heap.releaseDelayedReleasedObjects(); - m_vm->setStackPointerAtVMEntry(nullptr); - } + m_lockCount--; - if (m_entryAtomicStringTable) { - wtfThreadData().setCurrentAtomicStringTable(m_entryAtomicStringTable); - m_entryAtomicStringTable = nullptr; - } + if (!m_lockCount) + m_lock.unlock(); } void JSLock::lock(ExecState* exec) @@ -195,91 +147,180 @@ void JSLock::unlock(ExecState* exec) bool JSLock::currentThreadIsHoldingLock() { - ASSERT(!m_hasExclusiveThread || (exclusiveThread() == std::this_thread::get_id())); - if (m_hasExclusiveThread) - return !!m_lockCount; - return m_ownerThreadID == std::this_thread::get_id(); + return m_lockCount && m_ownerThread == WTF::currentThread(); } +// This is fairly nasty. We allow multiple threads to run on the same +// context, and we do not require any locking semantics in doing so - +// clients of the API may simply use the context from multiple threads +// concurently, and assume this will work. In order to make this work, +// We lock the context when a thread enters, and unlock it when it leaves. +// However we do not only unlock when the thread returns from its +// entry point (evaluate script or call function), we also unlock the +// context if the thread leaves JSC by making a call out to an external +// function through a callback. +// +// All threads using the context share the same JS stack (the JSStack). +// Whenever a thread calls into JSC it starts using the JSStack from the +// previous 'high water mark' - the maximum point the stack has ever grown to +// (returned by JSStack::end()). So if a first thread calls out to a +// callback, and a second thread enters JSC, then also exits by calling out +// to a callback, we can be left with stackframes from both threads in the +// JSStack. As such, a problem may occur should the first thread's +// callback complete first, and attempt to return to JSC. Were we to allow +// this to happen, and were its stack to grow further, then it may potentially +// write over the second thread's call frames. +// +// To avoid JS stack corruption we enforce a policy of only ever allowing two +// threads to use a JS context concurrently, and only allowing the second of +// these threads to execute until it has completed and fully returned from its +// outermost call into JSC. We enforce this policy using 'lockDropDepth'. The +// first time a thread exits it will call DropAllLocks - which will do as expected +// and drop locks allowing another thread to enter. Should another thread, or the +// same thread again, enter JSC (through evaluate script or call function), and exit +// again through a callback, then the locks will not be dropped when DropAllLocks +// is called (since lockDropDepth is non-zero). Since this thread is still holding +// the locks, only it will be able to re-enter JSC (either be returning from the +// callback, or by re-entering through another call to evaulate script or call +// function). +// +// This policy is slightly more restricive than it needs to be for correctness - +// we could validly allow futher entries into JSC from other threads, we only +// need ensure that callbacks return in the reverse chronological order of the +// order in which they were made - though implementing the less restrictive policy +// would likely increase complexity and overhead. +// + // This function returns the number of locks that were dropped. -unsigned JSLock::dropAllLocks(DropAllLocks* dropper) +unsigned JSLock::dropAllLocks(SpinLock& spinLock) { - if (m_hasExclusiveThread) { - ASSERT(exclusiveThread() == std::this_thread::get_id()); +#if PLATFORM(IOS) + ASSERT_UNUSED(spinLock, spinLock.IsHeld()); + // Check if this thread is currently holding the lock. + // FIXME: Maybe we want to require this, guard with an ASSERT? + unsigned lockCount = m_lockCount; + if (!lockCount || m_ownerThread != WTF::currentThread()) return 0; - } - if (!currentThreadIsHoldingLock()) + // Don't drop the locks if they've already been dropped once. + // (If the prior drop came from another thread, and it resumed first, + // it could trash our register file). + if (m_lockDropDepth) return 0; + // m_lockDropDepth is only incremented if any locks were dropped. ++m_lockDropDepth; + m_lockCount = 0; + m_lock.unlock(); + return lockCount; +#else + if (m_lockDropDepth++) + return 0; - dropper->setDropDepth(m_lockDropDepth); - - WTFThreadData& threadData = wtfThreadData(); - threadData.setSavedStackPointerAtVMEntry(m_vm->stackPointerAtVMEntry()); - threadData.setSavedLastStackTop(m_vm->lastStackTop()); + return dropAllLocksUnconditionally(spinLock); +#endif +} - unsigned droppedLockCount = m_lockCount; - unlock(droppedLockCount); +unsigned JSLock::dropAllLocksUnconditionally(SpinLock& spinLock) +{ +#if PLATFORM(IOS) + ASSERT_UNUSED(spinLock, spinLock.IsHeld()); + // Check if this thread is currently holding the lock. + // FIXME: Maybe we want to require this, guard with an ASSERT? + unsigned lockCount = m_lockCount; + if (!lockCount || m_ownerThread != WTF::currentThread()) + return 0; - return droppedLockCount; + // m_lockDropDepth is only incremented if any locks were dropped. + ++m_lockDropDepth; + m_lockCount = 0; + m_lock.unlock(); + return lockCount; +#else + UNUSED_PARAM(spinLock); + unsigned lockCount = m_lockCount; + for (unsigned i = 0; i < lockCount; ++i) + unlock(); + + return lockCount; +#endif } -void JSLock::grabAllLocks(DropAllLocks* dropper, unsigned droppedLockCount) +void JSLock::grabAllLocks(unsigned lockCount, SpinLock& spinLock) { - ASSERT(!m_hasExclusiveThread || !droppedLockCount); - +#if PLATFORM(IOS) + ASSERT(spinLock.IsHeld()); // If no locks were dropped, nothing to do! - if (!droppedLockCount) + if (!lockCount) return; - ASSERT(!currentThreadIsHoldingLock()); - lock(droppedLockCount); - - while (dropper->dropDepth() != m_lockDropDepth) { - unlock(droppedLockCount); - std::this_thread::yield(); - lock(droppedLockCount); + ThreadIdentifier currentThread = WTF::currentThread(); + // Check if this thread is currently holding the lock. + // FIXME: Maybe we want to prohibit this, guard against with an ASSERT? + if (m_ownerThread == currentThread && m_lockCount) { + m_lockCount += lockCount; + --m_lockDropDepth; + return; } + spinLock.Unlock(); + m_lock.lock(); + spinLock.Lock(); + + m_ownerThread = currentThread; + ASSERT(!m_lockCount); + m_lockCount = lockCount; --m_lockDropDepth; +#else + UNUSED_PARAM(spinLock); + for (unsigned i = 0; i < lockCount; ++i) + lock(); - WTFThreadData& threadData = wtfThreadData(); - m_vm->setStackPointerAtVMEntry(threadData.savedStackPointerAtVMEntry()); - m_vm->setLastStackTop(threadData.savedLastStackTop()); + --m_lockDropDepth; +#endif } -JSLock::DropAllLocks::DropAllLocks(VM* vm) - : m_droppedLockCount(0) - // If the VM is in the middle of being destroyed then we don't want to resurrect it - // by allowing DropAllLocks to ref it. By this point the JSLock has already been - // released anyways, so it doesn't matter that DropAllLocks is a no-op. - , m_vm(vm->refCount() ? vm : nullptr) +JSLock::DropAllLocks::DropAllLocks(ExecState* exec, AlwaysDropLocksTag alwaysDropLocks) + : m_lockCount(0) + , m_vm(exec ? &exec->vm() : nullptr) { if (!m_vm) return; - wtfThreadData().resetCurrentAtomicStringTable(); - RELEASE_ASSERT(!m_vm->apiLock().currentThreadIsHoldingLock() || !m_vm->isCollectorBusy()); - m_droppedLockCount = m_vm->apiLock().dropAllLocks(this); -} - -JSLock::DropAllLocks::DropAllLocks(ExecState* exec) - : DropAllLocks(exec ? &exec->vm() : nullptr) -{ + SpinLock& spinLock = m_vm->apiLock().m_spinLock; +#if PLATFORM(IOS) + SpinLockHolder holder(&spinLock); +#endif + if (alwaysDropLocks) + m_lockCount = m_vm->apiLock().dropAllLocksUnconditionally(spinLock); + else + m_lockCount = m_vm->apiLock().dropAllLocks(spinLock); } -JSLock::DropAllLocks::DropAllLocks(VM& vm) - : DropAllLocks(&vm) +JSLock::DropAllLocks::DropAllLocks(VM* vm, AlwaysDropLocksTag alwaysDropLocks) + : m_lockCount(0) + , m_vm(vm) { + if (!m_vm) + return; + SpinLock& spinLock = m_vm->apiLock().m_spinLock; +#if PLATFORM(IOS) + SpinLockHolder holder(&spinLock); +#endif + if (alwaysDropLocks) + m_lockCount = m_vm->apiLock().dropAllLocksUnconditionally(spinLock); + else + m_lockCount = m_vm->apiLock().dropAllLocks(spinLock); } JSLock::DropAllLocks::~DropAllLocks() { if (!m_vm) return; - m_vm->apiLock().grabAllLocks(this, m_droppedLockCount); - wtfThreadData().setCurrentAtomicStringTable(m_vm->atomicStringTable()); + SpinLock& spinLock = m_vm->apiLock().m_spinLock; +#if PLATFORM(IOS) + SpinLockHolder holder(&spinLock); +#endif + m_vm->apiLock().grabAllLocks(m_lockCount, spinLock); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSLock.h b/Source/JavaScriptCore/runtime/JSLock.h index 4d0d17420..3002add64 100644 --- a/Source/JavaScriptCore/runtime/JSLock.h +++ b/Source/JavaScriptCore/runtime/JSLock.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005, 2008, 2009, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2005, 2008, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -21,125 +21,109 @@ #ifndef JSLock_h #define JSLock_h -#include <mutex> -#include <thread> #include <wtf/Assertions.h> -#include <wtf/Lock.h> #include <wtf/Noncopyable.h> #include <wtf/RefPtr.h> -#include <wtf/ThreadSafeRefCounted.h> -#include <wtf/WTFThreadData.h> +#include <wtf/TCSpinLock.h> +#include <wtf/Threading.h> namespace JSC { -// To make it safe to use JavaScript on multiple threads, it is -// important to lock before doing anything that allocates a -// JavaScript data structure or that interacts with shared state -// such as the protect count hash table. The simplest way to lock -// is to create a local JSLockHolder object in the scope where the lock -// must be held and pass it the context that requires protection. -// The lock is recursive so nesting is ok. The JSLock -// object also acts as a convenience short-hand for running important -// initialization routines. - -// To avoid deadlock, sometimes it is necessary to temporarily -// release the lock. Since it is recursive you actually have to -// release all locks held by your thread. This is safe to do if -// you are executing code that doesn't require the lock, and you -// reacquire the right number of locks at the end. You can do this -// by constructing a locally scoped JSLock::DropAllLocks object. The -// DropAllLocks object takes care to release the JSLock only if your -// thread acquired it to begin with. - -class ExecState; -class VM; - -// This class is used to protect the initialization of the legacy single -// shared VM. -class GlobalJSLock { - WTF_MAKE_NONCOPYABLE(GlobalJSLock); -public: - JS_EXPORT_PRIVATE GlobalJSLock(); - JS_EXPORT_PRIVATE ~GlobalJSLock(); -private: - static StaticLock s_sharedInstanceMutex; -}; - -class JSLockHolder { -public: - JS_EXPORT_PRIVATE JSLockHolder(VM*); - JS_EXPORT_PRIVATE JSLockHolder(VM&); - JS_EXPORT_PRIVATE JSLockHolder(ExecState*); - - JS_EXPORT_PRIVATE ~JSLockHolder(); -private: - void init(); - - RefPtr<VM> m_vm; -}; - -class JSLock : public ThreadSafeRefCounted<JSLock> { - WTF_MAKE_NONCOPYABLE(JSLock); -public: - JSLock(VM*); - JS_EXPORT_PRIVATE ~JSLock(); - - JS_EXPORT_PRIVATE void lock(); - JS_EXPORT_PRIVATE void unlock(); - - static void lock(ExecState*); - static void unlock(ExecState*); - static void lock(VM&); - static void unlock(VM&); - - VM* vm() { return m_vm; } - - bool hasExclusiveThread() const { return m_hasExclusiveThread; } - std::thread::id exclusiveThread() const - { - ASSERT(m_hasExclusiveThread); - return m_ownerThreadID; - } - JS_EXPORT_PRIVATE void setExclusiveThread(std::thread::id); - JS_EXPORT_PRIVATE bool currentThreadIsHoldingLock(); - - void willDestroyVM(VM*); - - class DropAllLocks { - WTF_MAKE_NONCOPYABLE(DropAllLocks); + // To make it safe to use JavaScript on multiple threads, it is + // important to lock before doing anything that allocates a + // JavaScript data structure or that interacts with shared state + // such as the protect count hash table. The simplest way to lock + // is to create a local JSLockHolder object in the scope where the lock + // must be held and pass it the context that requires protection. + // The lock is recursive so nesting is ok. The JSLock + // object also acts as a convenience short-hand for running important + // initialization routines. + + // To avoid deadlock, sometimes it is necessary to temporarily + // release the lock. Since it is recursive you actually have to + // release all locks held by your thread. This is safe to do if + // you are executing code that doesn't require the lock, and you + // reacquire the right number of locks at the end. You can do this + // by constructing a locally scoped JSLock::DropAllLocks object. The + // DropAllLocks object takes care to release the JSLock only if your + // thread acquired it to begin with. + + class ExecState; + class VM; + + // This class is used to protect the initialization of the legacy single + // shared VM. + class GlobalJSLock { + WTF_MAKE_NONCOPYABLE(GlobalJSLock); public: - JS_EXPORT_PRIVATE DropAllLocks(ExecState*); - JS_EXPORT_PRIVATE DropAllLocks(VM*); - JS_EXPORT_PRIVATE DropAllLocks(VM&); - JS_EXPORT_PRIVATE ~DropAllLocks(); - - void setDropDepth(unsigned depth) { m_dropDepth = depth; } - unsigned dropDepth() const { return m_dropDepth; } + JS_EXPORT_PRIVATE GlobalJSLock(); + JS_EXPORT_PRIVATE ~GlobalJSLock(); + static void initialize(); private: - intptr_t m_droppedLockCount; - RefPtr<VM> m_vm; - unsigned m_dropDepth; + static Mutex* s_sharedInstanceLock; }; -private: - void lock(intptr_t lockCount); - void unlock(intptr_t unlockCount); + class JSLockHolder { + public: + JS_EXPORT_PRIVATE JSLockHolder(VM*); + JS_EXPORT_PRIVATE JSLockHolder(VM&); + JS_EXPORT_PRIVATE JSLockHolder(ExecState*); + + JS_EXPORT_PRIVATE ~JSLockHolder(); + private: + void init(); - void didAcquireLock(); - void willReleaseLock(); + RefPtr<VM> m_vm; + }; - unsigned dropAllLocks(DropAllLocks*); - void grabAllLocks(DropAllLocks*, unsigned lockCount); + class JSLock : public ThreadSafeRefCounted<JSLock> { + WTF_MAKE_NONCOPYABLE(JSLock); + public: + JSLock(VM*); + JS_EXPORT_PRIVATE ~JSLock(); + + JS_EXPORT_PRIVATE void lock(); + JS_EXPORT_PRIVATE void unlock(); + + static void lock(ExecState*); + static void unlock(ExecState*); + static void lock(VM&); + static void unlock(VM&); + + VM* vm() { return m_vm; } + + JS_EXPORT_PRIVATE bool currentThreadIsHoldingLock(); + + unsigned dropAllLocks(SpinLock&); + unsigned dropAllLocksUnconditionally(SpinLock&); + void grabAllLocks(unsigned lockCount, SpinLock&); + + void willDestroyVM(VM*); + + class DropAllLocks { + WTF_MAKE_NONCOPYABLE(DropAllLocks); + public: + // By default, we release all locks conditionally. Some clients, such as Mobile Safari, + // may require that we release all locks unconditionally. + enum AlwaysDropLocksTag { DontAlwaysDropLocks = 0, AlwaysDropLocks }; + JS_EXPORT_PRIVATE DropAllLocks(ExecState*, AlwaysDropLocksTag = DontAlwaysDropLocks); + JS_EXPORT_PRIVATE DropAllLocks(VM*, AlwaysDropLocksTag = DontAlwaysDropLocks); + JS_EXPORT_PRIVATE ~DropAllLocks(); + + private: + intptr_t m_lockCount; + RefPtr<VM> m_vm; + }; - Lock m_lock; - std::thread::id m_ownerThreadID; - intptr_t m_lockCount; - unsigned m_lockDropDepth; - bool m_hasExclusiveThread; - VM* m_vm; - AtomicStringTable* m_entryAtomicStringTable; -}; + private: + SpinLock m_spinLock; + Mutex m_lock; + ThreadIdentifier m_ownerThread; + intptr_t m_lockCount; + unsigned m_lockDropDepth; + VM* m_vm; + }; } // namespace diff --git a/Source/JavaScriptCore/runtime/JSMap.cpp b/Source/JavaScriptCore/runtime/JSMap.cpp index 352648b5e..048641441 100644 --- a/Source/JavaScriptCore/runtime/JSMap.cpp +++ b/Source/JavaScriptCore/runtime/JSMap.cpp @@ -27,64 +27,25 @@ #include "JSMap.h" #include "JSCJSValueInlines.h" -#include "JSMapIterator.h" -#include "MapDataInlines.h" +#include "MapData.h" #include "SlotVisitorInlines.h" -#include "StructureInlines.h" namespace JSC { - -const ClassInfo JSMap::s_info = { "Map", &Base::s_info, 0, CREATE_METHOD_TABLE(JSMap) }; - -void JSMap::destroy(JSCell* cell) -{ - JSMap* thisObject = jsCast<JSMap*>(cell); - thisObject->JSMap::~JSMap(); -} + +const ClassInfo JSMap::s_info = { "Map", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSMap) }; void JSMap::visitChildren(JSCell* cell, SlotVisitor& visitor) { Base::visitChildren(cell, visitor); - jsCast<JSMap*>(cell)->m_mapData.visitChildren(cell, visitor); -} - -void JSMap::copyBackingStore(JSCell* cell, CopyVisitor& visitor, CopyToken token) -{ - Base::copyBackingStore(cell, visitor, token); - jsCast<JSMap*>(cell)->m_mapData.copyBackingStore(visitor, token); -} - -bool JSMap::has(ExecState* exec, JSValue key) -{ - return m_mapData.contains(exec, key); -} - -size_t JSMap::size(ExecState* exec) -{ - return m_mapData.size(exec); -} - -JSValue JSMap::get(ExecState* exec, JSValue key) -{ - JSValue result = m_mapData.get(exec, key); - if (!result) - return jsUndefined(); - return result; -} - -void JSMap::set(ExecState* exec, JSValue key, JSValue value) -{ - m_mapData.set(exec, this, key, value); + JSMap* thisObject = jsCast<JSMap*>(cell); + visitor.append(&thisObject->m_mapData); } -void JSMap::clear(ExecState*) +void JSMap::finishCreation(VM& vm) { - m_mapData.clear(); + Base::finishCreation(vm); + m_mapData.set(vm, this, MapData::create(vm)); } -bool JSMap::remove(ExecState* exec, JSValue key) -{ - return m_mapData.remove(exec, key); -} } diff --git a/Source/JavaScriptCore/runtime/JSMap.h b/Source/JavaScriptCore/runtime/JSMap.h index 837f7e369..29aa18243 100644 --- a/Source/JavaScriptCore/runtime/JSMap.h +++ b/Source/JavaScriptCore/runtime/JSMap.h @@ -26,67 +26,15 @@ #ifndef JSMap_h #define JSMap_h -#include "JSDestructibleObject.h" #include "JSObject.h" -#include "MapData.h" namespace JSC { -class JSMapIterator; +class MapData; -class JSMap : public JSDestructibleObject { +class JSMap : public JSNonFinalObject { public: - typedef JSDestructibleObject Base; - - friend class JSMapIterator; - - // Our marking functions expect Entry to maintain this layout, and have all - // fields be WriteBarrier<Unknown> - class Entry { - private: - WriteBarrier<Unknown> m_key; - WriteBarrier<Unknown> m_value; - - public: - const WriteBarrier<Unknown>& key() const - { - return m_key; - } - - const WriteBarrier<Unknown>& value() const - { - return m_value; - } - - void visitChildren(SlotVisitor& visitor) - { - visitor.append(&m_key); - visitor.append(&m_value); - } - - void setKey(VM& vm, const JSCell* owner, JSValue key) - { - m_key.set(vm, owner, key); - } - - void setKeyWithoutWriteBarrier(JSValue key) - { - m_key.setWithoutWriteBarrier(key); - } - - void setValue(VM& vm, const JSCell* owner, JSValue value) - { - m_value.set(vm, owner, value); - } - - void clear() - { - m_key.clear(); - m_value.clear(); - } - }; - - typedef MapDataImpl<Entry, JSMapIterator> MapData; + typedef JSNonFinalObject Base; DECLARE_EXPORT_INFO; @@ -107,25 +55,21 @@ public: return create(exec->vm(), structure); } - bool has(ExecState*, JSValue); - size_t size(ExecState*); - JSValue get(ExecState*, JSValue); - JS_EXPORT_PRIVATE void set(ExecState*, JSValue key, JSValue value); - void clear(ExecState*); - bool remove(ExecState*, JSValue); + MapData* mapData() { return m_mapData.get(); } private: + static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; + JSMap(VM& vm, Structure* structure) : Base(vm, structure) - , m_mapData(vm) { } - static void destroy(JSCell*); + JS_EXPORT_PRIVATE void finishCreation(VM&); + static void visitChildren(JSCell*, SlotVisitor&); - static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken); - MapData m_mapData; + WriteBarrier<MapData> m_mapData; }; } diff --git a/Source/JavaScriptCore/runtime/JSMapIterator.cpp b/Source/JavaScriptCore/runtime/JSMapIterator.cpp index 885362bd4..091d90b52 100644 --- a/Source/JavaScriptCore/runtime/JSMapIterator.cpp +++ b/Source/JavaScriptCore/runtime/JSMapIterator.cpp @@ -29,32 +29,27 @@ #include "JSCJSValueInlines.h" #include "JSCellInlines.h" #include "JSMap.h" -#include "MapDataInlines.h" #include "SlotVisitorInlines.h" -#include "StructureInlines.h" namespace JSC { -const ClassInfo JSMapIterator::s_info = { "Map Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(JSMapIterator) }; +const ClassInfo JSMapIterator::s_info = { "Map Iterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSMapIterator) }; void JSMapIterator::finishCreation(VM& vm, JSMap* iteratedObject) { Base::finishCreation(vm); - m_map.set(vm, this, iteratedObject); -} - -void JSMapIterator::destroy(JSCell* cell) -{ - JSMapIterator* thisObject = jsCast<JSMapIterator*>(cell); - thisObject->JSMapIterator::~JSMapIterator(); + m_iteratedObjectData.set(vm, this, iteratedObject->mapData()); } void JSMapIterator::visitChildren(JSCell* cell, SlotVisitor& visitor) { JSMapIterator* thisObject = jsCast<JSMapIterator*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + Base::visitChildren(thisObject, visitor); - visitor.append(&thisObject->m_map); + visitor.append(&thisObject->m_iteratedObjectData); } JSValue JSMapIterator::createPair(CallFrame* callFrame, JSValue key, JSValue value) @@ -66,11 +61,4 @@ JSValue JSMapIterator::createPair(CallFrame* callFrame, JSValue key, JSValue val return constructArray(callFrame, 0, globalObject, args); } -JSMapIterator* JSMapIterator::clone(ExecState* exec) -{ - auto clone = JSMapIterator::create(exec->vm(), exec->callee()->globalObject()->mapIteratorStructure(), m_map.get(), m_kind); - clone->m_iterator = m_iterator; - return clone; -} - } diff --git a/Source/JavaScriptCore/runtime/JSMapIterator.h b/Source/JavaScriptCore/runtime/JSMapIterator.h index cc2ae867a..5fc965ebc 100644 --- a/Source/JavaScriptCore/runtime/JSMapIterator.h +++ b/Source/JavaScriptCore/runtime/JSMapIterator.h @@ -57,27 +57,16 @@ public: bool next(CallFrame* callFrame, JSValue& value) { - WTF::KeyValuePair<JSValue, JSValue> pair; - if (!m_iterator.next(pair)) + if (!m_iterator.ensureSlot()) return false; if (m_kind == MapIterateValue) - value = pair.value; + value = m_iterator.value(); else if (m_kind == MapIterateKey) - value = pair.key; + value = m_iterator.key(); else - value = createPair(callFrame, pair.key, pair.value); - return true; - } - - bool nextKeyValue(JSValue& key, JSValue& value) - { - WTF::KeyValuePair<JSValue, JSValue> pair; - if (!m_iterator.next(pair)) - return false; - - key = pair.key; - value = pair.value; + value = createPair(callFrame, m_iterator.key(), m_iterator.value()); + ++m_iterator; return true; } @@ -86,30 +75,23 @@ public: m_iterator.finish(); } - MapIterationKind kind() const { return m_kind; } - JSValue iteratedValue() const { return m_map.get(); } - JSMapIterator* clone(ExecState*); +private: - JSMap::MapData::IteratorData* iteratorData() - { - return &m_iterator; - } + static const unsigned StructureFlags = Base::StructureFlags | OverridesVisitChildren; -private: JSMapIterator(VM& vm, Structure* structure, JSMap* iteratedObject, MapIterationKind kind) : Base(vm, structure) - , m_iterator(iteratedObject->m_mapData.createIteratorData(this)) + , m_iterator(iteratedObject->mapData()->begin()) , m_kind(kind) { } - static void destroy(JSCell*); - JS_EXPORT_PRIVATE void finishCreation(VM&, JSMap*); + void finishCreation(VM&, JSMap*); JSValue createPair(CallFrame*, JSValue, JSValue); static void visitChildren(JSCell*, SlotVisitor&); - WriteBarrier<JSMap> m_map; - JSMap::MapData::IteratorData m_iterator; + WriteBarrier<MapData> m_iteratedObjectData; + MapData::const_iterator m_iterator; MapIterationKind m_kind; }; diff --git a/Source/JavaScriptCore/runtime/JSNameScope.cpp b/Source/JavaScriptCore/runtime/JSNameScope.cpp new file mode 100644 index 000000000..76542f676 --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSNameScope.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2008, 2009, 2012 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSNameScope.h" + +#include "Error.h" +#include "Operations.h" + +namespace JSC { + +const ClassInfo JSNameScope::s_info = { "NameScope", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSNameScope) }; + +void JSNameScope::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + JSNameScope* thisObject = jsCast<JSNameScope*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + + Base::visitChildren(thisObject, visitor); + visitor.append(&thisObject->m_registerStore); +} + +JSValue JSNameScope::toThis(JSCell*, ExecState* exec, ECMAMode ecmaMode) +{ + if (ecmaMode == StrictMode) + return jsUndefined(); + return exec->globalThisValue(); +} + +void JSNameScope::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) +{ + JSNameScope* thisObject = jsCast<JSNameScope*>(cell); + if (slot.isStrictMode()) { + // Double lookup in strict mode, but this only occurs when + // a) indirectly writing to an exception slot + // b) writing to a function expression name + // (a) is unlikely, and (b) is an error. + // Also with a single entry the symbol table lookup should simply be + // a pointer compare. + PropertySlot slot(thisObject); + bool isWritable = true; + symbolTableGet(thisObject, propertyName, slot, isWritable); + if (!isWritable) { + exec->vm().throwException(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError)); + return; + } + } + if (symbolTablePut(thisObject, exec, propertyName, value, slot.isStrictMode())) + return; + + RELEASE_ASSERT_NOT_REACHED(); +} + +bool JSNameScope::getOwnPropertySlot(JSObject* object, ExecState*, PropertyName propertyName, PropertySlot& slot) +{ + return symbolTableGet(jsCast<JSNameScope*>(object), propertyName, slot); +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSNameScope.h b/Source/JavaScriptCore/runtime/JSNameScope.h new file mode 100644 index 000000000..f5b15a214 --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSNameScope.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSNameScope_h +#define JSNameScope_h + +#include "JSGlobalObject.h" +#include "JSVariableObject.h" + +namespace JSC { + +// Used for scopes with a single named variable: catch and named function expression. +class JSNameScope : public JSVariableObject { +public: + typedef JSVariableObject Base; + + static JSNameScope* create(ExecState* exec, const Identifier& identifier, JSValue value, unsigned attributes) + { + VM& vm = exec->vm(); + JSNameScope* scopeObject = new (NotNull, allocateCell<JSNameScope>(vm.heap)) JSNameScope(exec, exec->scope()); + scopeObject->finishCreation(vm, identifier, value, attributes); + return scopeObject; + } + + static JSNameScope* create(ExecState* exec, const Identifier& identifier, JSValue value, unsigned attributes, JSScope* next) + { + VM& vm = exec->vm(); + JSNameScope* scopeObject = new (NotNull, allocateCell<JSNameScope>(vm.heap)) JSNameScope(exec, next); + scopeObject->finishCreation(vm, identifier, value, attributes); + return scopeObject; + } + + static void visitChildren(JSCell*, SlotVisitor&); + static JSValue toThis(JSCell*, ExecState*, ECMAMode); + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(NameScopeObjectType, StructureFlags), info()); } + + DECLARE_INFO; + +protected: + void finishCreation(VM& vm, const Identifier& identifier, JSValue value, unsigned attributes) + { + Base::finishCreation(vm); + m_registerStore.set(vm, this, value); + symbolTable()->add(identifier.impl(), SymbolTableEntry(-1, attributes)); + } + + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | Base::StructureFlags; + +private: + JSNameScope(ExecState* exec, JSScope* next) + : Base( + exec->vm(), + exec->lexicalGlobalObject()->nameScopeStructure(), + reinterpret_cast<Register*>(&m_registerStore + 1), + next + ) + { + } + + WriteBarrier<Unknown> m_registerStore; +}; + +} + +#endif // JSNameScope_h diff --git a/Source/JavaScriptCore/runtime/JSNotAnObject.cpp b/Source/JavaScriptCore/runtime/JSNotAnObject.cpp index af4737e9b..7b7f3650f 100644 --- a/Source/JavaScriptCore/runtime/JSNotAnObject.cpp +++ b/Source/JavaScriptCore/runtime/JSNotAnObject.cpp @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -30,13 +30,13 @@ #include "config.h" #include "JSNotAnObject.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSNotAnObject); -const ClassInfo JSNotAnObject::s_info = { "Object", &Base::s_info, 0, CREATE_METHOD_TABLE(JSNotAnObject) }; +const ClassInfo JSNotAnObject::s_info = { "Object", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSNotAnObject) }; // JSValue methods JSValue JSNotAnObject::defaultValue(const JSObject*, ExecState* exec, PreferredPrimitiveType) diff --git a/Source/JavaScriptCore/runtime/JSNotAnObject.h b/Source/JavaScriptCore/runtime/JSNotAnObject.h index 0c26ec98b..8c3dd7263 100644 --- a/Source/JavaScriptCore/runtime/JSNotAnObject.h +++ b/Source/JavaScriptCore/runtime/JSNotAnObject.h @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -33,50 +33,52 @@ namespace JSC { -// This unholy class is used to allow us to avoid multiple exception checks -// in certain SquirrelFish bytecodes -- effectively it just silently consumes -// any operations performed on the result of a failed toObject call. -class JSNotAnObject final : public JSNonFinalObject { -private: - explicit JSNotAnObject(VM& vm) - : JSNonFinalObject(vm, vm.notAnObjectStructure.get()) - { - } + // This unholy class is used to allow us to avoid multiple exception checks + // in certain SquirrelFish bytecodes -- effectively it just silently consumes + // any operations performed on the result of a failed toObject call. + class JSNotAnObject : public JSNonFinalObject { + private: + explicit JSNotAnObject(VM& vm) + : JSNonFinalObject(vm, vm.notAnObjectStructure.get()) + { + } + + public: + typedef JSNonFinalObject Base; -public: - typedef JSNonFinalObject Base; - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames; + static JSNotAnObject* create(VM& vm) + { + JSNotAnObject* object = new (NotNull, allocateCell<JSNotAnObject>(vm.heap)) JSNotAnObject(vm); + object->finishCreation(vm); + return object; + } - static JSNotAnObject* create(VM& vm) - { - JSNotAnObject* object = new (NotNull, allocateCell<JSNotAnObject>(vm.heap)) JSNotAnObject(vm); - object->finishCreation(vm); - return object; - } + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } + DECLARE_INFO; - DECLARE_INFO; + private: + + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames | JSObject::StructureFlags; -private: - // JSValue methods - static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType); + // JSValue methods + static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType); - // JSObject methods - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); - static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&); + // JSObject methods + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&); - static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); - static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); + static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); + static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); - static bool deleteProperty(JSCell*, ExecState*, PropertyName); - static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); + static bool deleteProperty(JSCell*, ExecState*, PropertyName); + static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); - static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); -}; + static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSONObject.cpp b/Source/JavaScriptCore/runtime/JSONObject.cpp index f67ba7ece..982628917 100644 --- a/Source/JavaScriptCore/runtime/JSONObject.cpp +++ b/Source/JavaScriptCore/runtime/JSONObject.cpp @@ -36,7 +36,7 @@ #include "LocalScope.h" #include "Lookup.h" #include "ObjectConstructor.h" -#include "JSCInlines.h" +#include "Operations.h" #include "PropertyNameArray.h" #include <wtf/MathExtras.h> #include <wtf/text/StringBuilder.h> @@ -45,8 +45,8 @@ namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSONObject); -EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState*); -EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*); +static EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState*); +static EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*); } @@ -107,8 +107,9 @@ private: friend class Holder; + static void appendQuotedString(StringBuilder&, const String&); + JSValue toJSON(JSValue, const PropertyNameForFunctionCall&); - JSValue toJSONImpl(JSValue, const PropertyNameForFunctionCall&); enum StringifyResult { StringifyFailed, StringifySucceeded, StringifyFailedDueToUndefinedValue }; StringifyResult appendStringifiedValue(StringBuilder&, JSValue, JSObject* holder, const PropertyNameForFunctionCall&); @@ -206,7 +207,7 @@ Stringifier::Stringifier(ExecState* exec, const Local<Unknown>& replacer, const : m_exec(exec) , m_replacer(replacer) , m_usingArrayReplacer(false) - , m_arrayReplacerPropertyNames(exec, PropertyNameMode::Strings) + , m_arrayReplacerPropertyNames(exec) , m_replacerCallType(CallTypeNone) , m_gap(gap(exec, space.get())) { @@ -225,10 +226,9 @@ Stringifier::Stringifier(ExecState* exec, const Local<Unknown>& replacer, const if (name.isObject()) { if (!asObject(name)->inherits(NumberObject::info()) && !asObject(name)->inherits(StringObject::info())) continue; - } else if (!name.isNumber() && !name.isString()) - continue; + } - m_arrayReplacerPropertyNames.add(name.toString(exec)->toIdentifier(exec)); + m_arrayReplacerPropertyNames.add(Identifier(exec, name.toString(exec)->value(exec))); } return; } @@ -254,16 +254,83 @@ Local<Unknown> Stringifier::stringify(Handle<Unknown> value) return Local<Unknown>(m_exec->vm(), jsString(m_exec, result.toString())); } -ALWAYS_INLINE JSValue Stringifier::toJSON(JSValue value, const PropertyNameForFunctionCall& propertyName) +template <typename CharType> +static void appendStringToStringBuilder(StringBuilder& builder, const CharType* data, int length) +{ + for (int i = 0; i < length; ++i) { + int start = i; + while (i < length && (data[i] > 0x1F && data[i] != '"' && data[i] != '\\')) + ++i; + builder.append(data + start, i - start); + if (i >= length) + break; + switch (data[i]) { + case '\t': + builder.append('\\'); + builder.append('t'); + break; + case '\r': + builder.append('\\'); + builder.append('r'); + break; + case '\n': + builder.append('\\'); + builder.append('n'); + break; + case '\f': + builder.append('\\'); + builder.append('f'); + break; + case '\b': + builder.append('\\'); + builder.append('b'); + break; + case '"': + builder.append('\\'); + builder.append('"'); + break; + case '\\': + builder.append('\\'); + builder.append('\\'); + break; + default: + static const char hexDigits[] = "0123456789abcdef"; + UChar ch = data[i]; + LChar hex[] = { '\\', 'u', static_cast<LChar>(hexDigits[(ch >> 12) & 0xF]), static_cast<LChar>(hexDigits[(ch >> 8) & 0xF]), static_cast<LChar>(hexDigits[(ch >> 4) & 0xF]), static_cast<LChar>(hexDigits[ch & 0xF]) }; + builder.append(hex, WTF_ARRAY_LENGTH(hex)); + break; + } + } +} + +void escapeStringToBuilder(StringBuilder& builder, const String& message) +{ + if (message.is8Bit()) + appendStringToStringBuilder(builder, message.characters8(), message.length()); + else + appendStringToStringBuilder(builder, message.characters16(), message.length()); +} + +void Stringifier::appendQuotedString(StringBuilder& builder, const String& value) +{ + int length = value.length(); + + builder.append('"'); + + if (value.is8Bit()) + appendStringToStringBuilder<LChar>(builder, value.characters8(), length); + else + appendStringToStringBuilder<UChar>(builder, value.characters16(), length); + + builder.append('"'); +} + +inline JSValue Stringifier::toJSON(JSValue value, const PropertyNameForFunctionCall& propertyName) { ASSERT(!m_exec->hadException()); if (!value.isObject() || !asObject(value)->hasProperty(m_exec, m_exec->vm().propertyNames->toJSON)) return value; - return toJSONImpl(value, propertyName); -} -JSValue Stringifier::toJSONImpl(JSValue value, const PropertyNameForFunctionCall& propertyName) -{ JSValue toJSONFunction = asObject(value)->get(m_exec, m_exec->vm().propertyNames->toJSON); if (m_exec->hadException()) return jsNull(); @@ -320,21 +387,18 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder& return StringifySucceeded; } - if (value.isString()) { - builder.appendQuotedJSONString(asString(value)->value(m_exec)); + String stringValue; + if (value.getString(m_exec, stringValue)) { + appendQuotedString(builder, stringValue); return StringifySucceeded; } if (value.isNumber()) { - if (value.isInt32()) - builder.appendNumber(value.asInt32()); - else { - double number = value.asNumber(); - if (!std::isfinite(number)) - builder.appendLiteral("null"); - else - builder.appendECMAScriptNumber(number); - } + double number = value.asNumber(); + if (!std::isfinite(number)) + builder.appendLiteral("null"); + else + builder.append(String::numberToStringECMAScript(number)); return StringifySucceeded; } @@ -423,17 +487,14 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui if (!m_index) { if (m_isArray) { m_isJSArray = isJSArray(m_object.get()); - if (m_isJSArray) - m_size = asArray(m_object.get())->length(); - else - m_size = m_object->get(exec, exec->vm().propertyNames->length).toUInt32(exec); + m_size = m_object->get(exec, exec->vm().propertyNames->length).toUInt32(exec); builder.append('['); } else { if (stringifier.m_usingArrayReplacer) m_propertyNames = stringifier.m_arrayReplacerPropertyNames.data(); else { - PropertyNameArray objectPropertyNames(exec, PropertyNameMode::Strings); - m_object->methodTable()->getOwnPropertyNames(m_object.get(), exec, objectPropertyNames, EnumerationMode()); + PropertyNameArray objectPropertyNames(exec); + m_object->methodTable()->getOwnPropertyNames(m_object.get(), exec, objectPropertyNames, ExcludeDontEnumProperties); m_propertyNames = objectPropertyNames.releaseData(); } m_size = m_propertyNames->propertyNameVector().size(); @@ -495,7 +556,7 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui stringifier.startNewLine(builder); // Append the property name. - builder.appendQuotedJSONString(propertyName.string()); + appendQuotedString(builder, propertyName.string()); builder.append(':'); if (stringifier.willIndent()) builder.append(' '); @@ -527,7 +588,7 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui // ------------------------------ JSONObject -------------------------------- -const ClassInfo JSONObject::s_info = { "JSON", &JSNonFinalObject::s_info, &jsonTable, CREATE_METHOD_TABLE(JSONObject) }; +const ClassInfo JSONObject::s_info = { "JSON", &JSNonFinalObject::s_info, 0, ExecState::jsonTable, CREATE_METHOD_TABLE(JSONObject) }; /* Source for JSONObject.lut.h @begin jsonTable @@ -540,7 +601,7 @@ const ClassInfo JSONObject::s_info = { "JSON", &JSNonFinalObject::s_info, &jsonT bool JSONObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { - return getStaticFunctionSlot<JSObject>(exec, jsonTable, jsCast<JSONObject*>(object), propertyName, slot); + return getStaticFunctionSlot<JSObject>(exec, ExecState::jsonTable(exec->vm()), jsCast<JSONObject*>(object), propertyName, slot); } class Walker { @@ -593,7 +654,7 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) ASSERT(inValue.isObject()); ASSERT(isJSArray(asObject(inValue)) || asObject(inValue)->inherits(JSArray::info())); if (objectStack.size() + arrayStack.size() > maximumFilterRecursion) - return throwStackOverflowError(m_exec); + return m_exec->vm().throwException(m_exec, createStackOverflowError(m_exec)); JSArray* array = asArray(inValue); arrayStack.push(array); @@ -644,13 +705,13 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) ASSERT(inValue.isObject()); ASSERT(!isJSArray(asObject(inValue)) && !asObject(inValue)->inherits(JSArray::info())); if (objectStack.size() + arrayStack.size() > maximumFilterRecursion) - return throwStackOverflowError(m_exec); + return m_exec->vm().throwException(m_exec, createStackOverflowError(m_exec)); JSObject* object = asObject(inValue); objectStack.push(object); indexStack.append(0); - propertyStack.append(PropertyNameArray(m_exec, PropertyNameMode::Strings)); - object->methodTable()->getOwnPropertyNames(object, m_exec, propertyStack.last(), EnumerationMode()); + propertyStack.append(PropertyNameArray(m_exec)); + object->methodTable()->getOwnPropertyNames(object, m_exec, propertyStack.last(), ExcludeDontEnumProperties); } objectStartVisitMember: FALLTHROUGH; @@ -724,7 +785,7 @@ EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState* exec) { if (!exec->argumentCount()) return throwVMError(exec, createError(exec, ASCIILiteral("JSON.parse requires at least one parameter"))); - StringView source = exec->uncheckedArgument(0).toString(exec)->view(exec); + String source = exec->uncheckedArgument(0).toString(exec)->value(exec); if (exec->hadException()) return JSValue::encode(jsNull()); diff --git a/Source/JavaScriptCore/runtime/JSONObject.h b/Source/JavaScriptCore/runtime/JSONObject.h index d550525c9..cacfc5d6c 100644 --- a/Source/JavaScriptCore/runtime/JSONObject.h +++ b/Source/JavaScriptCore/runtime/JSONObject.h @@ -30,38 +30,40 @@ namespace JSC { -class Stringifier; + class Stringifier; -class JSONObject : public JSNonFinalObject { -public: - typedef JSNonFinalObject Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; + class JSONObject : public JSNonFinalObject { + public: + typedef JSNonFinalObject Base; - static JSONObject* create(VM& vm, Structure* structure) - { - JSONObject* object = new (NotNull, allocateCell<JSONObject>(vm.heap)) JSONObject(vm, structure); - object->finishCreation(vm); - return object; - } + static JSONObject* create(VM& vm, Structure* structure) + { + JSONObject* object = new (NotNull, allocateCell<JSONObject>(vm.heap)) JSONObject(vm, structure); + object->finishCreation(vm); + return object; + } + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } + + DECLARE_INFO; - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } + protected: + void finishCreation(VM&); + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSObject::StructureFlags; - DECLARE_INFO; + private: + JSONObject(VM&, Structure*); + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); -protected: - void finishCreation(VM&); + }; -private: - JSONObject(VM&, Structure*); - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); -}; - -JS_EXPORT_PRIVATE JSValue JSONParse(ExecState*, const String&); -JS_EXPORT_PRIVATE String JSONStringify(ExecState*, JSValue, unsigned indent); + JS_EXPORT_PRIVATE JSValue JSONParse(ExecState*, const String&); + JS_EXPORT_PRIVATE String JSONStringify(ExecState*, JSValue, unsigned indent); + void escapeStringToBuilder(StringBuilder&, const String&); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp index 52dea7801..6910b7e04 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-2006, 2008, 2009, 2012-2015 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 @@ -28,10 +28,8 @@ #include "CopiedSpaceInlines.h" #include "CopyVisitor.h" #include "CopyVisitorInlines.h" -#include "CustomGetterSetter.h" #include "DatePrototype.h" #include "ErrorConstructor.h" -#include "Exception.h" #include "Executable.h" #include "GetterSetter.h" #include "IndexingHeaderInlines.h" @@ -41,7 +39,7 @@ #include "NativeErrorConstructor.h" #include "Nodes.h" #include "ObjectPrototype.h" -#include "JSCInlines.h" +#include "Operations.h" #include "PropertyDescriptor.h" #include "PropertyNameArray.h" #include "Reject.h" @@ -57,28 +55,40 @@ namespace JSC { // ArrayConventions.h. static unsigned lastArraySize = 0; +JSCell* getCallableObjectSlow(JSCell* cell) +{ + Structure* structure = cell->structure(); + if (structure->typeInfo().type() == JSFunctionType) + return cell; + if (structure->classInfo()->isSubClassOf(InternalFunction::info())) + return cell; + return 0; +} + STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSObject); STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSFinalObject); const char* StrictModeReadonlyPropertyWriteError = "Attempted to assign to readonly property."; -const ClassInfo JSObject::s_info = { "Object", 0, 0, CREATE_METHOD_TABLE(JSObject) }; +const ClassInfo JSObject::s_info = { "Object", 0, 0, 0, CREATE_METHOD_TABLE(JSObject) }; -const ClassInfo JSFinalObject::s_info = { "Object", &Base::s_info, 0, CREATE_METHOD_TABLE(JSFinalObject) }; +const ClassInfo JSFinalObject::s_info = { "Object", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFinalObject) }; static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode, bool didReify) { - VM& vm = exec->vm(); - // Add properties from the static hashtables of properties for (; classInfo; classInfo = classInfo->parentClass) { - const HashTable* table = classInfo->staticPropHashTable; + const HashTable* table = classInfo->propHashTable(exec); if (!table) continue; - - for (auto iter = table->begin(); iter != table->end(); ++iter) { - if ((!(iter->attributes() & DontEnum) || mode.includeDontEnumProperties()) && !((iter->attributes() & BuiltinOrFunctionOrAccessor) && didReify)) - propertyNames.add(Identifier::fromString(&vm, iter.key())); + table->initializeIfNeeded(exec); + ASSERT(table->table); + + int hashSizeMask = table->compactSize - 1; + const HashEntry* entry = table->table; + for (int i = 0; i <= hashSizeMask; ++i, ++entry) { + if (entry->key() && (!(entry->attributes() & DontEnum) || (mode == IncludeDontEnumProperties)) && !((entry->attributes() & Function) && didReify)) + propertyNames.add(entry->key()); } } } @@ -119,7 +129,7 @@ ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butt WriteBarrier<Unknown>* currentSource; size_t count; - switch (this->indexingType()) { + switch (structure->indexingType()) { case ALL_UNDECIDED_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: case ALL_INT32_INDEXING_TYPES: @@ -158,7 +168,7 @@ ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* but { ASSERT(butterfly); - Structure* structure = this->structure(visitor.vm()); + Structure* structure = this->structure(); size_t propertyCapacity = structure->outOfLineCapacity(); size_t preCapacity; @@ -180,7 +190,7 @@ ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* but butterfly->base(preCapacity, propertyCapacity), capacityInBytes); // Mark the array if appropriate. - switch (this->indexingType()) { + switch (structure->indexingType()) { case ALL_CONTIGUOUS_INDEXING_TYPES: visitor.appendValues(butterfly->contiguous().data(), butterfly->publicLength()); break; @@ -207,7 +217,7 @@ void JSObject::visitChildren(JSCell* cell, SlotVisitor& visitor) Butterfly* butterfly = thisObject->butterfly(); if (butterfly) - thisObject->visitButterfly(visitor, butterfly, thisObject->structure(visitor.vm())->outOfLineSize()); + thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize()); #if !ASSERT_DISABLED visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation; @@ -238,12 +248,11 @@ void JSFinalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) JSCell::visitChildren(thisObject, visitor); - Structure* structure = thisObject->structure(); Butterfly* butterfly = thisObject->butterfly(); if (butterfly) - thisObject->visitButterfly(visitor, butterfly, structure->outOfLineSize()); + thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize()); - size_t storageSize = structure->inlineSize(); + size_t storageSize = thisObject->structure()->inlineSize(); visitor.appendValues(thisObject->inlineStorage(), storageSize); #if !ASSERT_DISABLED @@ -258,44 +267,6 @@ String JSObject::className(const JSObject* object) return info->className; } -String JSObject::calculatedClassName(JSObject* object) -{ - String prototypeFunctionName; - ExecState* exec = object->globalObject()->globalExec(); - PropertySlot slot(object->structure()->storedPrototype()); - PropertyName constructor(exec->propertyNames().constructor); - if (object->getPropertySlot(exec, constructor, slot)) { - if (slot.isValue()) { - JSValue constructorValue = slot.getValue(exec, constructor); - if (constructorValue.isCell()) { - if (JSCell* constructorCell = constructorValue.asCell()) { - if (JSObject* ctorObject = constructorCell->getObject()) { - if (JSFunction* constructorFunction = jsDynamicCast<JSFunction*>(ctorObject)) - prototypeFunctionName = constructorFunction->calculatedDisplayName(exec); - else if (InternalFunction* constructorFunction = jsDynamicCast<InternalFunction*>(ctorObject)) - prototypeFunctionName = constructorFunction->calculatedDisplayName(exec); - } - } - } - } - } - - if (prototypeFunctionName.isNull() || prototypeFunctionName == "Object") { - String tableClassName = object->methodTable()->className(object); - if (!tableClassName.isNull() && tableClassName != "Object") - return tableClassName; - - String classInfoName = object->classInfo()->className; - if (!classInfoName.isNull()) - return classInfoName; - - if (prototypeFunctionName.isNull()) - return ASCIILiteral("Object"); - } - - return prototypeFunctionName; -} - bool JSObject::getOwnPropertySlotByIndex(JSObject* thisObject, ExecState* exec, unsigned i, PropertySlot& slot) { // NB. The fact that we're directly consulting our indexed storage implies that it is not @@ -303,9 +274,9 @@ bool JSObject::getOwnPropertySlotByIndex(JSObject* thisObject, ExecState* exec, // getOwnPropertySlotByIndex(). if (i > MAX_ARRAY_INDEX) - return thisObject->methodTable(exec->vm())->getOwnPropertySlot(thisObject, exec, Identifier::from(exec, i), slot); + return thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, Identifier::from(exec, i), slot); - switch (thisObject->indexingType()) { + switch (thisObject->structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: case ALL_UNDECIDED_INDEXING_TYPES: break; @@ -378,19 +349,20 @@ void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSV // 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. - if (Optional<uint32_t> index = parseIndex(propertyName)) { - putByIndex(thisObject, exec, index.value(), value, slot.isStrictMode()); + unsigned i = propertyName.asIndex(); + if (i != PropertyName::NotAnIndex) { + putByIndex(thisObject, exec, i, value, slot.isStrictMode()); return; } // Check if there are any setters or getters in the prototype chain JSValue prototype; if (propertyName != exec->propertyNames().underscoreProto) { - for (JSObject* obj = thisObject; !obj->structure(vm)->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) { + for (JSObject* obj = thisObject; !obj->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) { prototype = obj->prototype(); if (prototype.isNull()) { - ASSERT(!thisObject->structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName)); - if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot) + 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; @@ -401,10 +373,11 @@ void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSV JSObject* obj; for (obj = thisObject; ; obj = asObject(prototype)) { unsigned attributes; - PropertyOffset offset = obj->structure(vm)->get(vm, propertyName, attributes); + JSCell* specificValue; + PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes, specificValue); if (isValidOffset(offset)) { if (attributes & ReadOnly) { - ASSERT(thisObject->structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject); + ASSERT(thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject); if (slot.isStrictMode()) exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError))); return; @@ -413,28 +386,19 @@ void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSV JSValue gs = obj->getDirect(offset); if (gs.isGetterSetter()) { callSetter(exec, cell, gs, value, slot.isStrictMode() ? StrictMode : NotStrictMode); - if (!thisObject->structure()->isDictionary()) - slot.setCacheableSetter(obj, offset); - return; - } - if (gs.isCustomGetterSetter()) { - callCustomSetter(exec, gs, obj, slot.thisValue(), value); - slot.setCustomProperty(obj, jsCast<CustomGetterSetter*>(gs.asCell())->setter()); return; - } - ASSERT(!(attributes & Accessor)); + } else + ASSERT(!(attributes & Accessor)); // If there's an existing property on the object or one of its // prototypes it should be replaced, so break here. break; } const ClassInfo* info = obj->classInfo(); - if (info->hasStaticSetterOrReadonlyProperties()) { - if (const HashTableValue* entry = obj->findPropertyHashEntry(propertyName)) { - if (!obj->staticFunctionsReified() || !(entry->attributes() & BuiltinOrFunctionOrAccessor)) { - putEntry(exec, entry, obj, propertyName, value, slot); - return; - } + if (info->hasStaticSetterOrReadonlyProperties(vm)) { + if (const HashEntry* entry = obj->findPropertyHashEntry(exec, propertyName)) { + putEntry(exec, entry, obj, propertyName, value, slot); + return; } } prototype = obj->prototype(); @@ -442,8 +406,8 @@ void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSV break; } - ASSERT(!thisObject->structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject); - if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot) && 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; } @@ -458,7 +422,7 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, return; } - switch (thisObject->indexingType()) { + switch (thisObject->structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: break; @@ -585,11 +549,11 @@ 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(vm, map, value); + map->add(this, i).iterator->value.set(vm, this, value); } DeferGC deferGC(vm.heap); - Butterfly* newButterfly = storage->butterfly()->resizeArray(vm, this, structure(vm), 0, ArrayStorage::sizeFor(0)); + Butterfly* newButterfly = storage->butterfly()->resizeArray(vm, this, structure(), 0, ArrayStorage::sizeFor(0)); RELEASE_ASSERT(newButterfly); newButterfly->arrayStorage()->m_indexBias = 0; newButterfly->arrayStorage()->setVectorLength(0); @@ -601,7 +565,7 @@ ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists void JSObject::enterDictionaryIndexingMode(VM& vm) { - switch (indexingType()) { + switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: case ALL_UNDECIDED_INDEXING_TYPES: case ALL_INT32_INDEXING_TYPES: @@ -625,7 +589,7 @@ void JSObject::notifyPresenceOfIndexedAccessors(VM& vm) if (mayInterceptIndexedAccesses()) return; - setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AddIndexedAccessors)); + setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AddIndexedAccessors)); if (!vm.prototypeMap.isPrototype(this)) return; @@ -636,7 +600,7 @@ void JSObject::notifyPresenceOfIndexedAccessors(VM& vm) Butterfly* JSObject::createInitialIndexedStorage(VM& vm, unsigned length, size_t elementSize) { ASSERT(length < MAX_ARRAY_INDEX); - IndexingType oldType = indexingType(); + IndexingType oldType = structure()->indexingType(); ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType)); ASSERT(!structure()->needsSlowPutIndexing()); ASSERT(!indexingShouldBeSparse()); @@ -653,7 +617,7 @@ Butterfly* JSObject::createInitialUndecided(VM& vm, unsigned length) { DeferGC deferGC(vm.heap); Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue)); - Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), AllocateUndecided); + Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateUndecided); setStructureAndButterfly(vm, newStructure, newButterfly); return newButterfly; } @@ -662,7 +626,7 @@ ContiguousJSValues JSObject::createInitialInt32(VM& vm, unsigned length) { DeferGC deferGC(vm.heap); Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue)); - Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), AllocateInt32); + Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateInt32); setStructureAndButterfly(vm, newStructure, newButterfly); return newButterfly->contiguousInt32(); } @@ -672,8 +636,8 @@ ContiguousDoubles JSObject::createInitialDouble(VM& vm, unsigned length) DeferGC deferGC(vm.heap); Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(double)); for (unsigned i = newButterfly->vectorLength(); i--;) - newButterfly->contiguousDouble()[i] = PNaN; - Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), AllocateDouble); + newButterfly->contiguousDouble()[i] = QNaN; + Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateDouble); setStructureAndButterfly(vm, newStructure, newButterfly); return newButterfly->contiguousDouble(); } @@ -682,7 +646,7 @@ ContiguousJSValues JSObject::createInitialContiguous(VM& vm, unsigned length) { DeferGC deferGC(vm.heap); Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue)); - Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), AllocateContiguous); + Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateContiguous); setStructureAndButterfly(vm, newStructure, newButterfly); return newButterfly->contiguous(); } @@ -690,11 +654,10 @@ ContiguousJSValues JSObject::createInitialContiguous(VM& vm, unsigned length) ArrayStorage* JSObject::createArrayStorage(VM& vm, unsigned length, unsigned vectorLength) { DeferGC deferGC(vm.heap); - Structure* structure = this->structure(vm); - IndexingType oldType = indexingType(); + IndexingType oldType = structure()->indexingType(); ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType)); Butterfly* newButterfly = Butterfly::createOrGrowArrayRight( - m_butterfly.get(), vm, this, structure, structure->outOfLineCapacity(), false, 0, + m_butterfly.get(), vm, this, structure(), structure()->outOfLineCapacity(), false, 0, ArrayStorage::sizeFor(vectorLength)); RELEASE_ASSERT(newButterfly); @@ -704,7 +667,7 @@ ArrayStorage* JSObject::createArrayStorage(VM& vm, unsigned length, unsigned vec result->m_sparseMap.clear(); result->m_numValuesInVector = 0; result->m_indexBias = 0; - Structure* newStructure = Structure::nonPropertyTransition(vm, structure, structure->suggestedArrayStorageTransition()); + Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), structure()->suggestedArrayStorageTransition()); setStructureAndButterfly(vm, newStructure, newButterfly); return result; } @@ -716,35 +679,34 @@ ArrayStorage* JSObject::createInitialArrayStorage(VM& vm) ContiguousJSValues JSObject::convertUndecidedToInt32(VM& vm) { - ASSERT(hasUndecided(indexingType())); - setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateInt32)); + ASSERT(hasUndecided(structure()->indexingType())); + setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateInt32)); return m_butterfly->contiguousInt32(); } ContiguousDoubles JSObject::convertUndecidedToDouble(VM& vm) { - ASSERT(hasUndecided(indexingType())); + ASSERT(hasUndecided(structure()->indexingType())); for (unsigned i = m_butterfly->vectorLength(); i--;) - m_butterfly->contiguousDouble()[i] = PNaN; + m_butterfly->contiguousDouble()[i] = QNaN; - setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateDouble)); + setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble)); return m_butterfly->contiguousDouble(); } ContiguousJSValues JSObject::convertUndecidedToContiguous(VM& vm) { - ASSERT(hasUndecided(indexingType())); - setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateContiguous)); + ASSERT(hasUndecided(structure()->indexingType())); + setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous)); return m_butterfly->contiguous(); } ArrayStorage* JSObject::constructConvertedArrayStorageWithoutCopyingElements(VM& vm, unsigned neededLength) { - Structure* structure = this->structure(vm); unsigned publicLength = m_butterfly->publicLength(); - unsigned propertyCapacity = structure->outOfLineCapacity(); - unsigned propertySize = structure->outOfLineSize(); + unsigned propertyCapacity = structure()->outOfLineCapacity(); + unsigned propertySize = structure()->outOfLineSize(); Butterfly* newButterfly = Butterfly::createUninitialized( vm, this, 0, propertyCapacity, true, ArrayStorage::sizeFor(neededLength)); @@ -764,82 +726,90 @@ ArrayStorage* JSObject::constructConvertedArrayStorageWithoutCopyingElements(VM& return newStorage; } -ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm, NonPropertyTransition transition) +ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength) { DeferGC deferGC(vm.heap); - ASSERT(hasUndecided(indexingType())); - - unsigned vectorLength = m_butterfly->vectorLength(); - ArrayStorage* storage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength); + ASSERT(hasUndecided(structure()->indexingType())); + + ArrayStorage* storage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength); // No need to copy elements. - Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), transition); + Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition); setStructureAndButterfly(vm, newStructure, storage->butterfly()); return storage; } +ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm, NonPropertyTransition transition) +{ + return convertUndecidedToArrayStorage(vm, transition, m_butterfly->vectorLength()); +} + ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm) { - return convertUndecidedToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition()); + return convertUndecidedToArrayStorage(vm, structure()->suggestedArrayStorageTransition()); } ContiguousDoubles JSObject::convertInt32ToDouble(VM& vm) { - ASSERT(hasInt32(indexingType())); + ASSERT(hasInt32(structure()->indexingType())); for (unsigned i = m_butterfly->vectorLength(); i--;) { WriteBarrier<Unknown>* current = &m_butterfly->contiguousInt32()[i]; double* currentAsDouble = bitwise_cast<double*>(current); JSValue v = current->get(); if (!v) { - *currentAsDouble = PNaN; + *currentAsDouble = QNaN; continue; } ASSERT(v.isInt32()); *currentAsDouble = v.asInt32(); } - setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateDouble)); + setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble)); return m_butterfly->contiguousDouble(); } ContiguousJSValues JSObject::convertInt32ToContiguous(VM& vm) { - ASSERT(hasInt32(indexingType())); + ASSERT(hasInt32(structure()->indexingType())); - setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateContiguous)); + setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous)); return m_butterfly->contiguous(); } -ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm, NonPropertyTransition transition) +ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength) { + ASSERT(hasInt32(structure()->indexingType())); + DeferGC deferGC(vm.heap); - ASSERT(hasInt32(indexingType())); - - unsigned vectorLength = m_butterfly->vectorLength(); - ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength); - for (unsigned i = 0; i < m_butterfly->publicLength(); i++) { + ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength); + for (unsigned i = m_butterfly->publicLength(); i--;) { JSValue v = m_butterfly->contiguous()[i].get(); - if (v) { - newStorage->m_vector[i].setWithoutWriteBarrier(v); - newStorage->m_numValuesInVector++; - } else - ASSERT(newStorage->m_vector[i].get().isEmpty()); + if (!v) + continue; + newStorage->m_vector[i].setWithoutWriteBarrier(v); + newStorage->m_numValuesInVector++; } - Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), transition); + Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition); setStructureAndButterfly(vm, newStructure, newStorage->butterfly()); return newStorage; } +ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm, NonPropertyTransition transition) +{ + return convertInt32ToArrayStorage(vm, transition, m_butterfly->vectorLength()); +} + ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm) { - return convertInt32ToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition()); + return convertInt32ToArrayStorage(vm, structure()->suggestedArrayStorageTransition()); } -ContiguousJSValues JSObject::convertDoubleToContiguous(VM& vm) +template<JSObject::DoubleToContiguousMode mode> +ContiguousJSValues JSObject::genericConvertDoubleToContiguous(VM& vm) { - ASSERT(hasDouble(indexingType())); + ASSERT(hasDouble(structure()->indexingType())); for (unsigned i = m_butterfly->vectorLength(); i--;) { double* current = &m_butterfly->contiguousDouble()[i]; @@ -849,64 +819,89 @@ ContiguousJSValues JSObject::convertDoubleToContiguous(VM& vm) currentAsValue->clear(); continue; } - JSValue v = 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(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateContiguous)); + setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous)); return m_butterfly->contiguous(); } -ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm, NonPropertyTransition transition) +ContiguousJSValues JSObject::convertDoubleToContiguous(VM& vm) { - DeferGC deferGC(vm.heap); - ASSERT(hasDouble(indexingType())); + return genericConvertDoubleToContiguous<EncodeValueAsDouble>(vm); +} - unsigned vectorLength = m_butterfly->vectorLength(); - ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength); - for (unsigned i = 0; i < m_butterfly->publicLength(); i++) { +ContiguousJSValues JSObject::rageConvertDoubleToContiguous(VM& vm) +{ + return genericConvertDoubleToContiguous<RageConvertDoubleToValue>(vm); +} + +ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength) +{ + DeferGC deferGC(vm.heap); + ASSERT(hasDouble(structure()->indexingType())); + + ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength); + for (unsigned i = m_butterfly->publicLength(); i--;) { double value = m_butterfly->contiguousDouble()[i]; - if (value == value) { - newStorage->m_vector[i].setWithoutWriteBarrier(JSValue(JSValue::EncodeAsDouble, value)); - newStorage->m_numValuesInVector++; - } else - ASSERT(newStorage->m_vector[i].get().isEmpty()); + if (value != value) + continue; + newStorage->m_vector[i].setWithoutWriteBarrier(JSValue(JSValue::EncodeAsDouble, value)); + newStorage->m_numValuesInVector++; } - Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), transition); + Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition); setStructureAndButterfly(vm, newStructure, newStorage->butterfly()); return newStorage; } +ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm, NonPropertyTransition transition) +{ + return convertDoubleToArrayStorage(vm, transition, m_butterfly->vectorLength()); +} + ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm) { - return convertDoubleToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition()); + return convertDoubleToArrayStorage(vm, structure()->suggestedArrayStorageTransition()); } -ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm, NonPropertyTransition transition) +ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength) { DeferGC deferGC(vm.heap); - ASSERT(hasContiguous(indexingType())); - - unsigned vectorLength = m_butterfly->vectorLength(); - ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength); - for (unsigned i = 0; i < m_butterfly->publicLength(); i++) { + ASSERT(hasContiguous(structure()->indexingType())); + + ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength); + for (unsigned i = m_butterfly->publicLength(); i--;) { JSValue v = m_butterfly->contiguous()[i].get(); - if (v) { - newStorage->m_vector[i].setWithoutWriteBarrier(v); - newStorage->m_numValuesInVector++; - } else - ASSERT(newStorage->m_vector[i].get().isEmpty()); + if (!v) + continue; + newStorage->m_vector[i].setWithoutWriteBarrier(v); + newStorage->m_numValuesInVector++; } - Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), transition); + Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition); setStructureAndButterfly(vm, newStructure, newStorage->butterfly()); return newStorage; } +ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm, NonPropertyTransition transition) +{ + return convertContiguousToArrayStorage(vm, transition, m_butterfly->vectorLength()); +} + ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm) { - return convertContiguousToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition()); + return convertContiguousToArrayStorage(vm, structure()->suggestedArrayStorageTransition()); } void JSObject::convertUndecidedForValue(VM& vm, JSValue value) @@ -946,7 +941,7 @@ void JSObject::convertInt32ForValue(VM& vm, JSValue value) { ASSERT(!value.isInt32()); - if (value.isDouble() && !std::isnan(value.asDouble())) { + if (value.isDouble()) { convertInt32ToDouble(vm); return; } @@ -980,9 +975,9 @@ ContiguousJSValues JSObject::ensureInt32Slow(VM& vm) { ASSERT(inherits(info())); - switch (indexingType()) { + switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: - if (UNLIKELY(indexingShouldBeSparse() || structure(vm)->needsSlowPutIndexing())) + if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing())) return ContiguousJSValues(); return createInitialInt32(vm, 0); @@ -1004,9 +999,9 @@ ContiguousDoubles JSObject::ensureDoubleSlow(VM& vm) { ASSERT(inherits(info())); - switch (indexingType()) { + switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: - if (UNLIKELY(indexingShouldBeSparse() || structure(vm)->needsSlowPutIndexing())) + if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing())) return ContiguousDoubles(); return createInitialDouble(vm, 0); @@ -1026,13 +1021,13 @@ ContiguousDoubles JSObject::ensureDoubleSlow(VM& vm) } } -ContiguousJSValues JSObject::ensureContiguousSlow(VM& vm) +ContiguousJSValues JSObject::ensureContiguousSlow(VM& vm, DoubleToContiguousMode mode) { ASSERT(inherits(info())); - switch (indexingType()) { + switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: - if (UNLIKELY(indexingShouldBeSparse() || structure(vm)->needsSlowPutIndexing())) + if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing())) return ContiguousJSValues(); return createInitialContiguous(vm, 0); @@ -1043,6 +1038,8 @@ ContiguousJSValues JSObject::ensureContiguousSlow(VM& vm) return convertInt32ToContiguous(vm); case ALL_DOUBLE_INDEXING_TYPES: + if (mode == RageConvertDoubleToValue) + return rageConvertDoubleToContiguous(vm); return convertDoubleToContiguous(vm); case ALL_ARRAY_STORAGE_INDEXING_TYPES: @@ -1054,11 +1051,21 @@ ContiguousJSValues JSObject::ensureContiguousSlow(VM& vm) } } +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(info())); - switch (indexingType()) { + switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: if (UNLIKELY(indexingShouldBeSparse())) return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm); @@ -1066,22 +1073,22 @@ ArrayStorage* JSObject::ensureArrayStorageSlow(VM& vm) case ALL_UNDECIDED_INDEXING_TYPES: ASSERT(!indexingShouldBeSparse()); - ASSERT(!structure(vm)->needsSlowPutIndexing()); + ASSERT(!structure()->needsSlowPutIndexing()); return convertUndecidedToArrayStorage(vm); case ALL_INT32_INDEXING_TYPES: ASSERT(!indexingShouldBeSparse()); - ASSERT(!structure(vm)->needsSlowPutIndexing()); + ASSERT(!structure()->needsSlowPutIndexing()); return convertInt32ToArrayStorage(vm); case ALL_DOUBLE_INDEXING_TYPES: ASSERT(!indexingShouldBeSparse()); - ASSERT(!structure(vm)->needsSlowPutIndexing()); + ASSERT(!structure()->needsSlowPutIndexing()); return convertDoubleToArrayStorage(vm); case ALL_CONTIGUOUS_INDEXING_TYPES: ASSERT(!indexingShouldBeSparse()); - ASSERT(!structure(vm)->needsSlowPutIndexing()); + ASSERT(!structure()->needsSlowPutIndexing()); return convertContiguousToArrayStorage(vm); default: @@ -1092,7 +1099,7 @@ ArrayStorage* JSObject::ensureArrayStorageSlow(VM& vm) ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(VM& vm) { - switch (indexingType()) { + switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: { createArrayStorage(vm, 0, 0); SparseArrayValueMap* map = allocateSparseIndexMap(vm); @@ -1123,7 +1130,7 @@ ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(V void JSObject::switchToSlowPutArrayStorage(VM& vm) { - switch (indexingType()) { + switch (structure()->indexingType()) { case ALL_UNDECIDED_INDEXING_TYPES: convertUndecidedToArrayStorage(vm, AllocateSlowPutArrayStorage); break; @@ -1142,7 +1149,7 @@ void JSObject::switchToSlowPutArrayStorage(VM& vm) case NonArrayWithArrayStorage: case ArrayWithArrayStorage: { - Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), SwitchToSlowPutArrayStorage); + Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), SwitchToSlowPutArrayStorage); setStructure(vm, newStructure); break; } @@ -1159,7 +1166,7 @@ void JSObject::setPrototype(VM& vm, JSValue prototype) if (prototype.isObject()) vm.prototypeMap.addPrototype(asObject(prototype)); - Structure* newStructure = Structure::changePrototypeTransition(vm, structure(vm), prototype); + Structure* newStructure = Structure::changePrototypeTransition(vm, structure(), prototype); setStructure(vm, newStructure); if (!newStructure->anyObjectInChainMayInterceptIndexedAccesses()) @@ -1170,10 +1177,10 @@ void JSObject::setPrototype(VM& vm, JSValue prototype) return; } - if (!hasIndexedProperties(indexingType())) + if (!hasIndexedProperties(structure()->indexingType())) return; - if (shouldUseSlowPut(indexingType())) + if (shouldUseSlowPut(structure()->indexingType())) return; switchToSlowPutArrayStorage(vm); @@ -1181,7 +1188,7 @@ void JSObject::setPrototype(VM& vm, JSValue prototype) bool JSObject::setPrototypeWithCycleCheck(ExecState* exec, JSValue prototype) { - ASSERT(methodTable(exec->vm())->toThis(this, exec, NotStrictMode) == this); + ASSERT(methodTable()->toThis(this, exec, NotStrictMode) == this); JSValue nextPrototype = prototype; while (nextPrototype && nextPrototype.isObject()) { if (nextPrototype == this) @@ -1198,61 +1205,34 @@ bool JSObject::allowsAccessFrom(ExecState* exec) return globalObject->globalObjectMethodTable()->allowsAccessFrom(globalObject, exec); } -void JSObject::putGetter(ExecState* exec, PropertyName propertyName, JSValue getter) -{ - PropertyDescriptor descriptor; - descriptor.setGetter(getter); - descriptor.setEnumerable(true); - descriptor.setConfigurable(true); - defineOwnProperty(this, exec, propertyName, descriptor, false); -} - -void JSObject::putSetter(ExecState* exec, PropertyName propertyName, JSValue setter) -{ - PropertyDescriptor descriptor; - descriptor.setSetter(setter); - descriptor.setEnumerable(true); - descriptor.setConfigurable(true); - defineOwnProperty(this, exec, propertyName, descriptor, false); -} - void JSObject::putDirectAccessor(ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes) { ASSERT(value.isGetterSetter() && (attributes & Accessor)); - if (Optional<uint32_t> index = parseIndex(propertyName)) { - putDirectIndex(exec, index.value(), value, attributes, PutDirectIndexLikePutDirect); + unsigned index = propertyName.asIndex(); + if (index != PropertyName::NotAnIndex) { + putDirectIndex(exec, index, value, attributes, PutDirectIndexLikePutDirect); return; } putDirectNonIndexAccessor(exec->vm(), propertyName, value, attributes); } -void JSObject::putDirectCustomAccessor(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes) -{ - ASSERT(!parseIndex(propertyName)); - - PutPropertySlot slot(this); - putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot); - - ASSERT(slot.type() == PutPropertySlot::NewProperty); - - Structure* structure = this->structure(vm); - if (attributes & ReadOnly) - structure->setContainsReadOnlyProperties(); - structure->setHasCustomGetterSetterPropertiesWithProtoCheck(propertyName == vm.propertyNames->underscoreProto); -} - void JSObject::putDirectNonIndexAccessor(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes) { PutPropertySlot slot(this); - putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot); + 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(vm, Structure::attributeChangeTransition(vm, structure(), propertyName, attributes)); - Structure* structure = this->structure(vm); if (attributes & ReadOnly) - structure->setContainsReadOnlyProperties(); + structure()->setContainsReadOnlyProperties(); - structure->setHasGetterSetterPropertiesWithProtoCheck(propertyName == vm.propertyNames->underscoreProto); + structure()->setHasGetterSetterProperties(propertyName == vm.propertyNames->underscoreProto); } bool JSObject::hasProperty(ExecState* exec, PropertyName propertyName) const @@ -1272,32 +1252,30 @@ bool JSObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName proper { JSObject* thisObject = jsCast<JSObject*>(cell); - if (Optional<uint32_t> index = parseIndex(propertyName)) - return thisObject->methodTable(exec->vm())->deletePropertyByIndex(thisObject, exec, index.value()); + unsigned i = propertyName.asIndex(); + if (i != PropertyName::NotAnIndex) + return thisObject->methodTable()->deletePropertyByIndex(thisObject, exec, i); if (!thisObject->staticFunctionsReified()) thisObject->reifyStaticFunctionsForDelete(exec); unsigned attributes; - VM& vm = exec->vm(); - if (isValidOffset(thisObject->structure(vm)->get(vm, propertyName, attributes))) { - if (attributes & DontDelete && !vm.isInDefineOwnProperty()) + JSCell* specificValue; + if (isValidOffset(thisObject->structure()->get(exec->vm(), propertyName, attributes, specificValue))) { + if (attributes & DontDelete && !exec->vm().isInDefineOwnProperty()) return false; - thisObject->removeDirect(vm, propertyName); + thisObject->removeDirect(exec->vm(), propertyName); return true; } // Look in the static hashtable of properties - const HashTableValue* entry = thisObject->findPropertyHashEntry(propertyName); + const HashEntry* entry = thisObject->findPropertyHashEntry(exec, propertyName); if (entry) { - if (entry->attributes() & DontDelete && !vm.isInDefineOwnProperty()) + if (entry->attributes() & DontDelete && !exec->vm().isInDefineOwnProperty()) return false; // this builtin property can't be deleted PutPropertySlot slot(thisObject); - if (!(entry->attributes() & BuiltinOrFunctionOrAccessor)) { - ASSERT(thisObject->staticFunctionsReified()); - putEntry(exec, entry, thisObject, propertyName, jsUndefined(), slot); - } + putEntry(exec, entry, thisObject, propertyName, jsUndefined(), slot); } return true; @@ -1306,13 +1284,7 @@ bool JSObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName proper bool JSObject::hasOwnProperty(ExecState* exec, PropertyName propertyName) const { PropertySlot slot(this); - return const_cast<JSObject*>(this)->methodTable(exec->vm())->getOwnPropertySlot(const_cast<JSObject*>(this), exec, propertyName, slot); -} - -bool JSObject::hasOwnProperty(ExecState* exec, unsigned propertyName) const -{ - PropertySlot slot(this); - return const_cast<JSObject*>(this)->methodTable(exec->vm())->getOwnPropertySlotByIndex(const_cast<JSObject*>(this), exec, propertyName, slot); + return const_cast<JSObject*>(this)->methodTable()->getOwnPropertySlot(const_cast<JSObject*>(this), exec, propertyName, slot); } bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i) @@ -1320,9 +1292,9 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i) JSObject* thisObject = jsCast<JSObject*>(cell); if (i > MAX_ARRAY_INDEX) - return thisObject->methodTable(exec->vm())->deleteProperty(thisObject, exec, Identifier::from(exec, i)); + return thisObject->methodTable()->deleteProperty(thisObject, exec, Identifier::from(exec, i)); - switch (thisObject->indexingType()) { + switch (thisObject->structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: case ALL_UNDECIDED_INDEXING_TYPES: return true; @@ -1340,7 +1312,7 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i) Butterfly* butterfly = thisObject->butterfly(); if (i >= butterfly->vectorLength()) return true; - butterfly->contiguousDouble()[i] = PNaN; + butterfly->contiguousDouble()[i] = QNaN; return true; } @@ -1395,7 +1367,7 @@ static ALWAYS_INLINE JSValue callDefaultValueFunction(ExecState* exec, const JSO bool JSObject::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result) const { - result = methodTable(exec->vm())->defaultValue(this, exec, PreferNumber); + result = methodTable()->defaultValue(this, exec, PreferNumber); number = result.toNumber(exec); return !result.isString(); } @@ -1403,10 +1375,6 @@ bool JSObject::getPrimitiveNumber(ExecState* exec, double& number, JSValue& resu // ECMA 8.6.2.6 JSValue JSObject::defaultValue(const JSObject* object, ExecState* exec, PreferredPrimitiveType hint) { - // Make sure that whatever default value methods there are on object's prototype chain are - // being watched. - object->structure()->startWatchingInternalPropertiesIfNecessaryForEntireChain(exec->vm()); - // Must call toString first for Date objects. if ((hint == PreferString) || (hint != PreferNumber && object->prototype() == exec->lexicalGlobalObject()->datePrototype())) { JSValue value = callDefaultValueFunction(exec, object, exec->propertyNames().toString); @@ -1429,11 +1397,11 @@ JSValue JSObject::defaultValue(const JSObject* object, ExecState* exec, Preferre return exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("No default value"))); } -const HashTableValue* JSObject::findPropertyHashEntry(PropertyName propertyName) const +const HashEntry* JSObject::findPropertyHashEntry(ExecState* exec, PropertyName propertyName) const { for (const ClassInfo* info = classInfo(); info; info = info->parentClass) { - if (const HashTable* propHashTable = info->staticPropHashTable) { - if (const HashTableValue* entry = propHashTable->entry(propertyName)) + if (const HashTable* propHashTable = info->propHashTable(exec)) { + if (const HashEntry* entry = propHashTable->entry(exec, propertyName)) return entry; } } @@ -1442,13 +1410,12 @@ const HashTableValue* JSObject::findPropertyHashEntry(PropertyName propertyName) bool JSObject::hasInstance(ExecState* exec, JSValue value) { - VM& vm = exec->vm(); - TypeInfo info = structure(vm)->typeInfo(); + TypeInfo info = structure()->typeInfo(); if (info.implementsDefaultHasInstance()) return defaultHasInstance(exec, value, get(exec, exec->propertyNames().prototype)); if (info.implementsHasInstance()) - return methodTable(vm)->customHasInstance(this, exec, value); - vm.throwException(exec, createInvalidInstanceofParameterError(exec, this)); + return methodTable()->customHasInstance(this, exec, value); + exec->vm().throwException(exec, createInvalidParameterError(exec, "instanceof" , this)); return false; } @@ -1470,21 +1437,34 @@ bool JSObject::defaultHasInstance(ExecState* exec, JSValue value, JSValue proto) return false; } +bool JSObject::getPropertySpecificValue(ExecState* exec, PropertyName propertyName, JSCell*& specificValue) const +{ + unsigned attributes; + if (isValidOffset(structure()->get(exec->vm(), propertyName, attributes, specificValue))) + return true; + + // This could be a function within the static table? - should probably + // also look in the hash? This currently should not be a problem, since + // we've currently always call 'get' first, which should have populated + // the normal storage. + return false; +} + void JSObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { - object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, propertyNames, mode); + propertyNames.setBaseObject(object); + object->methodTable()->getOwnPropertyNames(object, exec, propertyNames, mode); if (object->prototype().isNull()) return; - VM& vm = exec->vm(); JSObject* prototype = asObject(object->prototype()); while(1) { - if (prototype->structure(vm)->typeInfo().overridesGetPropertyNames()) { - prototype->methodTable(vm)->getPropertyNames(prototype, exec, propertyNames, mode); + if (prototype->structure()->typeInfo().overridesGetPropertyNames()) { + prototype->methodTable()->getPropertyNames(prototype, exec, propertyNames, mode); break; } - prototype->methodTable(vm)->getOwnPropertyNames(prototype, exec, propertyNames, mode); + prototype->methodTable()->getOwnPropertyNames(prototype, exec, propertyNames, mode); JSValue nextProto = prototype->prototype(); if (nextProto.isNull()) break; @@ -1494,89 +1474,81 @@ void JSObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameA void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { - if (!mode.includeJSObjectProperties()) { - // We still have to get non-indexed properties from any subclasses of JSObject that have them. - object->methodTable(exec->vm())->getOwnNonIndexPropertyNames(object, exec, propertyNames, mode); - return; + // Add numeric properties first. That appears to be the accepted convention. + // FIXME: Filling PropertyNameArray with an identifier for every integer + // is incredibly inefficient for large arrays. We need a different approach, + // which almost certainly means a different structure for PropertyNameArray. + switch (object->structure()->indexingType()) { + case ALL_BLANK_INDEXING_TYPES: + case ALL_UNDECIDED_INDEXING_TYPES: + break; + + case ALL_INT32_INDEXING_TYPES: + case ALL_CONTIGUOUS_INDEXING_TYPES: { + Butterfly* butterfly = object->butterfly(); + unsigned usedLength = butterfly->publicLength(); + for (unsigned i = 0; i < usedLength; ++i) { + if (!butterfly->contiguous()[i]) + continue; + propertyNames.add(Identifier::from(exec, i)); + } + break; } - - if (propertyNames.includeStringProperties()) { - // Add numeric properties first. That appears to be the accepted convention. - // FIXME: Filling PropertyNameArray with an identifier for every integer - // is incredibly inefficient for large arrays. We need a different approach, - // which almost certainly means a different structure for PropertyNameArray. - switch (object->indexingType()) { - case ALL_BLANK_INDEXING_TYPES: - case ALL_UNDECIDED_INDEXING_TYPES: - break; - - case ALL_INT32_INDEXING_TYPES: - case ALL_CONTIGUOUS_INDEXING_TYPES: { - Butterfly* butterfly = object->butterfly(); - unsigned usedLength = butterfly->publicLength(); - for (unsigned i = 0; i < usedLength; ++i) { - if (!butterfly->contiguous()[i]) - continue; - propertyNames.add(i); - } - break; + + case ALL_DOUBLE_INDEXING_TYPES: { + Butterfly* butterfly = object->butterfly(); + unsigned usedLength = butterfly->publicLength(); + for (unsigned i = 0; i < usedLength; ++i) { + double value = butterfly->contiguousDouble()[i]; + if (value != value) + continue; + propertyNames.add(Identifier::from(exec, i)); } - - case ALL_DOUBLE_INDEXING_TYPES: { - Butterfly* butterfly = object->butterfly(); - unsigned usedLength = butterfly->publicLength(); - for (unsigned i = 0; i < usedLength; ++i) { - double value = butterfly->contiguousDouble()[i]; - if (value != value) - continue; - propertyNames.add(i); - } - break; + break; + } + + case ALL_ARRAY_STORAGE_INDEXING_TYPES: { + ArrayStorage* storage = object->m_butterfly->arrayStorage(); + + unsigned usedVectorLength = std::min(storage->length(), storage->vectorLength()); + for (unsigned i = 0; i < usedVectorLength; ++i) { + if (storage->m_vector[i]) + propertyNames.add(Identifier::from(exec, i)); } + + if (SparseArrayValueMap* map = storage->m_sparseMap.get()) { + Vector<unsigned, 0, UnsafeVectorOverflow> keys; + keys.reserveInitialCapacity(map->size()); - case ALL_ARRAY_STORAGE_INDEXING_TYPES: { - ArrayStorage* storage = object->m_butterfly->arrayStorage(); - - unsigned usedVectorLength = std::min(storage->length(), storage->vectorLength()); - for (unsigned i = 0; i < usedVectorLength; ++i) { - if (storage->m_vector[i]) - propertyNames.add(i); - } - - if (SparseArrayValueMap* map = storage->m_sparseMap.get()) { - 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.uncheckedAppend(static_cast<unsigned>(it->key)); - } - - std::sort(keys.begin(), keys.end()); - for (unsigned i = 0; i < keys.size(); ++i) - propertyNames.add(keys[i]); + SparseArrayValueMap::const_iterator end = map->end(); + for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) { + if (mode == IncludeDontEnumProperties || !(it->value.attributes & DontEnum)) + keys.uncheckedAppend(static_cast<unsigned>(it->key)); } - break; - } - default: - RELEASE_ASSERT_NOT_REACHED(); + std::sort(keys.begin(), keys.end()); + for (unsigned i = 0; i < keys.size(); ++i) + propertyNames.add(Identifier::from(exec, keys[i])); } + break; } - - object->methodTable(exec->vm())->getOwnNonIndexPropertyNames(object, exec, propertyNames, mode); + + default: + RELEASE_ASSERT_NOT_REACHED(); + } + + object->methodTable()->getOwnNonIndexPropertyNames(object, exec, propertyNames, mode); } void JSObject::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { getClassPropertyNames(exec, object->classInfo(), propertyNames, mode, object->staticFunctionsReified()); - if (!mode.includeJSObjectProperties()) - return; - - VM& vm = exec->vm(); - object->structure(vm)->getPropertyNamesFromStructure(vm, propertyNames, mode); + bool canCachePropertiesFromStructure = !propertyNames.size(); + object->structure()->getPropertyNamesFromStructure(exec->vm(), propertyNames, mode); + + if (canCachePropertiesFromStructure) + propertyNames.setNumCacheableSlotsForObject(object, propertyNames.size()); } double JSObject::toNumber(ExecState* exec) const @@ -1605,7 +1577,7 @@ void JSObject::seal(VM& vm) if (isSealed(vm)) return; preventExtensions(vm); - setStructure(vm, Structure::sealTransition(vm, structure(vm))); + setStructure(vm, Structure::sealTransition(vm, structure())); } void JSObject::freeze(VM& vm) @@ -1613,14 +1585,14 @@ void JSObject::freeze(VM& vm) if (isFrozen(vm)) return; preventExtensions(vm); - setStructure(vm, Structure::freezeTransition(vm, structure(vm))); + setStructure(vm, Structure::freezeTransition(vm, structure())); } void JSObject::preventExtensions(VM& vm) { enterDictionaryIndexingMode(vm); if (isExtensible()) - setStructure(vm, Structure::preventExtensionsTransition(vm, structure(vm))); + setStructure(vm, Structure::preventExtensionsTransition(vm, structure())); } // This presently will flatten to an uncachable dictionary; this is suitable @@ -1633,43 +1605,42 @@ void JSObject::reifyStaticFunctionsForDelete(ExecState* exec) // 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. if (!classInfo()->hasStaticProperties()) { - structure(vm)->setStaticFunctionsReified(true); + structure()->setStaticFunctionsReified(); return; } - if (!structure(vm)->isUncacheableDictionary()) - setStructure(vm, Structure::toUncacheableDictionaryTransition(vm, structure(vm))); + if (!structure()->isUncacheableDictionary()) + setStructure(vm, Structure::toUncacheableDictionaryTransition(vm, structure())); for (const ClassInfo* info = classInfo(); info; info = info->parentClass) { - const HashTable* hashTable = info->staticPropHashTable; + const HashTable* hashTable = info->propHashTable(globalObject()->globalExec()); if (!hashTable) continue; PropertySlot slot(this); - for (auto iter = hashTable->begin(); iter != hashTable->end(); ++iter) { - if (iter->attributes() & BuiltinOrFunctionOrAccessor) - setUpStaticFunctionSlot(globalObject()->globalExec(), iter.value(), this, Identifier::fromString(&vm, iter.key()), slot); + for (HashTable::ConstIterator iter = hashTable->begin(vm); iter != hashTable->end(vm); ++iter) { + if (iter->attributes() & Function) + setUpStaticFunctionSlot(globalObject()->globalExec(), *iter, this, Identifier(&vm, iter->key()), slot); } } - structure(vm)->setStaticFunctionsReified(true); + structure()->setStaticFunctionsReified(); } bool JSObject::removeDirect(VM& vm, PropertyName propertyName) { - Structure* structure = this->structure(vm); - if (!isValidOffset(structure->get(vm, propertyName))) + if (!isValidOffset(structure()->get(vm, propertyName))) return false; PropertyOffset offset; - if (structure->isUncacheableDictionary()) { - offset = structure->removePropertyWithoutTransition(vm, propertyName); + if (structure()->isUncacheableDictionary()) { + offset = structure()->removePropertyWithoutTransition(vm, propertyName); if (offset == invalidOffset) return false; putDirectUndefined(offset); return true; } - setStructure(vm, Structure::removePropertyTransition(vm, structure, propertyName, offset)); + setStructure(vm, Structure::removePropertyTransition(vm, structure(), propertyName, offset)); if (offset == invalidOffset) return false; putDirectUndefined(offset); @@ -1682,19 +1653,19 @@ NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue g slot.setGetterSlot(this, attributes, jsCast<GetterSetter*>(getterSetter)); return; } + slot.setCacheableGetterSlot(this, attributes, jsCast<GetterSetter*>(getterSetter), offset); } void JSObject::putIndexedDescriptor(ExecState* exec, SparseArrayEntry* entryInMap, const PropertyDescriptor& descriptor, PropertyDescriptor& oldDescriptor) { VM& vm = exec->vm(); - auto map = m_butterfly->arrayStorage()->m_sparseMap.get(); if (descriptor.isDataDescriptor()) { if (descriptor.value()) - entryInMap->set(vm, map, descriptor.value()); + entryInMap->set(vm, this, descriptor.value()); else if (oldDescriptor.isAccessorDescriptor()) - entryInMap->set(vm, map, jsUndefined()); + entryInMap->set(vm, this, jsUndefined()); entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~Accessor; return; } @@ -1711,13 +1682,13 @@ void JSObject::putIndexedDescriptor(ExecState* exec, SparseArrayEntry* entryInMa else if (oldDescriptor.isAccessorDescriptor()) setter = oldDescriptor.setterObject(); - GetterSetter* accessor = GetterSetter::create(vm, exec->lexicalGlobalObject()); + GetterSetter* accessor = GetterSetter::create(vm); if (getter) - accessor->setGetter(vm, exec->lexicalGlobalObject(), getter); + accessor->setGetter(vm, getter); if (setter) - accessor->setSetter(vm, exec->lexicalGlobalObject(), setter); + accessor->setSetter(vm, setter); - entryInMap->set(vm, map, accessor); + entryInMap->set(vm, this, accessor); entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~ReadOnly; return; } @@ -1898,7 +1869,7 @@ bool JSObject::attemptToInterceptPutByIndexOnHole(ExecState* exec, unsigned i, J template<IndexingType indexingShape> void JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, unsigned i, JSValue value) { - ASSERT((indexingType() & IndexingShapeMask) == indexingShape); + ASSERT((structure()->indexingType() & IndexingShapeMask) == indexingShape); ASSERT(!indexingShouldBeSparse()); // For us to get here, the index is either greater than the public length, or greater than @@ -1946,11 +1917,6 @@ void JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, un } } -// Explicit instantiations needed by JSArray.cpp. -template void JSObject::putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(ExecState*, unsigned, JSValue); -template void JSObject::putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(ExecState*, unsigned, JSValue); -template void JSObject::putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(ExecState*, unsigned, JSValue); - void JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, bool shouldThrow, ArrayStorage* storage) { VM& vm = exec->vm(); @@ -2032,7 +1998,7 @@ void JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue // i should be a valid array index that is outside of the current vector. ASSERT(i <= MAX_ARRAY_INDEX); - switch (indexingType()) { + switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: { if (indexingShouldBeSparse()) { putByIndexBeyondVectorLengthWithArrayStorage( @@ -2045,10 +2011,10 @@ void JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue exec, i, value, shouldThrow, createArrayStorage(vm, 0, 0)); break; } - if (structure(vm)->needsSlowPutIndexing()) { - // Convert the indexing type to the SlowPutArrayStorage and retry. - createArrayStorage(vm, i + 1, getNewVectorLength(0, 0, i + 1)); - putByIndex(this, exec, i, value, shouldThrow); + if (structure()->needsSlowPutIndexing()) { + ArrayStorage* storage = createArrayStorage(vm, i + 1, getNewVectorLength(0, 0, i + 1)); + storage->m_vector[i].set(vm, this, value); + storage->m_numValuesInVector++; break; } @@ -2100,7 +2066,7 @@ bool JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, VM& vm = exec->vm(); // i should be a valid array index that is outside of the current vector. - ASSERT(hasAnyArrayStorage(indexingType())); + ASSERT(hasArrayStorage(structure()->indexingType())); ASSERT(arrayStorage() == storage); ASSERT(i >= storage->vectorLength() || attributes); ASSERT(i <= MAX_ARRAY_INDEX); @@ -2182,7 +2148,7 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV if (attributes & (ReadOnly | Accessor)) notifyPresenceOfIndexedAccessors(vm); - switch (indexingType()) { + switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: { if (indexingShouldBeSparse() || attributes) { return putDirectIndexBeyondVectorLengthWithArrayStorage( @@ -2193,7 +2159,7 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV return putDirectIndexBeyondVectorLengthWithArrayStorage( exec, i, value, attributes, mode, createArrayStorage(vm, 0, 0)); } - if (structure(vm)->needsSlowPutIndexing()) { + if (structure()->needsSlowPutIndexing()) { ArrayStorage* storage = createArrayStorage(vm, i + 1, getNewVectorLength(0, 0, i + 1)); storage->m_vector[i].set(vm, this, value); storage->m_numValuesInVector++; @@ -2211,10 +2177,9 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV } case ALL_INT32_INDEXING_TYPES: { - if (attributes) { - if (i < m_butterfly->vectorLength()) - return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm)); - return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, convertInt32ToArrayStorage(vm)); + if (attributes & (ReadOnly | Accessor)) { + return putDirectIndexBeyondVectorLengthWithArrayStorage( + exec, i, value, attributes, mode, convertInt32ToArrayStorage(vm)); } if (!value.isInt32()) { convertInt32ForValue(vm, value); @@ -2225,10 +2190,9 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV } case ALL_DOUBLE_INDEXING_TYPES: { - if (attributes) { - if (i < m_butterfly->vectorLength()) - return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm)); - return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, convertDoubleToArrayStorage(vm)); + if (attributes & (ReadOnly | Accessor)) { + return putDirectIndexBeyondVectorLengthWithArrayStorage( + exec, i, value, attributes, mode, convertDoubleToArrayStorage(vm)); } if (!value.isNumber()) { convertDoubleToContiguous(vm); @@ -2244,20 +2208,15 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV } case ALL_CONTIGUOUS_INDEXING_TYPES: { - if (attributes) { - if (i < m_butterfly->vectorLength()) - return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm)); - return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, convertContiguousToArrayStorage(vm)); + if (attributes & (ReadOnly | Accessor)) { + return putDirectIndexBeyondVectorLengthWithArrayStorage( + exec, i, value, attributes, mode, convertContiguousToArrayStorage(vm)); } putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, i, value); return true; } case ALL_ARRAY_STORAGE_INDEXING_TYPES: - if (attributes) { - if (i < m_butterfly->vectorLength()) - return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm)); - } return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, arrayStorage()); default: @@ -2277,28 +2236,6 @@ void JSObject::putDirectNativeFunction(VM& vm, JSGlobalObject* globalObject, con putDirect(vm, propertyName, function, attributes); } -JSFunction* JSObject::putDirectBuiltinFunction(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, FunctionExecutable* functionExecutable, unsigned attributes) -{ - StringImpl* name = propertyName.publicName(); - if (!name) - name = vm.propertyNames->anonymous.impl(); - ASSERT(name); - JSFunction* function = JSFunction::createBuiltinFunction(vm, static_cast<FunctionExecutable*>(functionExecutable), globalObject); - putDirect(vm, propertyName, function, attributes); - return function; -} - -JSFunction* JSObject::putDirectBuiltinFunctionWithoutTransition(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, FunctionExecutable* functionExecutable, unsigned attributes) -{ - StringImpl* name = propertyName.publicName(); - if (!name) - name = vm.propertyNames->anonymous.impl(); - ASSERT(name); - JSFunction* function = JSFunction::createBuiltinFunction(vm, static_cast<FunctionExecutable*>(functionExecutable), globalObject); - putDirectWithoutTransition(vm, propertyName, function, attributes); - return function; -} - void JSObject::putDirectNativeFunctionWithoutTransition(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, unsigned functionLength, NativeFunction nativeFunction, Intrinsic intrinsic, unsigned attributes) { StringImpl* name = propertyName.publicName(); @@ -2335,7 +2272,7 @@ ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned desiredLength) unsigned vectorLength; unsigned length; - if (hasIndexedProperties(indexingType())) { + if (hasIndexedProperties(structure()->indexingType())) { vectorLength = m_butterfly->vectorLength(); length = m_butterfly->publicLength(); } else { @@ -2374,7 +2311,7 @@ unsigned JSObject::countElements(Butterfly* butterfly) unsigned JSObject::countElements() { - switch (indexingType()) { + switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: case ALL_UNDECIDED_INDEXING_TYPES: return 0; @@ -2413,11 +2350,10 @@ bool JSObject::increaseVectorLength(VM& vm, unsigned newLength) unsigned newVectorLength = getNewVectorLength(newLength); // Fast case - there is no precapacity. In these cases a realloc makes sense. - Structure* structure = this->structure(vm); if (LIKELY(!indexBias)) { DeferGC deferGC(vm.heap); Butterfly* newButterfly = storage->butterfly()->growArrayRight( - vm, this, structure, structure->outOfLineCapacity(), true, + vm, this, structure(), structure()->outOfLineCapacity(), true, ArrayStorage::sizeFor(vectorLength), ArrayStorage::sizeFor(newVectorLength)); if (!newButterfly) return false; @@ -2431,7 +2367,7 @@ bool JSObject::increaseVectorLength(VM& vm, unsigned newLength) unsigned newIndexBias = std::min(indexBias >> 1, MAX_STORAGE_VECTOR_LENGTH - newVectorLength); Butterfly* newButterfly = storage->butterfly()->resizeArray( vm, this, - structure->outOfLineCapacity(), true, ArrayStorage::sizeFor(vectorLength), + structure()->outOfLineCapacity(), true, ArrayStorage::sizeFor(vectorLength), newIndexBias, true, ArrayStorage::sizeFor(newVectorLength)); if (!newButterfly) return false; @@ -2444,7 +2380,7 @@ bool JSObject::increaseVectorLength(VM& vm, unsigned newLength) void JSObject::ensureLengthSlow(VM& vm, unsigned length) { ASSERT(length < MAX_ARRAY_INDEX); - ASSERT(hasContiguous(indexingType()) || hasInt32(indexingType()) || hasDouble(indexingType()) || hasUndecided(indexingType())); + ASSERT(hasContiguous(structure()->indexingType()) || hasInt32(structure()->indexingType()) || hasDouble(structure()->indexingType()) || hasUndecided(structure()->indexingType())); ASSERT(length > m_butterfly->vectorLength()); unsigned newVectorLength = std::min( @@ -2459,27 +2395,12 @@ void JSObject::ensureLengthSlow(VM& vm, unsigned length) m_butterfly->setVectorLength(newVectorLength); - if (hasDouble(indexingType())) { + if (hasDouble(structure()->indexingType())) { for (unsigned i = oldVectorLength; i < newVectorLength; ++i) - m_butterfly->contiguousDouble().data()[i] = PNaN; + m_butterfly->contiguousDouble().data()[i] = QNaN; } } -void JSObject::reallocateAndShrinkButterfly(VM& vm, unsigned length) -{ - ASSERT(length < MAX_ARRAY_INDEX); - ASSERT(length < MAX_STORAGE_VECTOR_LENGTH); - ASSERT(hasContiguous(indexingType()) || hasInt32(indexingType()) || hasDouble(indexingType()) || hasUndecided(indexingType())); - ASSERT(m_butterfly->vectorLength() > length); - ASSERT(!m_butterfly->indexingHeader()->preCapacity(structure())); - - DeferGC deferGC(vm.heap); - Butterfly* newButterfly = m_butterfly->resizeArray(vm, this, structure(), 0, ArrayStorage::sizeFor(length)); - m_butterfly.set(vm, this, newButterfly); - m_butterfly->setVectorLength(length); - m_butterfly->setPublicLength(length); -} - Butterfly* JSObject::growOutOfLineStorage(VM& vm, size_t oldSize, size_t newSize) { ASSERT(newSize > oldSize); @@ -2487,21 +2408,19 @@ Butterfly* JSObject::growOutOfLineStorage(VM& vm, size_t oldSize, size_t newSize // 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 Butterfly::createOrGrowPropertyStorage(m_butterfly.get(), vm, this, structure(vm), oldSize, newSize); + return m_butterfly->growPropertyStorage(vm, this, structure(), oldSize, newSize); } bool JSObject::getOwnPropertyDescriptor(ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor) { JSC::PropertySlot slot(this); - if (!methodTable(exec->vm())->getOwnPropertySlot(this, exec, propertyName, slot)) + if (!methodTable()->getOwnPropertySlot(this, exec, propertyName, slot)) return false; /* Workaround, JSDOMWindow::getOwnPropertySlot searches the prototype chain. :-( */ - if (slot.slotBase() != this && slot.slotBase() && slot.slotBase()->methodTable(exec->vm())->toThis(slot.slotBase(), exec, NotStrictMode) != this) + if (slot.slotBase() != this && slot.slotBase() && slot.slotBase()->methodTable()->toThis(slot.slotBase(), exec, NotStrictMode) != this) return false; if (slot.isAccessor()) descriptor.setAccessorDescriptor(slot.getterSetter(), slot.attributes()); - else if (slot.attributes() & CustomAccessor) - descriptor.setCustomDescriptor(slot.attributes()); else descriptor.setDescriptor(slot.getValue(exec, propertyName), slot.attributes()); return true; @@ -2512,11 +2431,11 @@ static bool putDescriptor(ExecState* exec, JSObject* target, PropertyName proper VM& vm = exec->vm(); if (descriptor.isGenericDescriptor() || descriptor.isDataDescriptor()) { if (descriptor.isGenericDescriptor() && oldDescriptor.isAccessorDescriptor()) { - GetterSetter* accessor = GetterSetter::create(vm, exec->lexicalGlobalObject()); + GetterSetter* accessor = GetterSetter::create(vm); if (oldDescriptor.getterPresent()) - accessor->setGetter(vm, exec->lexicalGlobalObject(), oldDescriptor.getterObject()); + accessor->setGetter(vm, oldDescriptor.getterObject()); if (oldDescriptor.setterPresent()) - accessor->setSetter(vm, exec->lexicalGlobalObject(), oldDescriptor.setterObject()); + accessor->setSetter(vm, oldDescriptor.setterObject()); target->putDirectAccessor(exec, propertyName, accessor, attributes | Accessor); return true; } @@ -2527,20 +2446,20 @@ static bool putDescriptor(ExecState* exec, JSObject* target, PropertyName proper newValue = oldDescriptor.value(); target->putDirect(vm, propertyName, newValue, attributes & ~Accessor); if (attributes & ReadOnly) - target->structure(vm)->setContainsReadOnlyProperties(); + target->structure()->setContainsReadOnlyProperties(); return true; } attributes &= ~ReadOnly; - GetterSetter* accessor = GetterSetter::create(vm, exec->lexicalGlobalObject()); + GetterSetter* accessor = GetterSetter::create(vm); if (descriptor.getterPresent()) - accessor->setGetter(vm, exec->lexicalGlobalObject(), descriptor.getterObject()); + accessor->setGetter(vm, descriptor.getterObject()); else if (oldDescriptor.getterPresent()) - accessor->setGetter(vm, exec->lexicalGlobalObject(), oldDescriptor.getterObject()); + accessor->setGetter(vm, oldDescriptor.getterObject()); if (descriptor.setterPresent()) - accessor->setSetter(vm, exec->lexicalGlobalObject(), descriptor.setterObject()); + accessor->setSetter(vm, descriptor.setterObject()); else if (oldDescriptor.setterPresent()) - accessor->setSetter(vm, exec->lexicalGlobalObject(), oldDescriptor.setterObject()); + accessor->setSetter(vm, oldDescriptor.setterObject()); target->putDirectAccessor(exec, propertyName, accessor, attributes | Accessor); return true; @@ -2548,10 +2467,11 @@ static bool putDescriptor(ExecState* exec, JSObject* target, PropertyName proper void JSObject::putDirectMayBeIndex(ExecState* exec, PropertyName propertyName, JSValue value) { - if (Optional<uint32_t> index = parseIndex(propertyName)) - putDirectIndex(exec, index.value(), value); - else + unsigned asIndex = propertyName.asIndex(); + if (asIndex == PropertyName::NotAnIndex) putDirect(exec->vm(), propertyName, value); + else + putDirectIndex(exec, asIndex, value); } class DefineOwnPropertyScope { @@ -2603,7 +2523,7 @@ bool JSObject::defineOwnNonIndexProperty(ExecState* exec, PropertyName propertyN if (!current.configurable()) { if (descriptor.configurable()) { if (throwException) - exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change configurable attribute of unconfigurable property."))); + exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to configurable attribute of unconfigurable property."))); return false; } if (descriptor.enumerablePresent() && descriptor.enumerable() != current.enumerable()) { @@ -2616,7 +2536,7 @@ bool JSObject::defineOwnNonIndexProperty(ExecState* exec, PropertyName propertyN // A generic descriptor is simply changing the attributes of an existing property if (descriptor.isGenericDescriptor()) { if (!current.attributesEqual(descriptor)) { - methodTable(exec->vm())->deleteProperty(this, exec, propertyName); + methodTable()->deleteProperty(this, exec, propertyName); return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current); } return true; @@ -2629,7 +2549,7 @@ bool JSObject::defineOwnNonIndexProperty(ExecState* exec, PropertyName propertyN exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change access mechanism for an unconfigurable property."))); return false; } - methodTable(exec->vm())->deleteProperty(this, exec, propertyName); + methodTable()->deleteProperty(this, exec, propertyName); return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current); } @@ -2651,7 +2571,7 @@ bool JSObject::defineOwnNonIndexProperty(ExecState* exec, PropertyName propertyN } if (current.attributesEqual(descriptor) && !descriptor.value()) return true; - methodTable(exec->vm())->deleteProperty(this, exec, propertyName); + methodTable()->deleteProperty(this, exec, propertyName); return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current); } @@ -2668,34 +2588,18 @@ bool JSObject::defineOwnNonIndexProperty(ExecState* exec, PropertyName propertyN exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change the getter of an unconfigurable property."))); return false; } - if (current.attributes() & CustomAccessor) { - if (throwException) - exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change access mechanism for an unconfigurable property."))); - return false; - } } JSValue accessor = getDirect(exec->vm(), propertyName); if (!accessor) return false; - GetterSetter* getterSetter; - bool getterSetterChanged = false; - if (accessor.isCustomGetterSetter()) - getterSetter = GetterSetter::create(exec->vm(), exec->lexicalGlobalObject()); - else { - ASSERT(accessor.isGetterSetter()); - getterSetter = asGetterSetter(accessor); - } - if (descriptor.setterPresent()) { - getterSetter = getterSetter->withSetter(exec->vm(), exec->lexicalGlobalObject(), descriptor.setterObject()); - getterSetterChanged = true; - } - if (descriptor.getterPresent()) { - getterSetter = getterSetter->withGetter(exec->vm(), exec->lexicalGlobalObject(), descriptor.getterObject()); - getterSetterChanged = true; - } - if (current.attributesEqual(descriptor) && !getterSetterChanged) + GetterSetter* getterSetter = asGetterSetter(accessor); + if (descriptor.setterPresent()) + getterSetter->setSetter(exec->vm(), descriptor.setterObject()); + if (descriptor.getterPresent()) + getterSetter->setGetter(exec->vm(), descriptor.getterObject()); + if (current.attributesEqual(descriptor)) return true; - methodTable(exec->vm())->deleteProperty(this, exec, propertyName); + methodTable()->deleteProperty(this, exec, propertyName); unsigned attrs = descriptor.attributesOverridingCurrent(current); putDirectAccessor(exec, propertyName, getterSetter, attrs | Accessor); return true; @@ -2704,120 +2608,31 @@ bool JSObject::defineOwnNonIndexProperty(ExecState* exec, PropertyName propertyN bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException) { // If it's an array index, then use the indexed property storage. - if (Optional<uint32_t> index = parseIndex(propertyName)) { + unsigned index = propertyName.asIndex(); + if (index != PropertyName::NotAnIndex) { // c. Let succeeded be the result of calling the default [[DefineOwnProperty]] internal method (8.12.9) on A passing P, Desc, and false as arguments. // d. Reject if succeeded is false. // e. If index >= oldLen // e.i. Set oldLenDesc.[[Value]] to index + 1. // e.ii. Call the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", oldLenDesc, and false as arguments. This call will always return true. // f. Return true. - return object->defineOwnIndexedProperty(exec, index.value(), descriptor, throwException); + return object->defineOwnIndexedProperty(exec, index, descriptor, throwException); } return object->defineOwnNonIndexProperty(exec, propertyName, descriptor, throwException); } -JSObject* throwTypeError(ExecState* exec, const String& message) -{ - return exec->vm().throwException(exec, createTypeError(exec, message)); -} - -void JSObject::convertToDictionary(VM& vm) -{ - DeferredStructureTransitionWatchpointFire deferredWatchpointFire; - setStructure( - vm, Structure::toCacheableDictionaryTransition(vm, structure(vm), &deferredWatchpointFire)); -} - -void JSObject::shiftButterflyAfterFlattening(VM& vm, size_t outOfLineCapacityBefore, size_t outOfLineCapacityAfter) +bool JSObject::getOwnPropertySlotSlow(ExecState* exec, PropertyName propertyName, PropertySlot& slot) { - Butterfly* butterfly = this->butterfly(); - size_t preCapacity = this->butterflyPreCapacity(); - void* currentBase = butterfly->base(preCapacity, outOfLineCapacityAfter); - void* newBase = butterfly->base(preCapacity, outOfLineCapacityBefore); - - memmove(newBase, currentBase, this->butterflyTotalSize()); - setButterflyWithoutChangingStructure(vm, Butterfly::fromBase(newBase, preCapacity, outOfLineCapacityAfter)); -} - -uint32_t JSObject::getEnumerableLength(ExecState* exec, JSObject* object) -{ - VM& vm = exec->vm(); - Structure* structure = object->structure(vm); - if (structure->holesMustForwardToPrototype(vm)) - return 0; - switch (object->indexingType()) { - case ALL_BLANK_INDEXING_TYPES: - case ALL_UNDECIDED_INDEXING_TYPES: - return 0; - - case ALL_INT32_INDEXING_TYPES: - case ALL_CONTIGUOUS_INDEXING_TYPES: { - Butterfly* butterfly = object->butterfly(); - unsigned usedLength = butterfly->publicLength(); - for (unsigned i = 0; i < usedLength; ++i) { - if (!butterfly->contiguous()[i]) - return 0; - } - return usedLength; - } - - case ALL_DOUBLE_INDEXING_TYPES: { - Butterfly* butterfly = object->butterfly(); - unsigned usedLength = butterfly->publicLength(); - for (unsigned i = 0; i < usedLength; ++i) { - double value = butterfly->contiguousDouble()[i]; - if (value != value) - return 0; - } - return usedLength; - } - - case ALL_ARRAY_STORAGE_INDEXING_TYPES: { - ArrayStorage* storage = object->m_butterfly->arrayStorage(); - if (storage->m_sparseMap.get()) - return 0; - - unsigned usedVectorLength = std::min(storage->length(), storage->vectorLength()); - for (unsigned i = 0; i < usedVectorLength; ++i) { - if (!storage->m_vector[i]) - return 0; - } - return usedVectorLength; - } - - default: - RELEASE_ASSERT_NOT_REACHED(); - return 0; - } -} - -void JSObject::getStructurePropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) -{ - VM& vm = exec->vm(); - object->structure(vm)->getPropertyNamesFromStructure(vm, propertyNames, mode); + unsigned i = propertyName.asIndex(); + if (i != PropertyName::NotAnIndex) + return getOwnPropertySlotByIndex(this, exec, i, slot); + return false; } -void JSObject::getGenericPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +JSObject* throwTypeError(ExecState* exec, const String& message) { - VM& vm = exec->vm(); - object->methodTable(vm)->getOwnPropertyNames(object, exec, propertyNames, EnumerationMode(mode, JSObjectPropertiesMode::Exclude)); - - if (object->prototype().isNull()) - return; - - JSObject* prototype = asObject(object->prototype()); - while (true) { - if (prototype->structure(vm)->typeInfo().overridesGetPropertyNames()) { - prototype->methodTable(vm)->getPropertyNames(prototype, exec, propertyNames, mode); - break; - } - prototype->methodTable(vm)->getOwnPropertyNames(prototype, exec, propertyNames, mode); - JSValue nextProto = prototype->prototype(); - if (nextProto.isNull()) - break; - prototype = asObject(nextProto); - } + return exec->vm().throwException(exec, createTypeError(exec, message)); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h index 2c5b8f733..02b137b35 100644 --- a/Source/JavaScriptCore/runtime/JSObject.h +++ b/Source/JavaScriptCore/runtime/JSObject.h @@ -1,7 +1,7 @@ /* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003-2009, 2012-2015 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012, 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 Library General Public @@ -31,10 +31,8 @@ #include "ClassInfo.h" #include "CommonIdentifiers.h" #include "CopyWriteBarrier.h" -#include "CustomGetterSetter.h" #include "DeferGC.h" #include "Heap.h" -#include "HeapInlines.h" #include "IndexingHeaderInlines.h" #include "JSCell.h" #include "PropertySlot.h" @@ -52,21 +50,29 @@ namespace JSC { inline JSCell* getJSFunction(JSValue value) { - if (value.isCell() && (value.asCell()->type() == JSFunctionType)) + if (value.isCell() && (value.asCell()->structure()->typeInfo().type() == JSFunctionType)) return value.asCell(); return 0; } +JS_EXPORT_PRIVATE JSCell* getCallableObjectSlow(JSCell*); + +inline JSCell* getCallableObject(JSValue value) +{ + if (!value.isCell()) + return 0; + return getCallableObjectSlow(value.asCell()); +} + class GetterSetter; +class HashEntry; class InternalFunction; -class JSFunction; class LLIntOffsetsExtractor; class MarkedBlock; class PropertyDescriptor; class PropertyNameArray; class Structure; struct HashTable; -struct HashTableValue; JS_EXPORT_PRIVATE JSObject* throwTypeError(ExecState*, const String&); extern JS_EXPORTDATA const char* StrictModeReadonlyPropertyWriteError; @@ -86,7 +92,7 @@ class JSObject : public JSCell { friend class JSCell; friend class JSFinalObject; friend class MarkedBlock; - JS_EXPORT_PRIVATE friend bool setUpStaticFunctionSlot(ExecState*, const HashTableValue*, JSObject*, PropertyName, PropertySlot&); + JS_EXPORT_PRIVATE friend bool setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject*, PropertyName, PropertySlot&); enum PutMode { PutModePut, @@ -100,11 +106,10 @@ public: JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken); JS_EXPORT_PRIVATE static String className(const JSObject*); - JS_EXPORT_PRIVATE static String calculatedClassName(JSObject*); JSValue prototype() const; - JS_EXPORT_PRIVATE void setPrototype(VM&, JSValue prototype); - JS_EXPORT_PRIVATE bool setPrototypeWithCycleCheck(ExecState*, JSValue prototype); + void setPrototype(VM&, JSValue prototype); + bool setPrototypeWithCycleCheck(ExecState*, JSValue prototype); bool mayInterceptIndexedAccesses() { @@ -114,7 +119,7 @@ public: JSValue get(ExecState*, PropertyName) const; JSValue get(ExecState*, unsigned propertyName) const; - bool fastGetOwnPropertySlot(ExecState*, VM&, Structure&, PropertyName, PropertySlot&); + bool fastGetOwnPropertySlot(ExecState*, PropertyName, PropertySlot&); bool getPropertySlot(ExecState*, PropertyName, PropertySlot&); bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); @@ -124,20 +129,20 @@ public: // The key difference between this and getOwnPropertySlot is that getOwnPropertySlot // currently returns incorrect results for the DOM window (with non-own properties) // being returned. Once this is fixed we should migrate code & remove this method. - JS_EXPORT_PRIVATE bool getOwnPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&); + bool getOwnPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&); - JS_EXPORT_PRIVATE bool allowsAccessFrom(ExecState*); + bool allowsAccessFrom(ExecState*); unsigned getArrayLength() const { - if (!hasIndexedProperties(indexingType())) + if (!hasIndexedProperties(structure()->indexingType())) return 0; return m_butterfly->publicLength(); } unsigned getVectorLength() { - if (!hasIndexedProperties(indexingType())) + if (!hasIndexedProperties(structure()->indexingType())) return 0; return m_butterfly->vectorLength(); } @@ -145,13 +150,13 @@ public: JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); JS_EXPORT_PRIVATE static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); - ALWAYS_INLINE void putByIndexInline(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow) + void putByIndexInline(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow) { if (canSetIndexQuickly(propertyName)) { setIndexQuickly(exec->vm(), propertyName, value); return; } - methodTable(exec->vm())->putByIndex(this, exec, propertyName, value, shouldThrow); + methodTable()->putByIndex(this, exec, propertyName, value, shouldThrow); } // This is similar to the putDirect* methods: @@ -182,7 +187,7 @@ public: bool canGetIndexQuickly(unsigned i) { - switch (indexingType()) { + switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: case ALL_UNDECIDED_INDEXING_TYPES: return false; @@ -207,7 +212,7 @@ public: JSValue getIndexQuickly(unsigned i) { - switch (indexingType()) { + switch (structure()->indexingType()) { case ALL_INT32_INDEXING_TYPES: return jsNumber(m_butterfly->contiguous()[i].get().asInt32()); case ALL_CONTIGUOUS_INDEXING_TYPES: @@ -224,7 +229,7 @@ public: JSValue tryGetIndexQuickly(unsigned i) { - switch (indexingType()) { + switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: case ALL_UNDECIDED_INDEXING_TYPES: break; @@ -263,7 +268,7 @@ public: if (JSValue result = tryGetIndexQuickly(i)) return result; PropertySlot slot(this); - if (methodTable(exec->vm())->getOwnPropertySlotByIndex(this, exec, i, slot)) + if (methodTable()->getOwnPropertySlotByIndex(this, exec, i, slot)) return slot.getValue(exec, i); return JSValue(); } @@ -277,7 +282,7 @@ public: bool canSetIndexQuickly(unsigned i) { - switch (indexingType()) { + switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: case ALL_UNDECIDED_INDEXING_TYPES: return false; @@ -299,7 +304,7 @@ public: bool canSetIndexQuicklyForPutDirect(unsigned i) { - switch (indexingType()) { + switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: case ALL_UNDECIDED_INDEXING_TYPES: return false; @@ -316,7 +321,7 @@ public: void setIndexQuickly(VM& vm, unsigned i, JSValue v) { - switch (indexingType()) { + switch (structure()->indexingType()) { case ALL_INT32_INDEXING_TYPES: { ASSERT(i < m_butterfly->vectorLength()); if (!v.isInt32()) { @@ -364,15 +369,10 @@ public: RELEASE_ASSERT_NOT_REACHED(); } } - + void initializeIndex(VM& vm, unsigned i, JSValue v) { - initializeIndex(vm, i, v, indexingType()); - } - - void initializeIndex(VM& vm, unsigned i, JSValue v, IndexingType indexingType) - { - switch (indexingType) { + switch (structure()->indexingType()) { case ALL_UNDECIDED_INDEXING_TYPES: { setIndexQuicklyToUndecided(vm, i, v); break; @@ -421,7 +421,7 @@ public: bool hasSparseMap() { - switch (indexingType()) { + switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: case ALL_UNDECIDED_INDEXING_TYPES: case ALL_INT32_INDEXING_TYPES: @@ -429,7 +429,7 @@ public: case ALL_CONTIGUOUS_INDEXING_TYPES: return false; case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return !!m_butterfly->arrayStorage()->m_sparseMap; + return m_butterfly->arrayStorage()->m_sparseMap; default: RELEASE_ASSERT_NOT_REACHED(); return false; @@ -438,7 +438,7 @@ public: bool inSparseIndexingMode() { - switch (indexingType()) { + switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: case ALL_UNDECIDED_INDEXING_TYPES: case ALL_INT32_INDEXING_TYPES: @@ -465,15 +465,10 @@ public: void putDirectWithoutTransition(VM&, PropertyName, JSValue, unsigned attributes = 0); void putDirectNonIndexAccessor(VM&, PropertyName, JSValue, unsigned attributes); void putDirectAccessor(ExecState*, PropertyName, JSValue, unsigned attributes); - JS_EXPORT_PRIVATE void putDirectCustomAccessor(VM&, PropertyName, JSValue, unsigned attributes); - - void putGetter(ExecState*, PropertyName, JSValue); - void putSetter(ExecState*, PropertyName, JSValue); JS_EXPORT_PRIVATE bool hasProperty(ExecState*, PropertyName) const; JS_EXPORT_PRIVATE bool hasProperty(ExecState*, unsigned propertyName) const; bool hasOwnProperty(ExecState*, PropertyName) const; - bool hasOwnProperty(ExecState*, unsigned) const; JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName); JS_EXPORT_PRIVATE static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); @@ -487,10 +482,6 @@ public: JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - JS_EXPORT_PRIVATE static uint32_t getEnumerableLength(ExecState*, JSObject*); - JS_EXPORT_PRIVATE static void getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - JS_EXPORT_PRIVATE static void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const; bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const; JS_EXPORT_PRIVATE double toNumber(ExecState*) const; @@ -498,36 +489,36 @@ public: JS_EXPORT_PRIVATE static JSValue toThis(JSCell*, ExecState*, ECMAMode); + bool getPropertySpecificValue(ExecState*, PropertyName, JSCell*& specificFunction) const; + // This get function only looks at the property map. JSValue getDirect(VM& vm, PropertyName propertyName) const { - Structure* structure = this->structure(vm); - PropertyOffset offset = structure->get(vm, propertyName); - checkOffset(offset, structure->inlineCapacity()); + PropertyOffset offset = structure()->get(vm, propertyName); + checkOffset(offset, structure()->inlineCapacity()); return offset != invalidOffset ? getDirect(offset) : JSValue(); } - + JSValue getDirect(VM& vm, PropertyName propertyName, unsigned& attributes) const { - Structure* structure = this->structure(vm); - PropertyOffset offset = structure->get(vm, propertyName, attributes); - checkOffset(offset, structure->inlineCapacity()); + JSCell* specific; + PropertyOffset offset = structure()->get(vm, propertyName, attributes, specific); + checkOffset(offset, structure()->inlineCapacity()); return offset != invalidOffset ? getDirect(offset) : JSValue(); } PropertyOffset getDirectOffset(VM& vm, PropertyName propertyName) { - Structure* structure = this->structure(vm); - PropertyOffset offset = structure->get(vm, propertyName); - checkOffset(offset, structure->inlineCapacity()); + PropertyOffset offset = structure()->get(vm, propertyName); + checkOffset(offset, structure()->inlineCapacity()); return offset; } PropertyOffset getDirectOffset(VM& vm, PropertyName propertyName, unsigned& attributes) { - Structure* structure = this->structure(vm); - PropertyOffset offset = structure->get(vm, propertyName, attributes); - checkOffset(offset, structure->inlineCapacity()); + JSCell* specific; + PropertyOffset offset = structure()->get(vm, propertyName, attributes, specific); + checkOffset(offset, structure()->inlineCapacity()); return offset; } @@ -573,16 +564,15 @@ public: void transitionTo(VM&, Structure*); - JS_EXPORT_PRIVATE bool removeDirect(VM&, 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(); } - bool hasCustomGetterSetterProperties() { return structure()->hasCustomGetterSetterProperties(); } // putOwnDataProperty has 'put' like semantics, however this method: // - assumes the object contains no own getter/setter properties. // - provides no special handling for __proto__ // - does not walk the prototype chain (to check for accessors or non-writable properties). - // This is used by JSLexicalEnvironment. + // This is used by JSActivation. bool putOwnDataProperty(VM&, PropertyName, JSValue, PutPropertySlot&); // Fast access to known property offsets. @@ -590,10 +580,8 @@ public: void putDirect(VM& vm, PropertyOffset offset, JSValue value) { locationForOffset(offset)->set(vm, this, value); } void putDirectUndefined(PropertyOffset offset) { locationForOffset(offset)->setUndefined(); } - JS_EXPORT_PRIVATE void putDirectNativeFunction(VM&, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, unsigned attributes); - JS_EXPORT_PRIVATE JSFunction* putDirectBuiltinFunction(VM&, JSGlobalObject*, const PropertyName&, FunctionExecutable*, unsigned attributes); - JSFunction* putDirectBuiltinFunctionWithoutTransition(VM&, JSGlobalObject*, const PropertyName&, FunctionExecutable*, unsigned attributes); - JS_EXPORT_PRIVATE void putDirectNativeFunctionWithoutTransition(VM&, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, unsigned attributes); + void putDirectNativeFunction(VM&, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, unsigned attributes); + void putDirectNativeFunctionWithoutTransition(VM&, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, unsigned attributes); JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow); @@ -603,13 +591,12 @@ public: bool isNameScopeObject() const; bool isActivationObject() const; bool isErrorInstance() const; - bool isWithScope() const; - JS_EXPORT_PRIVATE void seal(VM&); - JS_EXPORT_PRIVATE void freeze(VM&); + void seal(VM&); + void freeze(VM&); JS_EXPORT_PRIVATE void preventExtensions(VM&); - bool isSealed(VM& vm) { return structure(vm)->isSealed(vm); } - bool isFrozen(VM& vm) { return structure(vm)->isFrozen(vm); } + bool isSealed(VM& vm) { return structure()->isSealed(vm); } + bool isFrozen(VM& vm) { return structure()->isFrozen(vm); } bool isExtensible() { return structure()->isExtensible(); } bool indexingShouldBeSparse() { @@ -628,13 +615,10 @@ public: void setStructureAndReallocateStorageIfNecessary(VM&, unsigned oldCapacity, Structure*); void setStructureAndReallocateStorageIfNecessary(VM&, Structure*); - JS_EXPORT_PRIVATE void convertToDictionary(VM&); - void flattenDictionaryObject(VM& vm) { - structure(vm)->flattenDictionaryStructure(vm, this); + structure()->flattenDictionaryStructure(vm, this); } - void shiftButterflyAfterFlattening(VM&, size_t outOfLineCapacityBefore, size_t outOfLineCapacityAfter); JSGlobalObject* globalObject() const { @@ -660,7 +644,7 @@ public: // contiguous, array storage). ContiguousJSValues ensureInt32(VM& vm) { - if (LIKELY(hasInt32(indexingType()))) + if (LIKELY(hasInt32(structure()->indexingType()))) return m_butterfly->contiguousInt32(); return ensureInt32Slow(vm); @@ -672,7 +656,7 @@ public: // or array storage). ContiguousDoubles ensureDouble(VM& vm) { - if (LIKELY(hasDouble(indexingType()))) + if (LIKELY(hasDouble(structure()->indexingType()))) return m_butterfly->contiguousDouble(); return ensureDoubleSlow(vm); @@ -682,21 +666,32 @@ public: // indexing should be sparse or because we're having a bad time. ContiguousJSValues ensureContiguous(VM& vm) { - if (LIKELY(hasContiguous(indexingType()))) + if (LIKELY(hasContiguous(structure()->indexingType()))) return m_butterfly->contiguous(); 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(VM& vm) { - if (LIKELY(hasAnyArrayStorage(indexingType()))) + if (LIKELY(hasArrayStorage(structure()->indexingType()))) return m_butterfly->arrayStorage(); - + return ensureArrayStorageSlow(vm); } @@ -719,6 +714,8 @@ protected: { Base::finishCreation(vm); ASSERT(inherits(info())); + ASSERT(!structure()->outOfLineCapacity()); + ASSERT(structure()->isEmpty()); ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype())); ASSERT(structure()->isObject()); ASSERT(classInfo()); @@ -740,7 +737,7 @@ protected: // storage. This will assert otherwise. ArrayStorage* arrayStorage() { - ASSERT(hasAnyArrayStorage(indexingType())); + ASSERT(hasArrayStorage(structure()->indexingType())); return m_butterfly->arrayStorage(); } @@ -748,7 +745,7 @@ protected: // object is in a mode where it has array storage. ArrayStorage* arrayStorageOrNull() { - switch (indexingType()) { + switch (structure()->indexingType()) { case ALL_ARRAY_STORAGE_INDEXING_TYPES: return m_butterfly->arrayStorage(); @@ -757,9 +754,6 @@ protected: } } - size_t butterflyTotalSize(); - size_t butterflyPreCapacity(); - Butterfly* createInitialUndecided(VM&, unsigned length); ContiguousJSValues createInitialInt32(VM&, unsigned length); ContiguousDoubles createInitialDouble(VM&, unsigned length); @@ -775,18 +769,23 @@ protected: ContiguousJSValues convertUndecidedToInt32(VM&); ContiguousDoubles convertUndecidedToDouble(VM&); ContiguousJSValues convertUndecidedToContiguous(VM&); + ArrayStorage* convertUndecidedToArrayStorage(VM&, NonPropertyTransition, unsigned neededLength); ArrayStorage* convertUndecidedToArrayStorage(VM&, NonPropertyTransition); ArrayStorage* convertUndecidedToArrayStorage(VM&); 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(VM&, NonPropertyTransition, unsigned neededLength); ArrayStorage* convertContiguousToArrayStorage(VM&, NonPropertyTransition); ArrayStorage* convertContiguousToArrayStorage(VM&); @@ -813,7 +812,7 @@ protected: void ensureLength(VM& vm, unsigned length) { ASSERT(length < MAX_ARRAY_INDEX); - ASSERT(hasContiguous(indexingType()) || hasInt32(indexingType()) || hasDouble(indexingType()) || hasUndecided(indexingType())); + ASSERT(hasContiguous(structure()->indexingType()) || hasInt32(structure()->indexingType()) || hasDouble(structure()->indexingType()) || hasUndecided(structure()->indexingType())); if (m_butterfly->vectorLength() < length) ensureLengthSlow(vm, length); @@ -822,16 +821,109 @@ protected: m_butterfly->setPublicLength(length); } - // Call this if you want to shrink the butterfly backing store, and you're - // sure that the array is contiguous. - void reallocateAndShrinkButterfly(VM&, unsigned length); - template<IndexingType indexingShape> unsigned countElements(Butterfly*); // This is relevant to undecided, int32, double, and contiguous. unsigned countElements(); + // This strange method returns a pointer to the start of the indexed data + // 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> + ContiguousJSValues indexingData() + { + switch (indexingType) { + case ALL_INT32_INDEXING_TYPES: + case ALL_DOUBLE_INDEXING_TYPES: + case ALL_CONTIGUOUS_INDEXING_TYPES: + return m_butterfly->contiguous(); + + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return m_butterfly->arrayStorage()->vector(); + + default: + CRASH(); + return ContiguousJSValues(); + } + } + + ContiguousJSValues currentIndexingData() + { + switch (structure()->indexingType()) { + case ALL_INT32_INDEXING_TYPES: + case ALL_CONTIGUOUS_INDEXING_TYPES: + return m_butterfly->contiguous(); + + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return m_butterfly->arrayStorage()->vector(); + + default: + CRASH(); + return ContiguousJSValues(); + } + } + + JSValue getHolyIndexQuickly(unsigned i) + { + ASSERT(i < m_butterfly->vectorLength()); + switch (structure()->indexingType()) { + case ALL_INT32_INDEXING_TYPES: + case ALL_CONTIGUOUS_INDEXING_TYPES: + return m_butterfly->contiguous()[i].get(); + case ALL_DOUBLE_INDEXING_TYPES: { + double value = m_butterfly->contiguousDouble()[i]; + if (value == value) + return JSValue(JSValue::EncodeAsDouble, value); + return JSValue(); + } + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return m_butterfly->arrayStorage()->m_vector[i].get(); + default: + CRASH(); + return JSValue(); + } + } + + template<IndexingType indexingType> + unsigned relevantLength() + { + switch (indexingType) { + case ALL_INT32_INDEXING_TYPES: + case ALL_DOUBLE_INDEXING_TYPES: + case ALL_CONTIGUOUS_INDEXING_TYPES: + return m_butterfly->publicLength(); + + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return std::min( + m_butterfly->arrayStorage()->length(), + m_butterfly->arrayStorage()->vectorLength()); + + default: + CRASH(); + return 0; + } + } + + unsigned currentRelevantLength() + { + switch (structure()->indexingType()) { + case ALL_INT32_INDEXING_TYPES: + case ALL_DOUBLE_INDEXING_TYPES: + case ALL_CONTIGUOUS_INDEXING_TYPES: + return m_butterfly->publicLength(); + + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return std::min( + m_butterfly->arrayStorage()->length(), + m_butterfly->arrayStorage()->vectorLength()); + + default: + CRASH(); + return 0; + } + } + private: friend class LLIntOffsetsExtractor; @@ -848,13 +940,12 @@ private: ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(VM&, ArrayStorage*); template<PutMode> - bool putDirectInternal(VM&, PropertyName, JSValue, unsigned attr, PutPropertySlot&); + bool putDirectInternal(VM&, PropertyName, JSValue, unsigned attr, PutPropertySlot&, JSCell*); - bool inlineGetOwnPropertySlot(VM&, Structure&, PropertyName, PropertySlot&); + bool inlineGetOwnPropertySlot(ExecState*, PropertyName, PropertySlot&); JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&, JSValue, unsigned, PropertyOffset); - void fillCustomGetterPropertySlot(PropertySlot&, JSValue, unsigned, Structure&); - const HashTableValue* findPropertyHashEntry(PropertyName) const; + const HashEntry* findPropertyHashEntry(ExecState*, PropertyName) const; void putIndexedDescriptor(ExecState*, SparseArrayEntry*, const PropertyDescriptor&, PropertyDescriptor& old); @@ -865,6 +956,8 @@ private: unsigned getNewVectorLength(unsigned currentVectorLength, unsigned currentLength, unsigned desiredLength); unsigned getNewVectorLength(unsigned desiredLength); + JS_EXPORT_PRIVATE bool getOwnPropertySlotSlow(ExecState*, PropertyName, PropertySlot&); + ArrayStorage* constructConvertedArrayStorageWithoutCopyingElements(VM&, unsigned neededLength); JS_EXPORT_PRIVATE void setIndexQuicklyToUndecided(VM&, unsigned index, JSValue); @@ -876,14 +969,16 @@ private: ContiguousJSValues ensureInt32Slow(VM&); ContiguousDoubles ensureDoubleSlow(VM&); ContiguousJSValues ensureContiguousSlow(VM&); - JS_EXPORT_PRIVATE ArrayStorage* ensureArrayStorageSlow(VM&); - + ContiguousJSValues rageEnsureContiguousSlow(VM&); + ArrayStorage* ensureArrayStorageSlow(VM&); + + enum DoubleToContiguousMode { EncodeValueAsDouble, RageConvertDoubleToValue }; + template<DoubleToContiguousMode mode> + ContiguousJSValues genericConvertDoubleToContiguous(VM&); + ContiguousJSValues ensureContiguousSlow(VM&, DoubleToContiguousMode); + protected: CopyWriteBarrier<Butterfly> m_butterfly; -#if USE(JSVALUE32_64) -private: - uint32_t m_padding; -#endif }; // JSNonFinalObject is a type of JSObject that has some internal storage, @@ -909,7 +1004,7 @@ protected: void finishCreation(VM& vm) { Base::finishCreation(vm); - ASSERT(!this->structure()->hasInlineStorage()); + ASSERT(!this->structure()->totalStorageCapacity()); ASSERT(classInfo()); } }; @@ -923,7 +1018,6 @@ class JSFinalObject : public JSObject { public: typedef JSObject Base; - static const unsigned StructureFlags = Base::StructureFlags; static size_t allocationSize(size_t inlineCapacity) { @@ -942,7 +1036,7 @@ public: return (maxSize - allocationSize(0)) / sizeof(WriteBarrier<Unknown>); } - static JSFinalObject* create(ExecState*, Structure*, Butterfly* = nullptr); + static JSFinalObject* create(ExecState*, Structure*); static JSFinalObject* create(VM&, Structure*); static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, unsigned inlineCapacity) { @@ -966,14 +1060,15 @@ protected: private: friend class LLIntOffsetsExtractor; - explicit JSFinalObject(VM& vm, Structure* structure, Butterfly* butterfly = nullptr) - : JSObject(vm, structure, butterfly) + explicit JSFinalObject(VM& vm, Structure* structure) + : JSObject(vm, structure) { } + + static const unsigned StructureFlags = JSObject::StructureFlags; }; -inline JSFinalObject* JSFinalObject::create( - ExecState* exec, Structure* structure, Butterfly* butterfly) +inline JSFinalObject* JSFinalObject::create(ExecState* exec, Structure* structure) { JSFinalObject* finalObject = new ( NotNull, @@ -981,7 +1076,7 @@ inline JSFinalObject* JSFinalObject::create( *exec->heap(), allocationSize(structure->inlineCapacity()) ) - ) JSFinalObject(exec->vm(), structure, butterfly); + ) JSFinalObject(exec->vm(), structure); finalObject->finishCreation(exec->vm()); return finalObject; } @@ -1010,38 +1105,35 @@ inline size_t JSObject::offsetOfInlineStorage() inline bool JSObject::isGlobalObject() const { - return type() == GlobalObjectType; + return structure()->typeInfo().type() == GlobalObjectType; } inline bool JSObject::isVariableObject() const { - return type() == GlobalObjectType || type() == ActivationObjectType; + return structure()->typeInfo().type() >= VariableObjectType; } + inline bool JSObject::isStaticScopeObject() const { - JSType type = this->type(); + JSType type = structure()->typeInfo().type(); return type == NameScopeObjectType || type == ActivationObjectType; } + inline bool JSObject::isNameScopeObject() const { - return type() == NameScopeObjectType; + return structure()->typeInfo().type() == NameScopeObjectType; } inline bool JSObject::isActivationObject() const { - return type() == ActivationObjectType; + return structure()->typeInfo().type() == ActivationObjectType; } inline bool JSObject::isErrorInstance() const { - return type() == ErrorInstanceType; -} - -inline bool JSObject::isWithScope() const -{ - return type() == WithScopeType; + return structure()->typeInfo().type() == ErrorInstanceType; } inline void JSObject::setStructureAndButterfly(VM& vm, Structure* structure, Butterfly* butterfly) @@ -1101,31 +1193,21 @@ inline JSValue JSObject::prototype() const return structure()->storedPrototype(); } -ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(VM& vm, Structure& structure, PropertyName propertyName, PropertySlot& slot) +ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot) { unsigned attributes; - PropertyOffset offset = structure.get(vm, propertyName, attributes); - if (!isValidOffset(offset)) - return false; - - JSValue value = getDirect(offset); - if (structure.hasGetterSetterProperties() && value.isGetterSetter()) - fillGetterPropertySlot(slot, value, attributes, offset); - else if (structure.hasCustomGetterSetterProperties() && value.isCustomGetterSetter()) - fillCustomGetterPropertySlot(slot, value, attributes, structure); - else - slot.setValue(this, attributes, value, offset); - - return true; -} - -ALWAYS_INLINE void JSObject::fillCustomGetterPropertySlot(PropertySlot& slot, JSValue customGetterSetter, unsigned attributes, Structure& structure) -{ - if (structure.isDictionary()) { - slot.setCustom(this, attributes, jsCast<CustomGetterSetter*>(customGetterSetter)->getter()); - return; + JSCell* specific; + PropertyOffset offset = structure()->get(exec->vm(), propertyName, attributes, specific); + if (LIKELY(isValidOffset(offset))) { + JSValue value = getDirect(offset); + if (structure()->hasGetterSetterProperties() && value.isGetterSetter()) + fillGetterPropertySlot(slot, value, attributes, offset); + else + slot.setValue(this, attributes, value, offset); + return true; } - slot.setCacheableCustom(this, attributes, jsCast<CustomGetterSetter*>(customGetterSetter)->getter()); + + return getOwnPropertySlotSlow(exec, propertyName, slot); } // It may seem crazy to inline a function this large, especially a virtual function, @@ -1133,54 +1215,38 @@ ALWAYS_INLINE void JSObject::fillCustomGetterPropertySlot(PropertySlot& slot, JS // base class call to this. ALWAYS_INLINE bool JSObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { - VM& vm = exec->vm(); - Structure& structure = *object->structure(vm); - if (object->inlineGetOwnPropertySlot(vm, structure, propertyName, slot)) - return true; - if (Optional<uint32_t> index = parseIndex(propertyName)) - return getOwnPropertySlotByIndex(object, exec, index.value(), slot); - return false; + return object->inlineGetOwnPropertySlot(exec, propertyName, slot); } -ALWAYS_INLINE bool JSObject::fastGetOwnPropertySlot(ExecState* exec, VM& vm, Structure& structure, PropertyName propertyName, PropertySlot& slot) +ALWAYS_INLINE bool JSObject::fastGetOwnPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot) { - if (LIKELY(!TypeInfo::overridesGetOwnPropertySlot(inlineTypeFlags()))) - return inlineGetOwnPropertySlot(vm, structure, propertyName, slot); - return structure.classInfo()->methodTable.getOwnPropertySlot(this, exec, propertyName, slot); + if (!structure()->typeInfo().overridesGetOwnPropertySlot()) + return asObject(this)->inlineGetOwnPropertySlot(exec, propertyName, slot); + return methodTable()->getOwnPropertySlot(this, exec, propertyName, slot); } // 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) { - VM& vm = exec->vm(); - auto& structureIDTable = vm.heap.structureIDTable(); JSObject* object = this; while (true) { - Structure& structure = *structureIDTable.get(object->structureID()); - if (object->fastGetOwnPropertySlot(exec, vm, structure, propertyName, slot)) + if (object->fastGetOwnPropertySlot(exec, propertyName, slot)) return true; - JSValue prototype = structure.storedPrototype(); + JSValue prototype = object->prototype(); if (!prototype.isObject()) - break; + return false; object = asObject(prototype); } - - if (Optional<uint32_t> index = parseIndex(propertyName)) - return getPropertySlot(exec, index.value(), slot); - return false; } ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) { - VM& vm = exec->vm(); - auto& structureIDTable = vm.heap.structureIDTable(); JSObject* object = this; while (true) { - Structure& structure = *structureIDTable.get(object->structureID()); - if (structure.classInfo()->methodTable.getOwnPropertySlotByIndex(object, exec, propertyName, slot)) + if (object->methodTable()->getOwnPropertySlotByIndex(object, exec, propertyName, slot)) return true; - JSValue prototype = structure.storedPrototype(); + JSValue prototype = object->prototype(); if (!prototype.isObject()) return false; object = asObject(prototype); @@ -1206,29 +1272,34 @@ inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const } template<JSObject::PutMode mode> -inline bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot) +inline bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot, JSCell* specificFunction) { ASSERT(value); ASSERT(value.isGetterSetter() == !!(attributes & Accessor)); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); - ASSERT(!parseIndex(propertyName)); + ASSERT(propertyName.asIndex() == PropertyName::NotAnIndex); - Structure* structure = this->structure(vm); - if (structure->isDictionary()) { + if (structure()->isDictionary()) { unsigned currentAttributes; - PropertyOffset offset = structure->get(vm, propertyName, currentAttributes); + JSCell* 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(vm, propertyName); if ((mode == PutModePut) && currentAttributes & ReadOnly) return false; putDirect(vm, offset, value); - structure->didReplaceProperty(offset); - slot.setExistingProperty(this, offset); - - if ((attributes & Accessor) != (currentAttributes & Accessor)) { - ASSERT(!(attributes & ReadOnly)); - setStructure(vm, Structure::attributeChangeTransition(vm, structure, propertyName, attributes)); - } + // 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 + // value is different (or there is no new value), then the slot now has no value - and + // as such it is cachable. + // If there was previously a value, and the new value is the same, then we cannot cache. + if (!currentSpecificFunction || (specificFunction != currentSpecificFunction)) + slot.setExistingProperty(this, offset); return true; } @@ -1237,23 +1308,25 @@ inline bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSVal DeferGC deferGC(vm.heap); Butterfly* newButterfly = butterfly(); - if (this->structure()->putWillGrowOutOfLineStorage()) - newButterfly = growOutOfLineStorage(vm, this->structure()->outOfLineCapacity(), this->structure()->suggestedNewOutOfLineStorageCapacity()); - offset = this->structure()->addPropertyWithoutTransition(vm, propertyName, attributes); - setStructureAndButterfly(vm, this->structure(), newButterfly); + if (structure()->putWillGrowOutOfLineStorage()) + newButterfly = growOutOfLineStorage(vm, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity()); + offset = structure()->addPropertyWithoutTransition(vm, propertyName, attributes, specificFunction); + setStructureAndButterfly(vm, structure(), newButterfly); validateOffset(offset); - ASSERT(this->structure()->isValidOffset(offset)); + ASSERT(structure()->isValidOffset(offset)); putDirect(vm, offset, value); - slot.setNewProperty(this, offset); + // See comment on setNewProperty call below. + if (!specificFunction) + slot.setNewProperty(this, offset); if (attributes & ReadOnly) - this->structure()->setContainsReadOnlyProperties(); + structure()->setContainsReadOnlyProperties(); return true; } PropertyOffset offset; - size_t currentCapacity = this->structure()->outOfLineCapacity(); - if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, offset)) { + size_t currentCapacity = structure()->outOfLineCapacity(); + if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, specificFunction, offset)) { DeferGC deferGC(vm.heap); Butterfly* newButterfly = butterfly(); if (currentCapacity != structure->outOfLineCapacity()) { @@ -1265,43 +1338,59 @@ inline bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSVal ASSERT(structure->isValidOffset(offset)); setStructureAndButterfly(vm, structure, newButterfly); putDirect(vm, offset, value); - slot.setNewProperty(this, offset); + // This is a new property; transitions with specific values are not currently cachable, + // so leave the slot in an uncachable state. + if (!specificFunction) + slot.setNewProperty(this, offset); return true; } unsigned currentAttributes; - offset = structure->get(vm, propertyName, currentAttributes); + JSCell* currentSpecificFunction; + offset = structure()->get(vm, propertyName, currentAttributes, currentSpecificFunction); if (offset != invalidOffset) { if ((mode == PutModePut) && currentAttributes & ReadOnly) return false; - structure->didReplaceProperty(offset); + // There are three possibilities here: + // (1) There is an existing specific value set, and we're overwriting with *the same value*. + // * Do nothing - no need to despecify, but that means we can't cache (a cached + // put could write a different value). Leave the slot in an uncachable state. + // (2) There is a specific value currently set, but we're writing a different value. + // * First, we have to despecify. Having done so, this is now a regular slot + // with no specific value, so go ahead & cache like normal. + // (3) Normal case, there is no specific value set. + // * Go ahead & cache like normal. + if (currentSpecificFunction) { + // case (1) Do the put, then return leaving the slot uncachable. + if (specificFunction == currentSpecificFunction) { + putDirect(vm, offset, value); + return true; + } + // case (2) Despecify, fall through to (3). + setStructure(vm, Structure::despecifyFunctionTransition(vm, structure(), propertyName)); + } + + // case (3) set the slot, do the put, return. slot.setExistingProperty(this, offset); putDirect(vm, offset, value); - - if ((attributes & Accessor) != (currentAttributes & Accessor)) { - ASSERT(!(attributes & ReadOnly)); - setStructure(vm, Structure::attributeChangeTransition(vm, structure, propertyName, attributes)); - } return true; } if ((mode == PutModePut) && !isExtensible()) return false; - // We want the structure transition watchpoint to fire after this object has switched - // structure. This allows adaptive watchpoints to observe if the new structure is the one - // we want. - DeferredStructureTransitionWatchpointFire deferredWatchpointFire; - - structure = Structure::addPropertyTransition(vm, structure, propertyName, attributes, offset, slot.context(), &deferredWatchpointFire); + Structure* structure = Structure::addPropertyTransition(vm, this->structure(), propertyName, attributes, specificFunction, offset, slot.context()); validateOffset(offset); ASSERT(structure->isValidOffset(offset)); setStructureAndReallocateStorageIfNecessary(vm, structure); putDirect(vm, offset, value); - slot.setNewProperty(this, offset); + // This is a new property; transitions with specific values are not currently cachable, + // so leave the slot in an uncachable state. + if (!specificFunction) + slot.setNewProperty(this, offset); if (attributes & ReadOnly) structure->setContainsReadOnlyProperties(); return true; @@ -1325,7 +1414,7 @@ inline void JSObject::setStructureAndReallocateStorageIfNecessary(VM& vm, unsign inline void JSObject::setStructureAndReallocateStorageIfNecessary(VM& vm, Structure* newStructure) { setStructureAndReallocateStorageIfNecessary( - vm, structure(vm)->outOfLineCapacity(), newStructure); + vm, structure()->outOfLineCapacity(), newStructure); } inline bool JSObject::putOwnDataProperty(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot) @@ -1333,35 +1422,31 @@ inline bool JSObject::putOwnDataProperty(VM& vm, PropertyName propertyName, JSVa ASSERT(value); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); ASSERT(!structure()->hasGetterSetterProperties()); - ASSERT(!structure()->hasCustomGetterSetterProperties()); - return putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot); + return putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot, getCallableObject(value)); } inline void JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes) { ASSERT(!value.isGetterSetter() && !(attributes & Accessor)); - ASSERT(!value.isCustomGetterSetter()); PutPropertySlot slot(this); - putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot); + putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot, getCallableObject(value)); } inline void JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { ASSERT(!value.isGetterSetter()); - ASSERT(!value.isCustomGetterSetter()); - putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, 0, slot); + putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, 0, slot, getCallableObject(value)); } inline void JSObject::putDirectWithoutTransition(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes) { DeferGC deferGC(vm.heap); ASSERT(!value.isGetterSetter() && !(attributes & Accessor)); - ASSERT(!value.isCustomGetterSetter()); Butterfly* newButterfly = m_butterfly.get(); if (structure()->putWillGrowOutOfLineStorage()) newButterfly = growOutOfLineStorage(vm, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity()); - PropertyOffset offset = structure()->addPropertyWithoutTransition(vm, propertyName, attributes); + PropertyOffset offset = structure()->addPropertyWithoutTransition(vm, propertyName, attributes, getCallableObject(value)); setStructureAndButterfly(vm, structure(), newButterfly); putDirect(vm, offset, value); } @@ -1371,15 +1456,18 @@ inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType pre return methodTable()->defaultValue(this, exec, preferredType); } -ALWAYS_INLINE JSObject* Register::object() const +ALWAYS_INLINE JSObject* Register::function() const { + if (!jsValue()) + return 0; return asObject(jsValue()); } -ALWAYS_INLINE Register& Register::operator=(JSObject* object) +ALWAYS_INLINE Register Register::withCallee(JSObject* callee) { - u.value = JSValue::encode(JSValue(object)); - return *this; + Register r; + r = JSValue(callee); + return r; } inline size_t offsetInButterfly(PropertyOffset offset) @@ -1387,32 +1475,6 @@ inline size_t offsetInButterfly(PropertyOffset offset) return offsetInOutOfLineStorage(offset) + Butterfly::indexOfPropertyStorage(); } -inline size_t JSObject::butterflyPreCapacity() -{ - if (UNLIKELY(hasIndexingHeader())) - return butterfly()->indexingHeader()->preCapacity(structure()); - return 0; -} - -inline size_t JSObject::butterflyTotalSize() -{ - Structure* structure = this->structure(); - Butterfly* butterfly = this->butterfly(); - size_t preCapacity; - size_t indexingPayloadSizeInBytes; - bool hasIndexingHeader = this->hasIndexingHeader(); - - if (UNLIKELY(hasIndexingHeader)) { - preCapacity = butterfly->indexingHeader()->preCapacity(structure); - indexingPayloadSizeInBytes = butterfly->indexingHeader()->indexingPayloadSizeInBytes(structure); - } else { - preCapacity = 0; - indexingPayloadSizeInBytes = 0; - } - - return Butterfly::totalSize(preCapacity, structure->outOfLineCapacity(), hasIndexingHeader, indexingPayloadSizeInBytes); -} - // 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. @@ -1454,7 +1516,7 @@ COMPILE_ASSERT(!(sizeof(JSObject) % sizeof(WriteBarrierBase<Unknown>)), JSObject ALWAYS_INLINE Identifier makeIdentifier(VM& vm, const char* name) { - return Identifier::fromString(&vm, name); + return Identifier(&vm, name); } ALWAYS_INLINE Identifier makeIdentifier(VM&, const Identifier& name) @@ -1476,11 +1538,27 @@ ALWAYS_INLINE Identifier makeIdentifier(VM&, const Identifier& name) #define JSC_NATIVE_FUNCTION(jsName, cppName, attributes, length) \ JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, (attributes), (length), NoIntrinsic) -// Identical helpers but for builtins. Note that currently, we don't support builtins that are -// also intrinsics, but we probably will do that eventually. -#define JSC_BUILTIN_FUNCTION(jsName, generatorName, attributes) \ - putDirectBuiltinFunction(\ - vm, globalObject, makeIdentifier(vm, (jsName)), (generatorName)(vm), (attributes)) +ALWAYS_INLINE JSValue PropertySlot::getValue(ExecState* exec, PropertyName propertyName) const +{ + if (m_propertyType == TypeValue) + return JSValue::decode(m_data.value); + if (m_propertyType == TypeCustomIndex) + return JSValue::decode(m_data.customIndex.getIndexValue(exec, JSValue::encode(slotBase()), JSValue::encode(m_thisValue), m_data.customIndex.index)); + if (m_propertyType == TypeGetter) + return functionGetter(exec); + return JSValue::decode(m_data.custom.getValue(exec, JSValue::encode(slotBase()), JSValue::encode(m_thisValue), propertyName)); +} + +ALWAYS_INLINE JSValue PropertySlot::getValue(ExecState* exec, unsigned propertyName) const +{ + if (m_propertyType == TypeValue) + return JSValue::decode(m_data.value); + if (m_propertyType == TypeCustomIndex) + return JSValue::decode(m_data.customIndex.getIndexValue(exec, JSValue::encode(slotBase()), JSValue::encode(m_thisValue), m_data.customIndex.index)); + if (m_propertyType == TypeGetter) + return functionGetter(exec); + return JSValue::decode(m_data.custom.getValue(exec, JSValue::encode(slotBase()), JSValue::encode(m_thisValue), Identifier::from(exec, propertyName))); +} } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSPromise.cpp b/Source/JavaScriptCore/runtime/JSPromise.cpp index 2531976b5..9f182c954 100644 --- a/Source/JavaScriptCore/runtime/JSPromise.cpp +++ b/Source/JavaScriptCore/runtime/JSPromise.cpp @@ -26,22 +26,27 @@ #include "config.h" #include "JSPromise.h" +#if ENABLE(PROMISES) + #include "Error.h" #include "JSCJSValueInlines.h" #include "JSCellInlines.h" #include "JSPromiseConstructor.h" +#include "JSPromiseReaction.h" #include "Microtask.h" #include "SlotVisitorInlines.h" #include "StructureInlines.h" namespace JSC { -const ClassInfo JSPromise::s_info = { "Promise", &Base::s_info, 0, CREATE_METHOD_TABLE(JSPromise) }; +static void triggerPromiseReactions(VM&, JSGlobalObject*, Vector<WriteBarrier<JSPromiseReaction>>&, JSValue); + +const ClassInfo JSPromise::s_info = { "Promise", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSPromise) }; -JSPromise* JSPromise::create(VM& vm, JSGlobalObject* globalObject) +JSPromise* JSPromise::create(VM& vm, JSGlobalObject* globalObject, JSPromiseConstructor* constructor) { JSPromise* promise = new (NotNull, allocateCell<JSPromise>(vm.heap)) JSPromise(vm, globalObject->promiseStructure()); - promise->finishCreation(vm); + promise->finishCreation(vm, constructor); return promise; } @@ -51,29 +56,116 @@ Structure* JSPromise::createStructure(VM& vm, JSGlobalObject* globalObject, JSVa } JSPromise::JSPromise(VM& vm, Structure* structure) - : JSNonFinalObject(vm, structure) + : JSDestructibleObject(vm, structure) + , m_status(Status::Unresolved) { } -void JSPromise::finishCreation(VM& vm) +void JSPromise::finishCreation(VM& vm, JSPromiseConstructor* constructor) { Base::finishCreation(vm); - putDirect(vm, vm.propertyNames->promiseStatePrivateName, jsNumber(static_cast<unsigned>(Status::Pending))); - putDirect(vm, vm.propertyNames->promiseFulfillReactionsPrivateName, jsUndefined()); - putDirect(vm, vm.propertyNames->promiseRejectReactionsPrivateName, jsUndefined()); - putDirect(vm, vm.propertyNames->promiseResultPrivateName, jsUndefined()); + ASSERT(inherits(info())); + + m_constructor.set(vm, this, constructor); } -auto JSPromise::status(VM& vm) const -> Status +void JSPromise::destroy(JSCell* cell) { - JSValue value = getDirect(vm, vm.propertyNames->promiseStatePrivateName); - ASSERT(value.isUInt32()); - return static_cast<Status>(value.asUInt32()); + static_cast<JSPromise*>(cell)->JSPromise::~JSPromise(); } -JSValue JSPromise::result(VM& vm) const +void JSPromise::visitChildren(JSCell* cell, SlotVisitor& visitor) { - return getDirect(vm, vm.propertyNames->promiseResultPrivateName); + JSPromise* thisObject = jsCast<JSPromise*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + + Base::visitChildren(thisObject, visitor); + + visitor.append(&thisObject->m_result); + visitor.append(&thisObject->m_constructor); + visitor.append(thisObject->m_resolveReactions.begin(), thisObject->m_resolveReactions.end()); + visitor.append(thisObject->m_rejectReactions.begin(), thisObject->m_rejectReactions.end()); +} + +void JSPromise::reject(VM& vm, JSValue reason) +{ + // 1. If the value of promise's internal slot [[PromiseStatus]] is not "unresolved", return. + if (m_status != Status::Unresolved) + return; + + DeferGC deferGC(vm.heap); + + // 2. Let 'reactions' be the value of promise's [[RejectReactions]] internal slot. + Vector<WriteBarrier<JSPromiseReaction>> reactions; + reactions.swap(m_rejectReactions); + + // 3. Set the value of promise's [[Result]] internal slot to reason. + m_result.set(vm, this, reason); + + // 4. Set the value of promise's [[ResolveReactions]] internal slot to undefined. + m_resolveReactions.clear(); + + // 5. Set the value of promise's [[RejectReactions]] internal slot to undefined. + // NOTE: Handled by the swap above. + + // 6. Set the value of promise's [[PromiseStatus]] internal slot to "has-rejection". + m_status = Status::HasRejection; + + // 7. Return the result of calling TriggerPromiseReactions(reactions, reason). + triggerPromiseReactions(vm, globalObject(), reactions, reason); +} + +void JSPromise::resolve(VM& vm, JSValue resolution) +{ + // 1. If the value of promise's internal slot [[PromiseStatus]] is not "unresolved", return. + if (m_status != Status::Unresolved) + return; + + DeferGC deferGC(vm.heap); + + // 2. Let 'reactions' be the value of promise's [[ResolveReactions]] internal slot. + Vector<WriteBarrier<JSPromiseReaction>> reactions; + reactions.swap(m_resolveReactions); + + // 3. Set the value of promise's [[Result]] internal slot to resolution. + m_result.set(vm, this, resolution); + + // 4. Set the value of promise's [[ResolveReactions]] internal slot to undefined. + // NOTE: Handled by the swap above. + + // 5. Set the value of promise's [[RejectReactions]] internal slot to undefined. + m_rejectReactions.clear(); + + // 6. Set the value of promise's [[PromiseStatus]] internal slot to "has-resolution". + m_status = Status::HasResolution; + + // 7. Return the result of calling TriggerPromiseReactions(reactions, resolution). + triggerPromiseReactions(vm, globalObject(), reactions, resolution); +} + +void JSPromise::appendResolveReaction(VM& vm, JSPromiseReaction* reaction) +{ + m_resolveReactions.append(WriteBarrier<JSPromiseReaction>(vm, this, reaction)); +} + +void JSPromise::appendRejectReaction(VM& vm, JSPromiseReaction* reaction) +{ + m_rejectReactions.append(WriteBarrier<JSPromiseReaction>(vm, this, reaction)); +} + +void triggerPromiseReactions(VM& vm, JSGlobalObject* globalObject, Vector<WriteBarrier<JSPromiseReaction>>& reactions, JSValue argument) +{ + // 1. Repeat for each reaction in reactions, in original insertion order + for (auto& reaction : reactions) { + // i. Call QueueMicrotask(ExecutePromiseReaction, (reaction, argument)). + globalObject->queueMicrotask(createExecutePromiseReactionMicrotask(vm, reaction.get(), argument)); + } + + // 2. Return. } } // namespace JSC + +#endif // ENABLE(PROMISES) diff --git a/Source/JavaScriptCore/runtime/JSPromise.h b/Source/JavaScriptCore/runtime/JSPromise.h index 88e4c043e..d1d1854d9 100644 --- a/Source/JavaScriptCore/runtime/JSPromise.h +++ b/Source/JavaScriptCore/runtime/JSPromise.h @@ -26,33 +26,68 @@ #ifndef JSPromise_h #define JSPromise_h -#include "JSObject.h" +#if ENABLE(PROMISES) + +#include "JSDestructibleObject.h" namespace JSC { -class JSPromise : public JSNonFinalObject { +class JSPromiseReaction; +class JSPromiseConstructor; + +class JSPromise : public JSDestructibleObject { public: - typedef JSNonFinalObject Base; + typedef JSDestructibleObject Base; - static JSPromise* create(VM&, JSGlobalObject*); + static JSPromise* create(VM&, JSGlobalObject*, JSPromiseConstructor*); static Structure* createStructure(VM&, JSGlobalObject*, JSValue); - DECLARE_EXPORT_INFO; + DECLARE_INFO; - enum class Status : unsigned { - Pending = 1, - Fulfilled, - Rejected + enum class Status { + Unresolved, + HasResolution, + HasRejection }; - Status status(VM&) const; - JSValue result(VM&) const; + Status status() const + { + return m_status; + } + + JSValue result() const + { + ASSERT(m_status != Status::Unresolved); + return m_result.get(); + } + + JSPromiseConstructor* constructor() const + { + return m_constructor.get(); + } + + void reject(VM&, JSValue); + void resolve(VM&, JSValue); + + void appendResolveReaction(VM&, JSPromiseReaction*); + void appendRejectReaction(VM&, JSPromiseReaction*); private: JSPromise(VM&, Structure*); - void finishCreation(VM&); + void finishCreation(VM&, JSPromiseConstructor*); + static const unsigned StructureFlags = OverridesVisitChildren | JSObject::StructureFlags; + static void destroy(JSCell*); + static void visitChildren(JSCell*, SlotVisitor&); + + Status m_status; + WriteBarrier<Unknown> m_result; + WriteBarrier<JSPromiseConstructor> m_constructor; + Vector<WriteBarrier<JSPromiseReaction>> m_resolveReactions; + Vector<WriteBarrier<JSPromiseReaction>> m_rejectReactions; }; } // namespace JSC +#endif // ENABLE(PROMISES) + #endif // JSPromise_h diff --git a/Source/JavaScriptCore/runtime/JSPromiseConstructor.cpp b/Source/JavaScriptCore/runtime/JSPromiseConstructor.cpp index 44e1e73ca..402619633 100644 --- a/Source/JavaScriptCore/runtime/JSPromiseConstructor.cpp +++ b/Source/JavaScriptCore/runtime/JSPromiseConstructor.cpp @@ -26,13 +26,14 @@ #include "config.h" #include "JSPromiseConstructor.h" +#if ENABLE(PROMISES) + #include "Error.h" -#include "Exception.h" -#include "IteratorOperations.h" -#include "JSCBuiltins.h" #include "JSCJSValueInlines.h" #include "JSCellInlines.h" #include "JSPromise.h" +#include "JSPromiseDeferred.h" +#include "JSPromiseFunctions.h" #include "JSPromisePrototype.h" #include "Lookup.h" #include "NumberObject.h" @@ -42,16 +43,22 @@ namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSPromiseConstructor); +static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncCast(ExecState*); +static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncResolve(ExecState*); +static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncReject(ExecState*); +static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncRace(ExecState*); +static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncAll(ExecState*); } #include "JSPromiseConstructor.lut.h" namespace JSC { -const ClassInfo JSPromiseConstructor::s_info = { "Function", &InternalFunction::s_info, &promiseConstructorTable, CREATE_METHOD_TABLE(JSPromiseConstructor) }; +const ClassInfo JSPromiseConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::promiseConstructorTable, CREATE_METHOD_TABLE(JSPromiseConstructor) }; /* Source for JSPromiseConstructor.lut.h @begin promiseConstructorTable + cast JSPromiseConstructorFuncCast DontEnum|Function 1 resolve JSPromiseConstructorFuncResolve DontEnum|Function 1 reject JSPromiseConstructorFuncReject DontEnum|Function 1 race JSPromiseConstructorFuncRace DontEnum|Function 1 @@ -78,27 +85,65 @@ JSPromiseConstructor::JSPromiseConstructor(VM& vm, Structure* structure) void JSPromiseConstructor::finishCreation(VM& vm, JSPromisePrototype* promisePrototype) { - Base::finishCreation(vm, ASCIILiteral("Promise")); + Base::finishCreation(vm, "Promise"); putDirectWithoutTransition(vm, vm.propertyNames->prototype, promisePrototype, DontEnum | DontDelete | ReadOnly); putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontEnum | DontDelete); } static EncodedJSValue JSC_HOST_CALL constructPromise(ExecState* exec) { + // NOTE: We ignore steps 1-4 as they only matter if you support subclassing, which we do not yet. + // 1. Let promise be the this value. + // 2. If Type(promise) is not Object, then throw a TypeError exception. + // 3. If promise does not have a [[PromiseStatus]] internal slot, then throw a TypeError exception. + // 4. If promise's [[PromiseStatus]] internal slot is not undefined, then throw a TypeError exception. + + JSValue resolver = exec->argument(0); + + // 5. IsCallable(resolver) is false, then throw a TypeError exception + CallData callData; + CallType callType = getCallData(resolver, callData); + if (callType == CallTypeNone) + return JSValue::encode(throwTypeError(exec, ASCIILiteral("Promise constructor takes a function argument"))); + VM& vm = exec->vm(); JSGlobalObject* globalObject = exec->callee()->globalObject(); - JSPromise* promise = JSPromise::create(vm, globalObject); + JSPromise* promise = JSPromise::create(vm, globalObject, jsCast<JSPromiseConstructor*>(exec->callee())); - JSFunction* initializePromise = globalObject->initializePromiseFunction(); - CallData callData; - CallType callType = getCallData(initializePromise, callData); - ASSERT(callType != CallTypeNone); + // NOTE: Steps 6-8 are handled by JSPromise::create(). + // 6. Set promise's [[PromiseStatus]] internal slot to "unresolved". + // 7. Set promise's [[ResolveReactions]] internal slot to a new empty List. + // 8. Set promise's [[RejectReactions]] internal slot to a new empty List. + + // 9. Let 'resolve' be a new built-in function object as defined in Resolve Promise Functions. + JSFunction* resolve = createResolvePromiseFunction(vm, globalObject); + + // 10. Set the [[Promise]] internal slot of 'resolve' to 'promise'. + resolve->putDirect(vm, vm.propertyNames->promisePrivateName, promise); + + // 11. Let 'reject' be a new built-in function object as defined in Reject Promise Functions + JSFunction* reject = createRejectPromiseFunction(vm, globalObject); + // 12. Set the [[Promise]] internal slot of 'reject' to 'promise'. + reject->putDirect(vm, vm.propertyNames->promisePrivateName, promise); + + // 13. Let 'result' be the result of calling the [[Call]] internal method of resolver with + // undefined as thisArgument and a List containing resolve and reject as argumentsList. MarkedArgumentBuffer arguments; - arguments.append(exec->argument(0)); - call(exec, initializePromise, callType, callData, promise, arguments); + arguments.append(resolve); + arguments.append(reject); + call(exec, resolver, callType, callData, jsUndefined(), arguments); + + // 14. If result is an abrupt completion, call PromiseReject(promise, result.[[value]]). + if (exec->hadException()) { + JSValue exception = exec->exception(); + exec->clearException(); + + promise->reject(vm, exception); + } + // 15. Return promise. return JSValue::encode(promise); } @@ -116,7 +161,396 @@ CallType JSPromiseConstructor::getCallData(JSCell*, CallData& callData) bool JSPromiseConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { - return getStaticFunctionSlot<InternalFunction>(exec, promiseConstructorTable, jsCast<JSPromiseConstructor*>(object), propertyName, slot); + return getStaticFunctionSlot<InternalFunction>(exec, ExecState::promiseConstructorTable(exec->vm()), jsCast<JSPromiseConstructor*>(object), propertyName, slot); +} + +EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncCast(ExecState* exec) +{ + // -- Promise.cast(x) -- + JSValue x = exec->argument(0); + + // 1. Let 'C' be the this value. + JSValue C = exec->thisValue(); + + // 2. If IsPromise(x) is true, + JSPromise* promise = jsDynamicCast<JSPromise*>(x); + if (promise) { + // i. Let 'constructor' be the value of x's [[PromiseConstructor]] internal slot. + JSValue constructor = promise->constructor(); + // ii. If SameValue(constructor, C) is true, return x. + if (sameValue(exec, constructor, C)) + return JSValue::encode(x); + } + + // 3. Let 'deferred' be the result of calling GetDeferred(C). + JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C); + + // 4. ReturnIfAbrupt(deferred). + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); + + // 5. Let 'resolveResult' be the result of calling the [[Call]] internal method + // of deferred.[[Resolve]] with undefined as thisArgument and a List containing x + // as argumentsList. + performDeferredResolve(exec, deferred, x); + + // 6. ReturnIfAbrupt(resolveResult). + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + // 7. Return deferred.[[Promise]]. + return JSValue::encode(deferred->promise()); +} + +EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncResolve(ExecState* exec) +{ + // -- Promise.resolve(x) -- + JSValue x = exec->argument(0); + + // 1. Let 'C' be the this value. + JSValue C = exec->thisValue(); + + // 2. Let 'deferred' be the result of calling GetDeferred(C). + JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C); + + // 3. ReturnIfAbrupt(deferred). + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); + + // 4. Let 'resolveResult' be the result of calling the [[Call]] internal method + // of deferred.[[Resolve]] with undefined as thisArgument and a List containing x + // as argumentsList. + performDeferredResolve(exec, deferred, x); + + // 5. ReturnIfAbrupt(resolveResult). + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + // 6. Return deferred.[[Promise]]. + return JSValue::encode(deferred->promise()); +} + +EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncReject(ExecState* exec) +{ + // -- Promise.reject(x) -- + JSValue r = exec->argument(0); + + // 1. Let 'C' be the this value. + JSValue C = exec->thisValue(); + + // 2. Let 'deferred' be the result of calling GetDeferred(C). + JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C); + + // 3. ReturnIfAbrupt(deferred). + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); + + // 4. Let 'rejectResult' be the result of calling the [[Call]] internal method + // of deferred.[[Reject]] with undefined as thisArgument and a List containing r + // as argumentsList. + performDeferredReject(exec, deferred, r); + + // 5. ReturnIfAbrupt(resolveResult). + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + // 6. Return deferred.[[Promise]]. + return JSValue::encode(deferred->promise()); +} + +EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncRace(ExecState* exec) +{ + // -- Promise.race(iterable) -- + JSValue iterable = exec->argument(0); + VM& vm = exec->vm(); + + // 1. Let 'C' be the this value. + JSValue C = exec->thisValue(); + + // 2. Let 'deferred' be the result of calling GetDeferred(C). + JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C); + + // 3. ReturnIfAbrupt(deferred). + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); + + // 4. Let 'iterator' be the result of calling GetIterator(iterable). + JSValue iteratorFunction = iterable.get(exec, vm.propertyNames->iteratorPrivateName); + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + CallData iteratorFunctionCallData; + CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData); + if (iteratorFunctionCallType == CallTypeNone) { + throwTypeError(exec); + return JSValue::encode(abruptRejection(exec, deferred)); + } + + ArgList iteratorFunctionArguments; + JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments); + + // 5. RejectIfAbrupt(iterator, deferred). + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + // 6. Repeat + do { + // i. Let 'next' be the result of calling IteratorStep(iterator). + JSValue nextFunction = iterator.get(exec, exec->vm().propertyNames->iteratorNextPrivateName); + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + CallData nextFunctionCallData; + CallType nextFunctionCallType = getCallData(nextFunction, nextFunctionCallData); + if (nextFunctionCallType == CallTypeNone) { + throwTypeError(exec); + return JSValue::encode(abruptRejection(exec, deferred)); + } + + MarkedArgumentBuffer nextFunctionArguments; + nextFunctionArguments.append(jsUndefined()); + JSValue next = call(exec, nextFunction, nextFunctionCallType, nextFunctionCallData, iterator, nextFunctionArguments); + + // ii. RejectIfAbrupt(next, deferred). + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + // iii. If 'next' is false, return deferred.[[Promise]]. + // Note: We implement this as an iterationTerminator + if (next == vm.iterationTerminator.get()) + return JSValue::encode(deferred->promise()); + + // iv. Let 'nextValue' be the result of calling IteratorValue(next). + // v. RejectIfAbrupt(nextValue, deferred). + // Note: 'next' is already the value, so there is nothing to do here. + + // vi. Let 'nextPromise' be the result of calling Invoke(C, "cast", (nextValue)). + JSValue castFunction = C.get(exec, vm.propertyNames->cast); + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + CallData castFunctionCallData; + CallType castFunctionCallType = getCallData(castFunction, castFunctionCallData); + if (castFunctionCallType == CallTypeNone) { + throwTypeError(exec); + return JSValue::encode(abruptRejection(exec, deferred)); + } + + MarkedArgumentBuffer castFunctionArguments; + castFunctionArguments.append(next); + JSValue nextPromise = call(exec, castFunction, castFunctionCallType, castFunctionCallData, C, castFunctionArguments); + + // vii. RejectIfAbrupt(nextPromise, deferred). + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + // viii. Let 'result' be the result of calling Invoke(nextPromise, "then", (deferred.[[Resolve]], deferred.[[Reject]])). + JSValue thenFunction = nextPromise.get(exec, vm.propertyNames->then); + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + CallData thenFunctionCallData; + CallType thenFunctionCallType = getCallData(thenFunction, thenFunctionCallData); + if (thenFunctionCallType == CallTypeNone) { + throwTypeError(exec); + return JSValue::encode(abruptRejection(exec, deferred)); + } + + MarkedArgumentBuffer thenFunctionArguments; + thenFunctionArguments.append(deferred->resolve()); + thenFunctionArguments.append(deferred->reject()); + + call(exec, thenFunction, thenFunctionCallType, thenFunctionCallData, nextPromise, thenFunctionArguments); + + // ix. RejectIfAbrupt(result, deferred). + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + } while (true); +} + +EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncAll(ExecState* exec) +{ + // -- Promise.all(iterable) -- + + JSValue iterable = exec->argument(0); + VM& vm = exec->vm(); + + // 1. Let 'C' be the this value. + JSValue C = exec->thisValue(); + + // 2. Let 'deferred' be the result of calling GetDeferred(C). + JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C); + + // 3. ReturnIfAbrupt(deferred). + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + // NOTE: A non-abrupt completion of createJSPromiseDeferredFromConstructor implies that + // C and deferredValue are objects. + JSObject* thisObject = asObject(C); + JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); + + // 4. Let 'iterator' be the result of calling GetIterator(iterable). + JSValue iteratorFunction = iterable.get(exec, vm.propertyNames->iteratorPrivateName); + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + CallData iteratorFunctionCallData; + CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData); + if (iteratorFunctionCallType == CallTypeNone) { + throwTypeError(exec); + return JSValue::encode(abruptRejection(exec, deferred)); + } + + ArgList iteratorFunctionArguments; + JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments); + + // 5. RejectIfAbrupt(iterator, deferred). + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + // 6. Let 'values' be the result of calling ArrayCreate(0). + JSArray* values = constructEmptyArray(exec, nullptr, thisObject->globalObject()); + + // 7. Let 'countdownHolder' be Record { [[Countdown]]: 0 }. + NumberObject* countdownHolder = constructNumber(exec, thisObject->globalObject(), JSValue(0)); + + // 8. Let 'index' be 0. + unsigned index = 0; + + // 9. Repeat. + do { + // i. Let 'next' be the result of calling IteratorStep(iterator). + JSValue nextFunction = iterator.get(exec, exec->vm().propertyNames->iteratorNextPrivateName); + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + CallData nextFunctionCallData; + CallType nextFunctionCallType = getCallData(nextFunction, nextFunctionCallData); + if (nextFunctionCallType == CallTypeNone) { + throwTypeError(exec); + return JSValue::encode(abruptRejection(exec, deferred)); + } + + MarkedArgumentBuffer nextFunctionArguments; + nextFunctionArguments.append(jsUndefined()); + JSValue next = call(exec, nextFunction, nextFunctionCallType, nextFunctionCallData, iterator, nextFunctionArguments); + + // ii. RejectIfAbrupt(next, deferred). + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + // iii. If 'next' is false, + // Note: We implement this as an iterationTerminator + if (next == vm.iterationTerminator.get()) { + // a. If 'index' is 0, + if (!index) { + // a. Let 'resolveResult' be the result of calling the [[Call]] internal method + // of deferred.[[Resolve]] with undefined as thisArgument and a List containing + // values as argumentsList. + performDeferredResolve(exec, deferred, values); + + // b. ReturnIfAbrupt(resolveResult). + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + } + + // b. Return deferred.[[Promise]]. + return JSValue::encode(deferred->promise()); + } + + // iv. Let 'nextValue' be the result of calling IteratorValue(next). + // v. RejectIfAbrupt(nextValue, deferred). + // Note: 'next' is already the value, so there is nothing to do here. + + // vi. Let 'nextPromise' be the result of calling Invoke(C, "cast", (nextValue)). + JSValue castFunction = C.get(exec, vm.propertyNames->cast); + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + CallData castFunctionCallData; + CallType castFunctionCallType = getCallData(castFunction, castFunctionCallData); + if (castFunctionCallType == CallTypeNone) { + throwTypeError(exec); + return JSValue::encode(abruptRejection(exec, deferred)); + } + + MarkedArgumentBuffer castFunctionArguments; + castFunctionArguments.append(next); + JSValue nextPromise = call(exec, castFunction, castFunctionCallType, castFunctionCallData, C, castFunctionArguments); + + // vii. RejectIfAbrupt(nextPromise, deferred). + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + // viii. Let 'countdownFunction' be a new built-in function object as defined in Promise.all Countdown Functions. + JSFunction* countdownFunction = createPromiseAllCountdownFunction(vm, thisObject->globalObject()); + + // ix. Set the [[Index]] internal slot of 'countdownFunction' to 'index'. + countdownFunction->putDirect(vm, vm.propertyNames->indexPrivateName, JSValue(index)); + + // x. Set the [[Values]] internal slot of 'countdownFunction' to 'values'. + countdownFunction->putDirect(vm, vm.propertyNames->valuesPrivateName, values); + + // xi. Set the [[Deferred]] internal slot of 'countdownFunction' to 'deferred'. + countdownFunction->putDirect(vm, vm.propertyNames->deferredPrivateName, deferred); + + // xii. Set the [[CountdownHolder]] internal slot of 'countdownFunction' to 'countdownHolder'. + countdownFunction->putDirect(vm, vm.propertyNames->countdownHolderPrivateName, countdownHolder); + + // xiii. Let 'result' be the result of calling Invoke(nextPromise, "then", (countdownFunction, deferred.[[Reject]])). + JSValue thenFunction = nextPromise.get(exec, vm.propertyNames->then); + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + CallData thenFunctionCallData; + CallType thenFunctionCallType = getCallData(thenFunction, thenFunctionCallData); + if (thenFunctionCallType == CallTypeNone) { + throwTypeError(exec); + return JSValue::encode(abruptRejection(exec, deferred)); + } + + MarkedArgumentBuffer thenFunctionArguments; + thenFunctionArguments.append(countdownFunction); + thenFunctionArguments.append(deferred->reject()); + + call(exec, thenFunction, thenFunctionCallType, thenFunctionCallData, nextPromise, thenFunctionArguments); + + // xiv. RejectIfAbrupt(result, deferred). + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + // xv. Set index to index + 1. + index++; + + // xvi. Set countdownHolder.[[Countdown]] to countdownHolder.[[Countdown]] + 1. + uint32_t newCountdownValue = countdownHolder->internalValue().asUInt32() + 1; + countdownHolder->setInternalValue(vm, JSValue(newCountdownValue)); + } while (true); +} + +JSPromise* constructPromise(ExecState* exec, JSGlobalObject* globalObject, JSFunction* resolver) +{ + JSPromiseConstructor* promiseConstructor = globalObject->promiseConstructor(); + + ConstructData constructData; + ConstructType constructType = getConstructData(promiseConstructor, constructData); + ASSERT(constructType != ConstructTypeNone); + + MarkedArgumentBuffer arguments; + arguments.append(resolver); + + return jsCast<JSPromise*>(construct(exec, promiseConstructor, constructType, constructData, arguments)); } } // namespace JSC + +#endif // ENABLE(PROMISES) diff --git a/Source/JavaScriptCore/runtime/JSPromiseConstructor.h b/Source/JavaScriptCore/runtime/JSPromiseConstructor.h index 5881e1630..498bb8b56 100644 --- a/Source/JavaScriptCore/runtime/JSPromiseConstructor.h +++ b/Source/JavaScriptCore/runtime/JSPromiseConstructor.h @@ -26,6 +26,8 @@ #ifndef JSPromiseConstructor_h #define JSPromiseConstructor_h +#if ENABLE(PROMISES) + #include "InternalFunction.h" namespace JSC { @@ -36,7 +38,6 @@ class JSPromisePrototype; class JSPromiseConstructor : public InternalFunction { public: typedef InternalFunction Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; static JSPromiseConstructor* create(VM&, Structure*, JSPromisePrototype*); static Structure* createStructure(VM&, JSGlobalObject*, JSValue); @@ -45,6 +46,7 @@ public: protected: void finishCreation(VM&, JSPromisePrototype*); + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags; private: JSPromiseConstructor(VM&, Structure*); @@ -53,6 +55,10 @@ private: static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); }; +JSPromise* constructPromise(ExecState*, JSGlobalObject*, JSFunction*); + } // namespace JSC +#endif // ENABLE(PROMISES) + #endif // JSPromiseConstructor_h diff --git a/Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp b/Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp index 6f3543235..cbc42eb9f 100644 --- a/Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp +++ b/Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp @@ -26,38 +26,29 @@ #include "config.h" #include "JSPromiseDeferred.h" -#include "BuiltinNames.h" #include "Error.h" -#include "Exception.h" #include "JSCJSValueInlines.h" #include "JSCellInlines.h" #include "JSPromise.h" #include "JSPromiseConstructor.h" +#include "JSPromiseFunctions.h" #include "SlotVisitorInlines.h" -#include "StructureInlines.h" namespace JSC { -const ClassInfo JSPromiseDeferred::s_info = { "JSPromiseDeferred", 0, 0, CREATE_METHOD_TABLE(JSPromiseDeferred) }; +const ClassInfo JSPromiseDeferred::s_info = { "JSPromiseDeferred", 0, 0, 0, CREATE_METHOD_TABLE(JSPromiseDeferred) }; JSPromiseDeferred* JSPromiseDeferred::create(ExecState* exec, JSGlobalObject* globalObject) { VM& vm = exec->vm(); + + JSFunction* resolver = createDeferredConstructionFunction(vm, globalObject); - JSFunction* newPromiseDeferredFunction = globalObject->newPromiseDeferredFunction(); - CallData callData; - CallType callType = JSC::getCallData(newPromiseDeferredFunction, callData); - ASSERT(callType != CallTypeNone); + JSPromise* promise = constructPromise(exec, globalObject, resolver); + JSValue resolve = resolver->get(exec, vm.propertyNames->resolvePrivateName); + JSValue reject = resolver->get(exec, vm.propertyNames->rejectPrivateName); - MarkedArgumentBuffer arguments; - JSValue deferred = call(exec, newPromiseDeferredFunction, callType, callData, jsUndefined(), arguments); - - JSValue promise = deferred.get(exec, vm.propertyNames->promisePrivateName); - ASSERT(promise.inherits(JSPromise::info())); - JSValue resolve = deferred.get(exec, vm.propertyNames->builtinNames().resolvePrivateName()); - JSValue reject = deferred.get(exec, vm.propertyNames->builtinNames().rejectPrivateName()); - - return JSPromiseDeferred::create(vm, jsCast<JSPromise*>(promise), resolve, reject); + return JSPromiseDeferred::create(vm, promise, resolve, reject); } JSPromiseDeferred* JSPromiseDeferred::create(VM& vm, JSObject* promise, JSValue resolve, JSValue reject) @@ -84,6 +75,8 @@ void JSPromiseDeferred::visitChildren(JSCell* cell, SlotVisitor& visitor) { JSPromiseDeferred* thisObject = jsCast<JSPromiseDeferred*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); Base::visitChildren(thisObject, visitor); @@ -92,4 +85,162 @@ void JSPromiseDeferred::visitChildren(JSCell* cell, SlotVisitor& visitor) visitor.append(&thisObject->m_reject); } +JSValue createJSPromiseDeferredFromConstructor(ExecState* exec, JSValue C) +{ + // -- This implements the GetDeferred(C) abstract operation -- + + // 1. If IsConstructor(C) is false, throw a TypeError. + if (!C.isObject()) + return throwTypeError(exec); + + ConstructData constructData; + ConstructType constructType = getConstructData(C, constructData); + if (constructType == ConstructTypeNone) + return throwTypeError(exec); + + VM& vm = exec->vm(); + + // 2. Let 'resolver' be a new built-in function object as defined in Deferred Construction Functions. + JSFunction* resolver = createDeferredConstructionFunction(vm, asObject(C)->globalObject()); + + // 3. Let 'promise' be the result of calling the [[Construct]] internal method of 'C' with + // an argument list containing the single item resolver. + MarkedArgumentBuffer constructArguments; + constructArguments.append(resolver); + JSObject* promise = construct(exec, C, constructType, constructData, constructArguments); + + // 4. ReturnIfAbrupt(promise). + if (exec->hadException()) + return jsUndefined(); + + // 5. Let 'resolve' be the value of resolver's [[Resolve]] internal slot. + JSValue resolve = resolver->get(exec, vm.propertyNames->resolvePrivateName); + + // 6. If IsCallable(resolve) is false, throw a TypeError. + CallData resolveCallData; + CallType resolveCallType = getCallData(resolve, resolveCallData); + if (resolveCallType == CallTypeNone) + return throwTypeError(exec); + + // 7. Let 'reject' be the value of resolver's [[Reject]] internal slot. + JSValue reject = resolver->get(exec, vm.propertyNames->rejectPrivateName); + + // 8. If IsCallable(reject) is false, throw a TypeError. + CallData rejectCallData; + CallType rejectCallType = getCallData(reject, rejectCallData); + if (rejectCallType == CallTypeNone) + return throwTypeError(exec); + + // 9. Return the Deferred { [[Promise]]: promise, [[Resolve]]: resolve, [[Reject]]: reject }. + return JSPromiseDeferred::create(exec->vm(), promise, resolve, reject); +} + +ThenableStatus updateDeferredFromPotentialThenable(ExecState* exec, JSValue x, JSPromiseDeferred* deferred) +{ + // 1. If Type(x) is not Object, return "not a thenable". + if (!x.isObject()) + return NotAThenable; + + // 2. Let 'then' be the result of calling Get(x, "then"). + JSValue thenValue = x.get(exec, exec->vm().propertyNames->then); + + // 3. If then is an abrupt completion, + if (exec->hadException()) { + // i. Let 'rejectResult' be the result of calling the [[Call]] internal method of + // deferred.[[Reject]] with undefined as thisArgument and a List containing + // then.[[value]] as argumentsList. + JSValue exception = exec->exception(); + exec->clearException(); + + performDeferredReject(exec, deferred, exception); + + // ii. ReturnIfAbrupt(rejectResult). + // NOTE: Nothing to do. + + // iii. Return. + return WasAThenable; + } + + // 4. Let 'then' be then.[[value]]. + // Note: Nothing to do. + + // 5. If IsCallable(then) is false, return "not a thenable". + CallData thenCallData; + CallType thenCallType = getCallData(thenValue, thenCallData); + if (thenCallType == CallTypeNone) + return NotAThenable; + + // 6. Let 'thenCallResult' be the result of calling the [[Call]] internal method of + // 'then' passing x as thisArgument and a List containing deferred.[[Resolve]] and + // deferred.[[Reject]] as argumentsList. + MarkedArgumentBuffer thenArguments; + thenArguments.append(deferred->resolve()); + thenArguments.append(deferred->reject()); + + call(exec, thenValue, thenCallType, thenCallData, x, thenArguments); + + // 7. If 'thenCallResult' is an abrupt completion, + if (exec->hadException()) { + // i. Let 'rejectResult' be the result of calling the [[Call]] internal method of + // deferred.[[Reject]] with undefined as thisArgument and a List containing + // thenCallResult.[[value]] as argumentsList. + JSValue exception = exec->exception(); + exec->clearException(); + + performDeferredReject(exec, deferred, exception); + + // ii. ReturnIfAbrupt(rejectResult). + // NOTE: Nothing to do. + } + + return WasAThenable; +} + +void performDeferredResolve(ExecState* exec, JSPromiseDeferred* deferred, JSValue argument) +{ + JSValue deferredResolve = deferred->resolve(); + + CallData resolveCallData; + CallType resolveCallType = getCallData(deferredResolve, resolveCallData); + ASSERT(resolveCallType != CallTypeNone); + + MarkedArgumentBuffer arguments; + arguments.append(argument); + + call(exec, deferredResolve, resolveCallType, resolveCallData, jsUndefined(), arguments); +} + +void performDeferredReject(ExecState* exec, JSPromiseDeferred* deferred, JSValue argument) +{ + JSValue deferredReject = deferred->reject(); + + CallData rejectCallData; + CallType rejectCallType = getCallData(deferredReject, rejectCallData); + ASSERT(rejectCallType != CallTypeNone); + + MarkedArgumentBuffer arguments; + arguments.append(argument); + + call(exec, deferredReject, rejectCallType, rejectCallData, jsUndefined(), arguments); +} + +JSValue abruptRejection(ExecState* exec, JSPromiseDeferred* deferred) +{ + ASSERT(exec->hadException()); + JSValue argument = exec->exception(); + exec->clearException(); + + // i. Let 'rejectResult' be the result of calling the [[Call]] internal method + // of deferred.[[Reject]] with undefined as thisArgument and a List containing + // argument.[[value]] as argumentsList. + performDeferredReject(exec, deferred, argument); + + // ii. ReturnIfAbrupt(rejectResult). + if (exec->hadException()) + return jsUndefined(); + + // iii. Return deferred.[[Promise]]. + return deferred->promise(); +} + } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSPromiseDeferred.h b/Source/JavaScriptCore/runtime/JSPromiseDeferred.h index dea0d17f9..ff509d77a 100644 --- a/Source/JavaScriptCore/runtime/JSPromiseDeferred.h +++ b/Source/JavaScriptCore/runtime/JSPromiseDeferred.h @@ -31,19 +31,20 @@ namespace JSC { -class JSPromiseDeferred final : public JSCell { +class JSPromiseDeferred : public JSCell { public: typedef JSCell Base; - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; JS_EXPORT_PRIVATE static JSPromiseDeferred* create(ExecState*, JSGlobalObject*); JS_EXPORT_PRIVATE static JSPromiseDeferred* create(VM&, JSObject* promise, JSValue resolve, JSValue reject); static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); + return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, StructureFlags), info()); } + static const bool hasImmortalStructure = true; + DECLARE_EXPORT_INFO; JSObject* promise() const { return m_promise.get(); } @@ -53,6 +54,7 @@ public: private: JSPromiseDeferred(VM&); void finishCreation(VM&, JSObject*, JSValue, JSValue); + static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; static void visitChildren(JSCell*, SlotVisitor&); WriteBarrier<JSObject> m_promise; @@ -60,6 +62,19 @@ private: WriteBarrier<Unknown> m_reject; }; +enum ThenableStatus { + WasAThenable, + NotAThenable +}; + +JSValue createJSPromiseDeferredFromConstructor(ExecState*, JSValue constructor); +ThenableStatus updateDeferredFromPotentialThenable(ExecState*, JSValue, JSPromiseDeferred*); + +void performDeferredResolve(ExecState*, JSPromiseDeferred*, JSValue argument); +void performDeferredReject(ExecState*, JSPromiseDeferred*, JSValue argument); + +JSValue abruptRejection(ExecState*, JSPromiseDeferred*); + } // namespace JSC #endif // JSPromiseDeferred_h diff --git a/Source/JavaScriptCore/runtime/JSPromiseFunctions.cpp b/Source/JavaScriptCore/runtime/JSPromiseFunctions.cpp new file mode 100644 index 000000000..139d280e8 --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSPromiseFunctions.cpp @@ -0,0 +1,274 @@ +/* + * 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 "JSPromiseFunctions.h" + +#if ENABLE(PROMISES) + +#include "Error.h" +#include "JSCJSValueInlines.h" +#include "JSCellInlines.h" +#include "JSPromise.h" +#include "JSPromiseConstructor.h" +#include "JSPromiseDeferred.h" +#include "NumberObject.h" + +namespace JSC { + +// Deferred Construction Functions +static EncodedJSValue JSC_HOST_CALL deferredConstructionFunction(ExecState* exec) +{ + JSObject* F = exec->callee(); + + VM& vm = exec->vm(); + + // 1. Set F's [[Resolve]] internal slot to resolve. + F->putDirect(vm, vm.propertyNames->resolvePrivateName, exec->argument(0)); + + // 2. Set F's [[Reject]] internal slot to reject. + F->putDirect(vm, vm.propertyNames->rejectPrivateName, exec->argument(1)); + + // 3. Return. + return JSValue::encode(jsUndefined()); +} + +JSFunction* createDeferredConstructionFunction(VM& vm, JSGlobalObject* globalObject) +{ + return JSFunction::create(vm, globalObject, 2, ASCIILiteral("DeferredConstructionFunction"), deferredConstructionFunction); +} + +// Identity Functions + +static EncodedJSValue JSC_HOST_CALL identifyFunction(ExecState* exec) +{ + return JSValue::encode(exec->argument(0)); +} + +JSFunction* createIdentifyFunction(VM& vm, JSGlobalObject* globalObject) +{ + return JSFunction::create(vm, globalObject, 1, ASCIILiteral("IdentityFunction"), identifyFunction); +} + +// Promise.All Countdown Functions + +static EncodedJSValue JSC_HOST_CALL promiseAllCountdownFunction(ExecState* exec) +{ + JSValue x = exec->argument(0); + VM& vm = exec->vm(); + JSObject* F = exec->callee(); + + // 1. Let 'index' be the value of F's [[Index]] internal slot. + uint32_t index = F->get(exec, vm.propertyNames->indexPrivateName).asUInt32(); + + // 2. Let 'values' be the value of F's [[Values]] internal slot.. + JSArray* values = jsCast<JSArray*>(F->get(exec, vm.propertyNames->valuesPrivateName)); + + // 3. Let 'deferred' be the value of F's [[Deferred]] internal slot. + JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(F->get(exec, vm.propertyNames->deferredPrivateName)); + + // 4. Let 'countdownHolder' be the value of F's [[CountdownHolder]] internal slot. + NumberObject* countdownHolder = jsCast<NumberObject*>(F->get(exec, vm.propertyNames->countdownHolderPrivateName)); + + // 5. Let 'result' be the result of calling the [[DefineOwnProperty]] internal method + // of 'values' with arguments 'index' and Property Descriptor { [[Value]]: x, + // [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true }. + values->putDirectIndex(exec, index, x); + + // 6. RejectIfAbrupt(result, deferred). + if (exec->hadException()) + abruptRejection(exec, deferred); + + // 7. Set countdownHolder.[[Countdown]] to countdownHolder.[[Countdown]] - 1. + uint32_t newCountdownValue = countdownHolder->internalValue().asUInt32() - 1; + countdownHolder->setInternalValue(vm, JSValue(newCountdownValue)); + + // 8. If countdownHolder.[[Countdown]] is 0, + if (!newCountdownValue) { + // i. Return the result of calling the [[Call]] internal method of deferred.[[Resolve]] + // with undefined as thisArgument and a List containing 'values' as argumentsList. + performDeferredResolve(exec, deferred, values); + } + + // 9. Return. + return JSValue::encode(jsUndefined()); +} + +JSFunction* createPromiseAllCountdownFunction(VM& vm, JSGlobalObject* globalObject) +{ + return JSFunction::create(vm, globalObject, 1, ASCIILiteral("PromiseAllCountdownFunction"), promiseAllCountdownFunction); +} + +// Promise Resolution Handler Functions + +static EncodedJSValue JSC_HOST_CALL promiseResolutionHandlerFunction(ExecState* exec) +{ + JSValue x = exec->argument(0); + VM& vm = exec->vm(); + JSObject* F = exec->callee(); + + // 1. Let 'promise' be the value of F's [[Promise]] internal slot + JSPromise* promise = jsCast<JSPromise*>(F->get(exec, vm.propertyNames->promisePrivateName)); + + // 2. Let 'fulfillmentHandler' be the value of F's [[FulfillmentHandler]] internal slot. + JSValue fulfillmentHandler = F->get(exec, vm.propertyNames->fulfillmentHandlerPrivateName); + + // 3. Let 'rejectionHandler' be the value of F's [[RejectionHandler]] internal slot. + JSValue rejectionHandler = F->get(exec, vm.propertyNames->rejectionHandlerPrivateName); + + // 4. If SameValue(x, promise) is true, + if (sameValue(exec, x, promise)) { + // i. Let 'selfResolutionError' be a newly-created TypeError object. + JSObject* selfResolutionError = createTypeError(exec, ASCIILiteral("Resolve a promise with itself")); + // ii. Return the result of calling the [[Call]] internal method of rejectionHandler with + // undefined as thisArgument and a List containing selfResolutionError as argumentsList. + CallData rejectCallData; + CallType rejectCallType = getCallData(rejectionHandler, rejectCallData); + ASSERT(rejectCallType != CallTypeNone); + + MarkedArgumentBuffer rejectArguments; + rejectArguments.append(selfResolutionError); + + return JSValue::encode(call(exec, rejectionHandler, rejectCallType, rejectCallData, jsUndefined(), rejectArguments)); + } + + // 5. Let 'C' be the value of promise's [[PromiseConstructor]] internal slot. + JSValue C = promise->constructor(); + + // 6. Let 'deferred' be the result of calling GetDeferred(C) + JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C); + + // 7. ReturnIfAbrupt(deferred). + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); + + // 8. Let 'updateResult' be the result of calling UpdateDeferredFromPotentialThenable(x, deferred). + ThenableStatus updateResult = updateDeferredFromPotentialThenable(exec, x, deferred); + + // 9. ReturnIfAbrupt(updateResult). + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + // 10. If 'updateResult' is not "not a thenable", return the result of calling + // Invoke(deferred.[[Promise]], "then", (fulfillmentHandler, rejectionHandler)). + // NOTE: Invoke does not seem to be defined anywhere, so I am guessing here. + if (updateResult != NotAThenable) { + JSObject* deferredPromise = deferred->promise(); + + JSValue thenValue = deferredPromise->get(exec, exec->vm().propertyNames->then); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + CallData thenCallData; + CallType thenCallType = getCallData(thenValue, thenCallData); + if (thenCallType == CallTypeNone) + return JSValue::encode(throwTypeError(exec)); + + MarkedArgumentBuffer arguments; + arguments.append(fulfillmentHandler); + arguments.append(rejectionHandler); + + return JSValue::encode(call(exec, thenValue, thenCallType, thenCallData, deferredPromise, arguments)); + } + + // 11. Return the result of calling the [[Call]] internal method of fulfillmentHandler + // with undefined as thisArgument and a List containing x as argumentsList. + CallData fulfillmentHandlerCallData; + CallType fulfillmentHandlerCallType = getCallData(fulfillmentHandler, fulfillmentHandlerCallData); + ASSERT(fulfillmentHandlerCallType != CallTypeNone); + + MarkedArgumentBuffer fulfillmentHandlerArguments; + fulfillmentHandlerArguments.append(x); + + return JSValue::encode(call(exec, fulfillmentHandler, fulfillmentHandlerCallType, fulfillmentHandlerCallData, jsUndefined(), fulfillmentHandlerArguments)); +} + +JSFunction* createPromiseResolutionHandlerFunction(VM& vm, JSGlobalObject* globalObject) +{ + return JSFunction::create(vm, globalObject, 1, ASCIILiteral("PromiseResolutionHandlerFunction"), promiseResolutionHandlerFunction); +} + +// Reject Promise Functions + +static EncodedJSValue JSC_HOST_CALL rejectPromiseFunction(ExecState* exec) +{ + JSValue reason = exec->argument(0); + JSObject* F = exec->callee(); + VM& vm = exec->vm(); + + // 1. Let 'promise' be the value of F's [[Promise]] internal slot. + JSPromise* promise = jsCast<JSPromise*>(F->get(exec, exec->vm().propertyNames->promisePrivateName)); + + // 2. Return the result of calling PromiseReject(promise, reason); + promise->reject(vm, reason); + + return JSValue::encode(jsUndefined()); +} + +JSFunction* createRejectPromiseFunction(VM& vm, JSGlobalObject* globalObject) +{ + return JSFunction::create(vm, globalObject, 1, ASCIILiteral("RejectPromiseFunction"), rejectPromiseFunction); +} + +// Resolve Promise Functions + +static EncodedJSValue JSC_HOST_CALL resolvePromiseFunction(ExecState* exec) +{ + JSValue resolution = exec->argument(0); + JSObject* F = exec->callee(); + VM& vm = exec->vm(); + + // 1. Let 'promise' be the value of F's [[Promise]] internal slot. + JSPromise* promise = jsCast<JSPromise*>(F->get(exec, vm.propertyNames->promisePrivateName)); + + // 2. Return the result of calling PromiseResolve(promise, resolution); + promise->resolve(vm, resolution); + + return JSValue::encode(jsUndefined()); +} + +JSFunction* createResolvePromiseFunction(VM& vm, JSGlobalObject* globalObject) +{ + return JSFunction::create(vm, globalObject, 1, ASCIILiteral("ResolvePromiseFunction"), resolvePromiseFunction); +} + +// Thrower Functions + +static EncodedJSValue JSC_HOST_CALL throwerFunction(ExecState* exec) +{ + return JSValue::encode(exec->vm().throwException(exec, exec->argument(0))); +} + +JSFunction* createThrowerFunction(VM& vm, JSGlobalObject* globalObject) +{ + return JSFunction::create(vm, globalObject, 1, ASCIILiteral("ThrowerFunction"), throwerFunction); +} + + +} // namespace JSC + +#endif // ENABLE(PROMISES) diff --git a/Source/JavaScriptCore/runtime/JSJob.h b/Source/JavaScriptCore/runtime/JSPromiseFunctions.h index 0147c836e..802121905 100644 --- a/Source/JavaScriptCore/runtime/JSJob.h +++ b/Source/JavaScriptCore/runtime/JSPromiseFunctions.h @@ -23,19 +23,25 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSJob_h -#define JSJob_h +#ifndef JSPromiseFunctions_h +#define JSPromiseFunctions_h -#include "JSCell.h" -#include "Structure.h" +#if ENABLE(PROMISES) -namespace JSC { +#include "JSFunction.h" -class Microtask; -class JSArray; +namespace JSC { -Ref<Microtask> createJSJob(VM&, JSValue job, JSArray* arguments); +JSFunction* createDeferredConstructionFunction(VM&, JSGlobalObject*); +JSFunction* createIdentifyFunction(VM&, JSGlobalObject*); +JSFunction* createPromiseAllCountdownFunction(VM&, JSGlobalObject*); +JSFunction* createPromiseResolutionHandlerFunction(VM&, JSGlobalObject*); +JSFunction* createRejectPromiseFunction(VM&, JSGlobalObject*); +JSFunction* createResolvePromiseFunction(VM&, JSGlobalObject*); +JSFunction* createThrowerFunction(VM&, JSGlobalObject*); } // namespace JSC -#endif // JSJob_h +#endif // ENABLE(PROMISES) + +#endif // JSPromiseFunctions_h diff --git a/Source/JavaScriptCore/runtime/JSPromisePrototype.cpp b/Source/JavaScriptCore/runtime/JSPromisePrototype.cpp index a0f102432..9df457817 100644 --- a/Source/JavaScriptCore/runtime/JSPromisePrototype.cpp +++ b/Source/JavaScriptCore/runtime/JSPromisePrototype.cpp @@ -26,12 +26,16 @@ #include "config.h" #include "JSPromisePrototype.h" +#if ENABLE(PROMISES) + #include "Error.h" -#include "JSCBuiltins.h" #include "JSCJSValueInlines.h" #include "JSCellInlines.h" #include "JSGlobalObject.h" #include "JSPromise.h" +#include "JSPromiseDeferred.h" +#include "JSPromiseFunctions.h" +#include "JSPromiseReaction.h" #include "Microtask.h" #include "StructureInlines.h" @@ -39,13 +43,16 @@ namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSPromisePrototype); +static EncodedJSValue JSC_HOST_CALL JSPromisePrototypeFuncThen(ExecState*); +static EncodedJSValue JSC_HOST_CALL JSPromisePrototypeFuncCatch(ExecState*); + } #include "JSPromisePrototype.lut.h" namespace JSC { -const ClassInfo JSPromisePrototype::s_info = { "PromisePrototype", &JSNonFinalObject::s_info, &promisePrototypeTable, CREATE_METHOD_TABLE(JSPromisePrototype) }; +const ClassInfo JSPromisePrototype::s_info = { "PromisePrototype", &JSNonFinalObject::s_info, 0, ExecState::promisePrototypeTable, CREATE_METHOD_TABLE(JSPromisePrototype) }; /* Source for JSPromisePrototype.lut.h @begin promisePrototypeTable @@ -79,7 +86,132 @@ void JSPromisePrototype::finishCreation(VM& vm, Structure*) bool JSPromisePrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { - return getStaticFunctionSlot<JSObject>(exec, promisePrototypeTable, jsCast<JSPromisePrototype*>(object), propertyName, slot); + return getStaticFunctionSlot<JSObject>(exec, ExecState::promisePrototypeTable(exec->vm()), jsCast<JSPromisePrototype*>(object), propertyName, slot); +} + +EncodedJSValue JSC_HOST_CALL JSPromisePrototypeFuncThen(ExecState* exec) +{ + // -- Promise.prototype.then(onFulfilled, onRejected) -- + + // 1. Let promise be the this value. + // 2. If IsPromise(promise) is false, throw a TypeError exception. + JSPromise* promise = jsDynamicCast<JSPromise*>(exec->thisValue()); + if (!promise) + return JSValue::encode(throwTypeError(exec)); + + // 3. Let 'C' be the result of calling Get(promise, "constructor"). + JSValue C = promise->get(exec, exec->propertyNames().constructor); + + // 4. ReturnIfAbrupt(C). + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + // 5. Let 'deferred' be the result of calling GetDeferred(C). + JSValue deferred = createJSPromiseDeferredFromConstructor(exec, C); + + // 6. ReturnIfAbrupt(deferred). + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + VM& vm = exec->vm(); + JSGlobalObject* globalObject = promise->globalObject(); + + // 7. Let 'rejectionHandler' be a new built-in function object as defined in Thrower Functions + // 8. If IsCallable(onRejected), set rejectionHandler to onRejected. + JSValue onRejected = exec->argument(1); + CallData onRejectedCallData; + CallType onRejectedCallType = getCallData(onRejected, onRejectedCallData); + JSObject* rejectionHandler = (onRejectedCallType == CallTypeNone) ? createThrowerFunction(vm, globalObject) : asObject(onRejected); + + // 9. Let 'fulfillmentHandler' be a new built-in function object as defined in Identity Functions + // 10. If IsCallable(onFulfilled), set fulfillmentHandler to onFulfilled + JSValue onFulfilled = exec->argument(0); + CallData onFulfilledCallData; + CallType onFulfilledCallType = getCallData(onFulfilled, onFulfilledCallData); + JSObject* fulfillmentHandler = (onFulfilledCallType == CallTypeNone) ? createIdentifyFunction(vm, globalObject) : asObject(onFulfilled); + + // 11. Let 'resolutionHandler' be a new built-in function object as defined in Promise Resolution Handler Functions + JSObject* resolutionHandler = createPromiseResolutionHandlerFunction(vm, globalObject); + + // 12. Set the [[Promise]] internal slot of resolutionHandler to promise. + resolutionHandler->putDirect(vm, vm.propertyNames->promisePrivateName, promise); + + // 13. Set the [[FulfillmentHandler]] internal slot of resolutionHandler to fulfillmentHandler. + resolutionHandler->putDirect(vm, vm.propertyNames->fulfillmentHandlerPrivateName, fulfillmentHandler); + + // 14. Set the [[RejectionHandler]] internal slot of resolutionHandler to rejectionHandler. + resolutionHandler->putDirect(vm, vm.propertyNames->rejectionHandlerPrivateName, rejectionHandler); + + // 15. Let 'resolveReaction' be the PromiseReaction { [[Deferred]]: deferred, [[Handler]]: resolutionHandler }. + JSPromiseReaction* resolveReaction = JSPromiseReaction::create(vm, jsCast<JSPromiseDeferred*>(deferred), resolutionHandler); + + // 16. Let 'rejectReaction' be the PromiseReaction { [[Deferred]]: deferred, [[Handler]]: rejectionHandler }. + JSPromiseReaction* rejectReaction = JSPromiseReaction::create(vm, jsCast<JSPromiseDeferred*>(deferred), rejectionHandler); + + switch (promise->status()) { + case JSPromise::Status::Unresolved: { + // 17. If the value of promise's [[PromiseStatus]] internal slot is "unresolved", + + // i. Append resolveReaction as the last element of promise's [[ResolveReactions]] internal slot. + promise->appendResolveReaction(vm, resolveReaction); + + // ii. Append rejectReaction as the last element of promise's [[RejectReactions]] internal slot. + promise->appendRejectReaction(vm, rejectReaction); + break; + } + + case JSPromise::Status::HasResolution: { + // 18. If the value of promise's [[PromiseStatus]] internal slot is "has-resolution", + + // i. Let 'resolution' be the value of promise's [[Result]] internal slot. + JSValue resolution = promise->result(); + + // ii. Call QueueMicrotask(ExecutePromiseReaction, (resolveReaction, resolution)). + globalObject->queueMicrotask(createExecutePromiseReactionMicrotask(vm, resolveReaction, resolution)); + break; + } + + case JSPromise::Status::HasRejection: { + // 19. If the value of promise's [[PromiseStatus]] internal slot is "has-rejection", + + // i. Let reason be the value of promise's [[Result]] internal slot. + JSValue reason = promise->result(); + + // ii. Call QueueMicrotask(ExecutePromiseReaction, (rejectReaction, reason)). + globalObject->queueMicrotask(createExecutePromiseReactionMicrotask(vm, rejectReaction, reason)); + break; + } + } + + // 20. Return deferred.[[Promise]]. + return JSValue::encode(jsCast<JSPromiseDeferred*>(deferred)->promise()); +} + +EncodedJSValue JSC_HOST_CALL JSPromisePrototypeFuncCatch(ExecState* exec) +{ + // -- Promise.prototype.catch(onRejected) -- + + // 1. Let 'promise' be the this value. + JSValue promise = exec->thisValue(); + + // 2. Return the result of calling Invoke(promise, "then", (undefined, onRejected)). + // NOTE: Invoke does not seem to be defined anywhere, so I am guessing here. + JSValue thenValue = promise.get(exec, exec->vm().propertyNames->then); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + CallData thenCallData; + CallType thenCallType = getCallData(thenValue, thenCallData); + if (thenCallType == CallTypeNone) + return JSValue::encode(throwTypeError(exec)); + + MarkedArgumentBuffer arguments; + arguments.append(jsUndefined()); + arguments.append(exec->argument(0)); + + return JSValue::encode(call(exec, thenValue, thenCallType, thenCallData, promise, arguments)); } } // namespace JSC + +#endif // ENABLE(PROMISES) diff --git a/Source/JavaScriptCore/runtime/JSPromisePrototype.h b/Source/JavaScriptCore/runtime/JSPromisePrototype.h index 458d14119..893fc4afc 100644 --- a/Source/JavaScriptCore/runtime/JSPromisePrototype.h +++ b/Source/JavaScriptCore/runtime/JSPromisePrototype.h @@ -26,6 +26,8 @@ #ifndef JSPromisePrototype_h #define JSPromisePrototype_h +#if ENABLE(PROMISES) + #include "JSObject.h" namespace JSC { @@ -33,7 +35,6 @@ namespace JSC { class JSPromisePrototype : public JSNonFinalObject { public: typedef JSNonFinalObject Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; static JSPromisePrototype* create(ExecState*, JSGlobalObject*, Structure*); static Structure* createStructure(VM&, JSGlobalObject*, JSValue); @@ -42,6 +43,7 @@ public: protected: void finishCreation(VM&, Structure*); + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSObject::StructureFlags; private: JSPromisePrototype(ExecState*, Structure*); @@ -50,4 +52,6 @@ private: } // namespace JSC +#endif // ENABLE(PROMISES) + #endif // JSPromisePrototype_h diff --git a/Source/JavaScriptCore/runtime/JSPromiseReaction.cpp b/Source/JavaScriptCore/runtime/JSPromiseReaction.cpp new file mode 100644 index 000000000..62578e121 --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSPromiseReaction.cpp @@ -0,0 +1,158 @@ +/* + * 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 "JSPromiseReaction.h" + +#include "Error.h" +#include "JSCJSValueInlines.h" +#include "JSCellInlines.h" +#include "JSGlobalObject.h" +#include "JSPromiseDeferred.h" +#include "Microtask.h" +#include "SlotVisitorInlines.h" +#include "StrongInlines.h" + +namespace JSC { + +class ExecutePromiseReactionMicrotask final : public Microtask { +public: + ExecutePromiseReactionMicrotask(VM& vm, JSPromiseReaction* reaction, JSValue argument) + { + m_reaction.set(vm, reaction); + m_argument.set(vm, argument); + } + + virtual ~ExecutePromiseReactionMicrotask() + { + } + +private: + virtual void run(ExecState*) override; + + Strong<JSPromiseReaction> m_reaction; + Strong<Unknown> m_argument; +}; + +PassRefPtr<Microtask> createExecutePromiseReactionMicrotask(VM& vm, JSPromiseReaction* reaction, JSValue argument) +{ + return adoptRef(new ExecutePromiseReactionMicrotask(vm, reaction, argument)); +} + +void ExecutePromiseReactionMicrotask::run(ExecState* exec) +{ + // 1. Let 'deferred' be reaction.[[Deferred]]. + JSPromiseDeferred* deferred = m_reaction->deferred(); + + // 2. Let 'handler' be reaction.[[Handler]]. + JSValue handler = m_reaction->handler(); + + // 3. Let 'handlerResult' be the result of calling the [[Call]] internal method of + // handler passing undefined as thisArgument and a List containing argument as + // argumentsList. + + CallData handlerCallData; + CallType handlerCallType = getCallData(handler, handlerCallData); + ASSERT(handlerCallType != CallTypeNone); + + MarkedArgumentBuffer handlerArguments; + handlerArguments.append(m_argument.get()); + + JSValue handlerResult = call(exec, handler, handlerCallType, handlerCallData, jsUndefined(), handlerArguments); + + // 4. If handlerResult is an abrupt completion, return the result of calling the + // [[Call]] internal method of deferred.[[Reject]] passing undefined as thisArgument + // and a List containing handlerResult.[[value]] as argumentsList. + if (exec->hadException()) { + JSValue exception = exec->exception(); + exec->clearException(); + + performDeferredReject(exec, deferred, exception); + } + + // 5. Let 'handlerResult' be handlerResult.[[value]]. + // Note: Nothing to do. + + // 6. If SameValue(handlerResult, deferred.[[Promise]]) is true, + if (sameValue(exec, handlerResult, deferred->promise())) { + // i. Let 'selfResolutionError' be a newly-created TypeError object. + JSObject* selfResolutionError = createTypeError(exec, ASCIILiteral("Resolve a promise with itself")); + + // ii. Return the result of calling the [[Call]] internal method of deferred.[[Reject]] passing + // undefined as thisArgument and a List containing selfResolutionError as argumentsList. + performDeferredReject(exec, deferred, selfResolutionError); + } + + // 7. Let 'updateResult' be the result of calling UpdateDeferredFromPotentialThenable(handlerResult, deferred). + ThenableStatus updateResult = updateDeferredFromPotentialThenable(exec, handlerResult, deferred); + + // 8. ReturnIfAbrupt(updateResult). + if (exec->hadException()) + return; + + // 9. If 'updateResult' is "not a thenable", + if (updateResult == NotAThenable) { + // i. Return the result of calling the [[Call]] internal method of deferred.[[Resolve]] + // passing undefined as thisArgument and a List containing handlerResult as argumentsList. + performDeferredResolve(exec, deferred, handlerResult); + } +} + + +const ClassInfo JSPromiseReaction::s_info = { "JSPromiseReaction", 0, 0, 0, CREATE_METHOD_TABLE(JSPromiseReaction) }; + +JSPromiseReaction* JSPromiseReaction::create(VM& vm, JSPromiseDeferred* deferred, JSValue handler) +{ + JSPromiseReaction* promiseReaction = new (NotNull, allocateCell<JSPromiseReaction>(vm.heap)) JSPromiseReaction(vm); + promiseReaction->finishCreation(vm, deferred, handler); + return promiseReaction; +} + +JSPromiseReaction::JSPromiseReaction(VM& vm) + : Base(vm, vm.promiseReactionStructure.get()) +{ +} + +void JSPromiseReaction::finishCreation(VM& vm, JSPromiseDeferred* deferred, JSValue handler) +{ + Base::finishCreation(vm); + m_deferred.set(vm, this, deferred); + m_handler.set(vm, this, handler); +} + +void JSPromiseReaction::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + JSPromiseReaction* thisObject = jsCast<JSPromiseReaction*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + + Base::visitChildren(thisObject, visitor); + + visitor.append(&thisObject->m_deferred); + visitor.append(&thisObject->m_handler); +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSPromiseReaction.h b/Source/JavaScriptCore/runtime/JSPromiseReaction.h new file mode 100644 index 000000000..fc7146c50 --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSPromiseReaction.h @@ -0,0 +1,68 @@ +/* + * 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 JSPromiseReaction_h +#define JSPromiseReaction_h + +#include "JSCell.h" +#include "Structure.h" + +namespace JSC { + +class JSPromiseDeferred; +class Microtask; + +class JSPromiseReaction : public JSCell { +public: + typedef JSCell Base; + + static JSPromiseReaction* create(VM&, JSPromiseDeferred*, JSValue); + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, StructureFlags), info()); + } + + static const bool hasImmortalStructure = true; + + DECLARE_INFO; + + JSPromiseDeferred* deferred() const { return m_deferred.get(); } + JSValue handler() const { return m_handler.get(); } + +private: + JSPromiseReaction(VM&); + void finishCreation(VM&, JSPromiseDeferred*, JSValue); + static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; + static void visitChildren(JSCell*, SlotVisitor&); + + WriteBarrier<JSPromiseDeferred> m_deferred; + WriteBarrier<Unknown> m_handler; +}; + +PassRefPtr<Microtask> createExecutePromiseReactionMicrotask(VM&, JSPromiseReaction*, JSValue); + +} // namespace JSC + +#endif // JSPromiseReaction_h diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.cpp b/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.cpp deleted file mode 100644 index 690920f0c..000000000 --- a/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2014 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 "JSPropertyNameEnumerator.h" - -#include "JSCInlines.h" -#include "StrongInlines.h" - -namespace JSC { - -const ClassInfo JSPropertyNameEnumerator::s_info = { "JSPropertyNameEnumerator", 0, 0, CREATE_METHOD_TABLE(JSPropertyNameEnumerator) }; - -JSPropertyNameEnumerator* JSPropertyNameEnumerator::create(VM& vm) -{ - if (!vm.emptyPropertyNameEnumerator.get()) { - PropertyNameArray propertyNames(&vm, PropertyNameMode::Strings); - vm.emptyPropertyNameEnumerator = Strong<JSCell>(vm, create(vm, 0, 0, 0, propertyNames)); - } - return jsCast<JSPropertyNameEnumerator*>(vm.emptyPropertyNameEnumerator.get()); -} - -JSPropertyNameEnumerator* JSPropertyNameEnumerator::create(VM& vm, Structure* structure, uint32_t indexedLength, uint32_t numberStructureProperties, PropertyNameArray& propertyNames) -{ - StructureID structureID = structure ? structure->id() : 0; - uint32_t inlineCapacity = structure ? structure->inlineCapacity() : 0; - JSPropertyNameEnumerator* enumerator = new (NotNull, - allocateCell<JSPropertyNameEnumerator>(vm.heap)) JSPropertyNameEnumerator(vm, structureID, inlineCapacity); - enumerator->finishCreation(vm, indexedLength, numberStructureProperties, propertyNames.data()); - return enumerator; -} - -JSPropertyNameEnumerator::JSPropertyNameEnumerator(VM& vm, StructureID structureID, uint32_t inlineCapacity) - : JSCell(vm, vm.propertyNameEnumeratorStructure.get()) - , m_cachedStructureID(structureID) - , m_cachedInlineCapacity(inlineCapacity) -{ -} - -void JSPropertyNameEnumerator::finishCreation(VM& vm, uint32_t indexedLength, uint32_t endStructurePropertyIndex, PassRefPtr<PropertyNameArrayData> idents) -{ - Base::finishCreation(vm); - - RefPtr<PropertyNameArrayData> identifiers = idents; - PropertyNameArrayData::PropertyNameVector& vector = identifiers->propertyNameVector(); - - m_indexedLength = indexedLength; - m_endStructurePropertyIndex = endStructurePropertyIndex; - m_endGenericPropertyIndex = vector.size(); - - m_propertyNames.resizeToFit(vector.size()); - for (unsigned i = 0; i < vector.size(); ++i) { - const Identifier& identifier = vector[i]; - m_propertyNames[i].set(vm, this, jsString(&vm, identifier.string())); - } -} - -void JSPropertyNameEnumerator::destroy(JSCell* cell) -{ - jsCast<JSPropertyNameEnumerator*>(cell)->JSPropertyNameEnumerator::~JSPropertyNameEnumerator(); -} - -void JSPropertyNameEnumerator::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - Base::visitChildren(cell, visitor); - JSPropertyNameEnumerator* thisObject = jsCast<JSPropertyNameEnumerator*>(cell); - for (unsigned i = 0; i < thisObject->m_propertyNames.size(); ++i) - visitor.append(&thisObject->m_propertyNames[i]); - visitor.append(&thisObject->m_prototypeChain); -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.h b/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.h deleted file mode 100644 index c9ece11ab..000000000 --- a/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2014 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 JSPropertyNameEnumerator_h -#define JSPropertyNameEnumerator_h - -#include "JSCell.h" -#include "Operations.h" -#include "PropertyNameArray.h" -#include "Structure.h" - -namespace JSC { - -class Identifier; - -class JSPropertyNameEnumerator final : public JSCell { -public: - typedef JSCell Base; - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; - - static JSPropertyNameEnumerator* create(VM&); - static JSPropertyNameEnumerator* create(VM&, Structure*, uint32_t, uint32_t, PropertyNameArray&); - - static const bool needsDestruction = true; - static void destroy(JSCell*); - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); - } - - DECLARE_EXPORT_INFO; - - JSString* propertyNameAtIndex(uint32_t index) const - { - if (index >= m_propertyNames.size()) - return nullptr; - return m_propertyNames[index].get(); - } - - StructureChain* cachedPrototypeChain() const { return m_prototypeChain.get(); } - void setCachedPrototypeChain(VM& vm, StructureChain* prototypeChain) { return m_prototypeChain.set(vm, this, prototypeChain); } - - Structure* cachedStructure(VM& vm) const - { - if (!m_cachedStructureID) - return nullptr; - return vm.heap.structureIDTable().get(m_cachedStructureID); - } - StructureID cachedStructureID() const { return m_cachedStructureID; } - uint32_t indexedLength() const { return m_indexedLength; } - uint32_t endStructurePropertyIndex() const { return m_endStructurePropertyIndex; } - uint32_t endGenericPropertyIndex() const { return m_endGenericPropertyIndex; } - uint32_t cachedInlineCapacity() const { return m_cachedInlineCapacity; } - static ptrdiff_t cachedStructureIDOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_cachedStructureID); } - static ptrdiff_t indexedLengthOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_indexedLength); } - static ptrdiff_t endStructurePropertyIndexOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_endStructurePropertyIndex); } - static ptrdiff_t endGenericPropertyIndexOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_endGenericPropertyIndex); } - static ptrdiff_t cachedInlineCapacityOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_cachedInlineCapacity); } - static ptrdiff_t cachedPropertyNamesVectorOffset() - { - return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_propertyNames) + Vector<WriteBarrier<JSString>>::dataMemoryOffset(); - } - - static void visitChildren(JSCell*, SlotVisitor&); - -private: - JSPropertyNameEnumerator(VM&, StructureID, uint32_t); - void finishCreation(VM&, uint32_t, uint32_t, PassRefPtr<PropertyNameArrayData>); - - Vector<WriteBarrier<JSString>> m_propertyNames; - StructureID m_cachedStructureID; - WriteBarrier<StructureChain> m_prototypeChain; - uint32_t m_indexedLength; - uint32_t m_endStructurePropertyIndex; - uint32_t m_endGenericPropertyIndex; - uint32_t m_cachedInlineCapacity; -}; - -inline JSPropertyNameEnumerator* propertyNameEnumerator(ExecState* exec, JSObject* base) -{ - VM& vm = exec->vm(); - - uint32_t indexedLength = base->methodTable(vm)->getEnumerableLength(exec, base); - - JSPropertyNameEnumerator* enumerator = nullptr; - - Structure* structure = base->structure(vm); - if (!indexedLength - && (enumerator = structure->cachedPropertyNameEnumerator()) - && enumerator->cachedPrototypeChain() == structure->prototypeChain(exec)) - return enumerator; - - uint32_t numberStructureProperties = 0; - - PropertyNameArray propertyNames(exec, PropertyNameMode::Strings); - - if (structure->canAccessPropertiesQuickly() && indexedLength == base->getArrayLength()) { - base->methodTable(vm)->getStructurePropertyNames(base, exec, propertyNames, EnumerationMode()); - - numberStructureProperties = propertyNames.size(); - - base->methodTable(vm)->getGenericPropertyNames(base, exec, propertyNames, EnumerationMode()); - } else - base->methodTable(vm)->getPropertyNames(base, exec, propertyNames, EnumerationMode()); - - ASSERT(propertyNames.size() < UINT32_MAX); - - normalizePrototypeChain(exec, structure); - - enumerator = JSPropertyNameEnumerator::create(vm, structure, indexedLength, numberStructureProperties, propertyNames); - enumerator->setCachedPrototypeChain(vm, structure->prototypeChain(exec)); - if (!indexedLength && structure->canCachePropertyNameEnumerator()) - structure->setCachedPropertyNameEnumerator(vm, enumerator); - return enumerator; -} - -} // namespace JSC - -#endif // JSPropertyNameEnumerator_h diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp index a9749a524..68a8bd87d 100644 --- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp +++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp @@ -1,153 +1,113 @@ /* - * Copyright (C) 2015 Apple, Inc. All rights reserved. + * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "JSPropertyNameIterator.h" -#include "IdentifierInlines.h" -#include "IteratorOperations.h" -#include "JSCJSValueInlines.h" -#include "JSCellInlines.h" -#include "JSPropertyNameEnumerator.h" -#include "SlotVisitorInlines.h" -#include "StructureInlines.h" +#include "JSGlobalObject.h" +#include <wtf/StdLibExtras.h> namespace JSC { -static EncodedJSValue JSC_HOST_CALL propertyNameIteratorFuncNext(ExecState*); - -const ClassInfo JSPropertyNameIterator::s_info = { "PropertyName Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(JSPropertyNameIterator) }; - -JSPropertyNameIterator::JSPropertyNameIterator(VM& vm, Structure* structure, JSObject* object, JSPropertyNameEnumerator* enumerator) - : Base(vm, structure) - , m_iteratedObject(vm, this, object) - , m_propertyNameEnumerator(vm, this, enumerator) - , m_enumerationPhase(EnumerationPhase::IndexedNames) - , m_cursor(0) -{ -} +const ClassInfo JSPropertyNameIterator::s_info = { "JSPropertyNameIterator", 0, 0, 0, CREATE_METHOD_TABLE(JSPropertyNameIterator) }; -JSPropertyNameIterator* JSPropertyNameIterator::clone(ExecState* exec) +inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlots) + : JSCell(exec->vm(), exec->vm().propertyNameIteratorStructure.get()) + , m_numCacheableSlots(numCacheableSlots) + , m_jsStringsSize(propertyNameArrayData->propertyNameVector().size()) + , m_jsStrings(m_jsStringsSize ? std::make_unique<WriteBarrier<Unknown>[]>(m_jsStringsSize) : nullptr) { - auto iterator = JSPropertyNameIterator::create(exec, exec->callee()->globalObject()->propertyNameIteratorStructure(), m_iteratedObject.get(), m_propertyNameEnumerator.get()); - iterator->m_enumerationPhase = m_enumerationPhase; - iterator->m_cursor = m_cursor; - return iterator; } -JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, Structure* structure, JSObject* iteratedObject) +JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSObject* o) { - return JSPropertyNameIterator::create(exec, structure, iteratedObject, propertyNameEnumerator(exec, iteratedObject)); -} + ASSERT(!o->structure()->enumerationCache() || + o->structure()->enumerationCache()->cachedStructure() != o->structure() || + o->structure()->enumerationCache()->cachedPrototypeChain() != o->structure()->prototypeChain(exec)); -JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, Structure* structure, JSObject* iteratedObject, JSPropertyNameEnumerator* enumerator) -{ VM& vm = exec->vm(); - JSPropertyNameIterator* instance = new (NotNull, allocateCell<JSPropertyNameIterator>(vm.heap)) JSPropertyNameIterator(vm, structure, iteratedObject, enumerator); - instance->finishCreation(vm, structure->globalObject()); - return instance; -} -void JSPropertyNameIterator::finishCreation(VM& vm, JSGlobalObject* globalObject) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); - JSC_NATIVE_FUNCTION(vm.propertyNames->next, propertyNameIteratorFuncNext, DontEnum, 0); + PropertyNameArray propertyNames(exec); + o->methodTable()->getPropertyNames(o, exec, propertyNames, ExcludeDontEnumProperties); + size_t numCacheableSlots = 0; + if (!o->structure()->hasNonEnumerableProperties() && !o->structure()->hasGetterSetterProperties() + && !o->structure()->isUncacheableDictionary() && !o->structure()->typeInfo().overridesGetPropertyNames()) + numCacheableSlots = propertyNames.numCacheableSlots(); + + JSPropertyNameIterator* jsPropertyNameIterator = new (NotNull, allocateCell<JSPropertyNameIterator>(vm.heap)) JSPropertyNameIterator(exec, propertyNames.data(), numCacheableSlots); + jsPropertyNameIterator->finishCreation(vm, propertyNames.data(), o); + + if (o->structure()->isDictionary()) + return jsPropertyNameIterator; + + if (o->structure()->typeInfo().overridesGetPropertyNames()) + return jsPropertyNameIterator; + + if (hasIndexedProperties(o->structure()->indexingType())) + return jsPropertyNameIterator; + + size_t count = normalizePrototypeChain(exec, o); + StructureChain* structureChain = o->structure()->prototypeChain(exec); + WriteBarrier<Structure>* structure = structureChain->head(); + for (size_t i = 0; i < count; ++i) { + if (structure[i]->typeInfo().overridesGetPropertyNames()) + return jsPropertyNameIterator; + } + + jsPropertyNameIterator->setCachedPrototypeChain(vm, structureChain); + jsPropertyNameIterator->setCachedStructure(vm, o->structure()); + o->structure()->setEnumerationCache(vm, jsPropertyNameIterator); + return jsPropertyNameIterator; } -void JSPropertyNameIterator::visitChildren(JSCell* cell, SlotVisitor& visitor) +void JSPropertyNameIterator::destroy(JSCell* cell) { - JSPropertyNameIterator* thisObject = jsCast<JSPropertyNameIterator*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - Base::visitChildren(thisObject, visitor); - visitor.append(&thisObject->m_iteratedObject); - visitor.append(&thisObject->m_propertyNameEnumerator); + static_cast<JSPropertyNameIterator*>(cell)->JSPropertyNameIterator::~JSPropertyNameIterator(); } -bool JSPropertyNameIterator::next(ExecState* exec, JSValue& output) +JSValue JSPropertyNameIterator::get(ExecState* exec, JSObject* base, size_t i) { - if (m_enumerationPhase == EnumerationPhase::IndexedNames) { - for (; m_cursor < m_propertyNameEnumerator->indexedLength();) { - uint32_t index = m_cursor++; - if (m_iteratedObject->hasProperty(exec, index)) { - output = jsString(exec, Identifier::from(exec, index).string()); - return true; - } - } - m_cursor = 0; - m_enumerationPhase = EnumerationPhase::StructureNames; - } + JSValue identifier = m_jsStrings[i].get(); + if (m_cachedStructure.get() == base->structure() && m_cachedPrototypeChain.get() == base->structure()->prototypeChain(exec)) + return identifier; - if (m_enumerationPhase == EnumerationPhase::StructureNames) { - for (; m_cursor < m_propertyNameEnumerator->endStructurePropertyIndex();) { - uint32_t index = m_cursor++; - JSString* propertyName = m_propertyNameEnumerator->propertyNameAtIndex(index); - ASSERT(propertyName); - if (m_iteratedObject->structure(exec->vm())->id() == m_propertyNameEnumerator->cachedStructureID()) { - output = propertyName; - return true; - } - - if (m_iteratedObject->hasProperty(exec, propertyName->toIdentifier(exec))) { - output = propertyName; - return true; - } - } - ASSERT(m_cursor >= m_propertyNameEnumerator->endStructurePropertyIndex()); - // Use the same m_cursor in the GenericNames phase. - m_enumerationPhase = EnumerationPhase::GenericNames; - } - - if (m_enumerationPhase == EnumerationPhase::GenericNames) { - for (; m_cursor < m_propertyNameEnumerator->endGenericPropertyIndex();) { - uint32_t index = m_cursor++; - JSString* propertyName = m_propertyNameEnumerator->propertyNameAtIndex(index); - ASSERT(propertyName); - if (m_iteratedObject->hasProperty(exec, propertyName->toIdentifier(exec))) { - output = propertyName; - return true; - } - } - m_enumerationPhase = EnumerationPhase::Done; - } - - return false; + if (!base->hasProperty(exec, Identifier(exec, asString(identifier)->value(exec)))) + return JSValue(); + return identifier; } -// ------------------------------ PropertyNameIterator Functions ---------------------------- - -EncodedJSValue JSC_HOST_CALL propertyNameIteratorFuncNext(ExecState* exec) +void JSPropertyNameIterator::visitChildren(JSCell* cell, SlotVisitor& visitor) { - JSPropertyNameIterator* iterator = jsDynamicCast<JSPropertyNameIterator*>(exec->thisValue()); - if (!iterator) - return JSValue::encode(throwTypeError(exec, ASCIILiteral("Cannot call PropertyNameIterator.next() on a non-PropertyNameIterator object"))); - - JSValue result; - if (iterator->next(exec, result)) - return JSValue::encode(createIteratorResultObject(exec, result, false)); - return JSValue::encode(createIteratorResultObject(exec, jsUndefined(), true)); + JSPropertyNameIterator* thisObject = jsCast<JSPropertyNameIterator*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + visitor.appendValues(thisObject->m_jsStrings.get(), thisObject->m_jsStringsSize); + visitor.append(&thisObject->m_cachedPrototypeChain); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h index bf0dc10f3..f4362ff35 100644 --- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h +++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h @@ -1,76 +1,119 @@ /* - * Copyright (C) 2015 Apple, Inc. All rights reserved. + * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 JSPropertyNameIterator_h #define JSPropertyNameIterator_h #include "JSObject.h" -#include "JSPropertyNameEnumerator.h" +#include "JSString.h" +#include "Operations.h" +#include "PropertyNameArray.h" +#include <memory> namespace JSC { -class JSPropertyNameIterator : public JSNonFinalObject { -public: - typedef JSNonFinalObject Base; - - enum class EnumerationPhase : uint32_t { - IndexedNames, - StructureNames, - GenericNames, - Done + class Identifier; + class JSObject; + class LLIntOffsetsExtractor; + + class JSPropertyNameIterator : public JSCell { + friend class JIT; + + public: + typedef JSCell Base; + + static JSPropertyNameIterator* create(ExecState*, JSObject*); + + 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(CompoundType, OverridesVisitChildren), info()); + } + + static void visitChildren(JSCell*, SlotVisitor&); + + JSValue get(ExecState*, JSObject*, size_t i); + size_t size() { return m_jsStringsSize; } + + void setCachedStructure(VM& vm, Structure* structure) + { + ASSERT(!m_cachedStructure); + ASSERT(structure); + m_cachedStructure.set(vm, this, structure); + } + Structure* cachedStructure() { return m_cachedStructure.get(); } + + void setCachedPrototypeChain(VM& vm, StructureChain* cachedPrototypeChain) { m_cachedPrototypeChain.set(vm, this, cachedPrototypeChain); } + StructureChain* cachedPrototypeChain() { return m_cachedPrototypeChain.get(); } + + DECLARE_EXPORT_INFO; + + protected: + void finishCreation(VM& vm, PropertyNameArrayData* propertyNameArrayData, JSObject* object) + { + Base::finishCreation(vm); + PropertyNameArrayData::PropertyNameVector& propertyNameVector = propertyNameArrayData->propertyNameVector(); + for (size_t i = 0; i < m_jsStringsSize; ++i) + m_jsStrings[i].set(vm, this, jsOwnedString(&vm, propertyNameVector[i].string())); + m_cachedStructureInlineCapacity = object->structure()->inlineCapacity(); + } + + private: + friend class LLIntOffsetsExtractor; + + JSPropertyNameIterator(ExecState*, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlot); + + WriteBarrier<Structure> m_cachedStructure; + WriteBarrier<StructureChain> m_cachedPrototypeChain; + uint32_t m_numCacheableSlots; + uint32_t m_jsStringsSize; + unsigned m_cachedStructureInlineCapacity; + std::unique_ptr<WriteBarrier<Unknown>[]> m_jsStrings; }; - DECLARE_EXPORT_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + ALWAYS_INLINE JSPropertyNameIterator* Register::propertyNameIterator() const { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + return jsCast<JSPropertyNameIterator*>(jsValue().asCell()); } - static JSPropertyNameIterator* create(ExecState*, Structure*, JSObject*); - - JSPropertyNameIterator* clone(ExecState*); - bool next(ExecState*, JSValue&); - - JSValue iteratedValue() const { return m_iteratedObject.get(); } - - static void visitChildren(JSCell*, SlotVisitor&); - -private: - JSPropertyNameIterator(VM&, Structure*, JSObject*, JSPropertyNameEnumerator*); - - void finishCreation(VM&, JSGlobalObject*); - - static JSPropertyNameIterator* create(ExecState*, Structure*, JSObject*, JSPropertyNameEnumerator*); - - WriteBarrier<JSObject> m_iteratedObject; - WriteBarrier<JSPropertyNameEnumerator> m_propertyNameEnumerator; - EnumerationPhase m_enumerationPhase; - uint32_t m_cursor; -}; + inline JSPropertyNameIterator* StructureRareData::enumerationCache() + { + return m_enumerationCache.get(); + } + + inline void StructureRareData::setEnumerationCache(VM& vm, const Structure*, JSPropertyNameIterator* value) + { + m_enumerationCache.set(vm, this, value); + } -} +} // namespace JSC #endif // JSPropertyNameIterator_h diff --git a/Source/JavaScriptCore/runtime/JSProxy.cpp b/Source/JavaScriptCore/runtime/JSProxy.cpp index f4c6829e0..ced8cc41f 100644 --- a/Source/JavaScriptCore/runtime/JSProxy.cpp +++ b/Source/JavaScriptCore/runtime/JSProxy.cpp @@ -27,18 +27,22 @@ #include "JSProxy.h" #include "JSGlobalObject.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSProxy); -const ClassInfo JSProxy::s_info = { "JSProxy", &Base::s_info, 0, CREATE_METHOD_TABLE(JSProxy) }; +const ClassInfo JSProxy::s_info = { "JSProxy", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSProxy) }; void JSProxy::visitChildren(JSCell* cell, SlotVisitor& visitor) { JSProxy* thisObject = jsCast<JSProxy*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + Base::visitChildren(thisObject, visitor); visitor.append(&thisObject->m_target); } @@ -69,74 +73,55 @@ String JSProxy::className(const JSObject* object) bool JSProxy::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { JSProxy* thisObject = jsCast<JSProxy*>(object); - return thisObject->target()->methodTable(exec->vm())->getOwnPropertySlot(thisObject->target(), exec, propertyName, slot); + return thisObject->target()->methodTable()->getOwnPropertySlot(thisObject->target(), exec, propertyName, slot); } bool JSProxy::getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned propertyName, PropertySlot& slot) { JSProxy* thisObject = jsCast<JSProxy*>(object); - return thisObject->target()->methodTable(exec->vm())->getOwnPropertySlotByIndex(thisObject->target(), exec, propertyName, slot); + return thisObject->target()->methodTable()->getOwnPropertySlotByIndex(thisObject->target(), exec, propertyName, slot); } void JSProxy::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { JSProxy* thisObject = jsCast<JSProxy*>(cell); - thisObject->target()->methodTable(exec->vm())->put(thisObject->target(), exec, propertyName, value, slot); + thisObject->target()->methodTable()->put(thisObject->target(), exec, propertyName, value, slot); } void JSProxy::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow) { JSProxy* thisObject = jsCast<JSProxy*>(cell); - thisObject->target()->methodTable(exec->vm())->putByIndex(thisObject->target(), exec, propertyName, value, shouldThrow); + thisObject->target()->methodTable()->putByIndex(thisObject->target(), exec, propertyName, value, shouldThrow); } bool JSProxy::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow) { JSProxy* thisObject = jsCast<JSProxy*>(object); - return thisObject->target()->methodTable(exec->vm())->defineOwnProperty(thisObject->target(), exec, propertyName, descriptor, shouldThrow); + return thisObject->target()->methodTable()->defineOwnProperty(thisObject->target(), exec, propertyName, descriptor, shouldThrow); } bool JSProxy::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) { JSProxy* thisObject = jsCast<JSProxy*>(cell); - return thisObject->target()->methodTable(exec->vm())->deleteProperty(thisObject->target(), exec, propertyName); + return thisObject->target()->methodTable()->deleteProperty(thisObject->target(), exec, propertyName); } bool JSProxy::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName) { JSProxy* thisObject = jsCast<JSProxy*>(cell); - return thisObject->target()->methodTable(exec->vm())->deletePropertyByIndex(thisObject->target(), exec, propertyName); + return thisObject->target()->methodTable()->deletePropertyByIndex(thisObject->target(), exec, propertyName); } void JSProxy::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { JSProxy* thisObject = jsCast<JSProxy*>(object); - thisObject->target()->methodTable(exec->vm())->getPropertyNames(thisObject->target(), exec, propertyNames, mode); -} - -uint32_t JSProxy::getEnumerableLength(ExecState* exec, JSObject* object) -{ - JSProxy* thisObject = jsCast<JSProxy*>(object); - return thisObject->target()->methodTable(exec->vm())->getEnumerableLength(exec, thisObject->target()); -} - -void JSProxy::getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode) -{ - // Skip the structure loop, since it is invalid for proxies. -} - -void JSProxy::getGenericPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) -{ - JSProxy* thisObject = jsCast<JSProxy*>(object); - // Get *all* of the property names, not just the generic ones, since we skipped the structure - // ones above. - thisObject->target()->methodTable(exec->vm())->getPropertyNames(thisObject->target(), exec, propertyNames, mode); + thisObject->target()->methodTable()->getPropertyNames(thisObject->target(), exec, propertyNames, mode); } void JSProxy::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { JSProxy* thisObject = jsCast<JSProxy*>(object); - thisObject->target()->methodTable(exec->vm())->getOwnPropertyNames(thisObject->target(), exec, propertyNames, mode); + thisObject->target()->methodTable()->getOwnPropertyNames(thisObject->target(), exec, propertyNames, mode); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSProxy.h b/Source/JavaScriptCore/runtime/JSProxy.h index 2bdcd1b72..ea941a275 100644 --- a/Source/JavaScriptCore/runtime/JSProxy.h +++ b/Source/JavaScriptCore/runtime/JSProxy.h @@ -33,7 +33,6 @@ namespace JSC { class JSProxy : public JSDestructibleObject { public: typedef JSDestructibleObject Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero; static JSProxy* create(VM& vm, Structure* structure, JSObject* target) { @@ -42,15 +41,14 @@ public: return proxy; } - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, JSType proxyType = ImpureProxyType) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(vm, globalObject, prototype, TypeInfo(proxyType, StructureFlags), info()); + return Structure::create(vm, globalObject, prototype, TypeInfo(ProxyType, StructureFlags), info()); } DECLARE_EXPORT_INFO; JSObject* target() const { return m_target.get(); } - static ptrdiff_t targetOffset() { return OBJECT_OFFSETOF(JSProxy, m_target); } protected: JSProxy(VM& vm, Structure* structure) @@ -69,6 +67,8 @@ protected: m_target.set(vm, this, target); } + static const unsigned StructureFlags = OverridesVisitChildren | OverridesGetOwnPropertySlot | OverridesGetPropertyNames | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | Base::StructureFlags; + JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); JS_EXPORT_PRIVATE void setTarget(VM&, JSGlobalObject*); @@ -82,9 +82,6 @@ protected: JS_EXPORT_PRIVATE static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned); JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - JS_EXPORT_PRIVATE static uint32_t getEnumerableLength(ExecState*, JSObject*); - JS_EXPORT_PRIVATE static void getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - JS_EXPORT_PRIVATE static void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow); private: diff --git a/Source/JavaScriptCore/runtime/JSScope.cpp b/Source/JavaScriptCore/runtime/JSScope.cpp index bb2efdd06..3440bc610 100644 --- a/Source/JavaScriptCore/runtime/JSScope.cpp +++ b/Source/JavaScriptCore/runtime/JSScope.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 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,10 +26,11 @@ #include "config.h" #include "JSScope.h" +#include "JSActivation.h" #include "JSGlobalObject.h" -#include "JSLexicalEnvironment.h" +#include "JSNameScope.h" #include "JSWithScope.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { @@ -39,6 +40,9 @@ void JSScope::visitChildren(JSCell* cell, SlotVisitor& visitor) { JSScope* thisObject = jsCast<JSScope*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + Base::visitChildren(thisObject, visitor); visitor.append(&thisObject->m_next); } @@ -46,26 +50,26 @@ void JSScope::visitChildren(JSCell* cell, SlotVisitor& visitor) // Returns true if we found enough information to terminate optimization. static inline bool abstractAccess(ExecState* exec, JSScope* scope, const Identifier& ident, GetOrPut getOrPut, size_t depth, bool& needsVarInjectionChecks, ResolveOp& op) { - if (JSLexicalEnvironment* lexicalEnvironment = jsDynamicCast<JSLexicalEnvironment*>(scope)) { + if (JSActivation* activation = jsDynamicCast<JSActivation*>(scope)) { if (ident == exec->propertyNames().arguments) { - // We know the property will be at this lexical environment scope, but we don't know how to cache it. + // We know the property will be at this activation scope, but we don't know how to cache it. op = ResolveOp(Dynamic, 0, 0, 0, 0, 0); return true; } - SymbolTableEntry entry = lexicalEnvironment->symbolTable()->get(ident.impl()); + SymbolTableEntry entry = activation->symbolTable()->get(ident.impl()); if (entry.isReadOnly() && getOrPut == Put) { - // We know the property will be at this lexical environment scope, but we don't know how to cache it. + // We know the property will be at this activation scope, but we don't know how to cache it. op = ResolveOp(Dynamic, 0, 0, 0, 0, 0); return true; } if (!entry.isNull()) { - op = ResolveOp(makeType(ClosureVar, needsVarInjectionChecks), depth, 0, lexicalEnvironment, entry.watchpointSet(), entry.scopeOffset().offset()); + op = ResolveOp(makeType(ClosureVar, needsVarInjectionChecks), depth, 0, activation, entry.watchpointSet(), entry.getIndex()); return true; } - if (lexicalEnvironment->symbolTable()->usesNonStrictEval()) + if (activation->symbolTable()->usesNonStrictEval()) needsVarInjectionChecks = true; return false; } @@ -81,7 +85,7 @@ static inline bool abstractAccess(ExecState* exec, JSScope* scope, const Identif op = ResolveOp( makeType(GlobalVar, needsVarInjectionChecks), depth, 0, 0, entry.watchpointSet(), - reinterpret_cast<uintptr_t>(globalObject->variableAt(entry.scopeOffset()).slot())); + reinterpret_cast<uintptr_t>(globalObject->registerAt(entry.getIndex()).slot())); return true; } @@ -95,19 +99,8 @@ static inline bool abstractAccess(ExecState* exec, JSScope* scope, const Identif op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, 0, 0, 0, 0); return true; } - - WatchpointState state = globalObject->structure()->ensurePropertyReplacementWatchpointSet(exec->vm(), slot.cachedOffset())->state(); - if (state == IsWatched && getOrPut == Put) { - // The field exists, but because the replacement watchpoint is still intact. This is - // kind of dangerous. We have two options: - // 1) Invalidate the watchpoint set. That would work, but it's possible that this code - // path never executes - in which case this would be unwise. - // 2) Have the invalidation happen at run-time. All we have to do is leave the code - // uncached. The only downside is slightly more work when this does execute. - // We go with option (2) here because it seems less evil. - op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, 0, 0, 0, 0); - } else - op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, globalObject->structure(), 0, 0, slot.cachedOffset()); + + op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, globalObject->structure(), 0, 0, slot.cachedOffset()); return true; } @@ -118,28 +111,18 @@ static inline bool abstractAccess(ExecState* exec, JSScope* scope, const Identif JSObject* JSScope::objectAtScope(JSScope* scope) { JSObject* object = scope; - if (object->type() == WithScopeType) + if (object->structure()->typeInfo().type() == WithScopeType) return jsCast<JSWithScope*>(object)->object(); return object; } -// When an exception occurs, the result of isUnscopable becomes false. -static inline bool isUnscopable(ExecState* exec, JSScope* scope, JSObject* object, const Identifier& ident) +int JSScope::depth() { - if (scope->type() != WithScopeType) - return false; - - JSValue unscopables = object->get(exec, exec->propertyNames().unscopablesSymbol); - if (exec->hadException()) - return false; - if (!unscopables.isObject()) - return false; - JSValue blocked = jsCast<JSObject*>(unscopables)->get(exec, ident); - if (exec->hadException()) - return false; - - return blocked.toBoolean(exec); + int depth = 0; + for (JSScope* scope = this; scope; scope = scope->next()) + ++depth; + return depth; } JSValue JSScope::resolve(ExecState* exec, JSScope* scope, const Identifier& ident) @@ -147,28 +130,24 @@ JSValue JSScope::resolve(ExecState* exec, JSScope* scope, const Identifier& iden ScopeChainIterator end = scope->end(); ScopeChainIterator it = scope->begin(); while (1) { - JSScope* scope = it.scope(); JSObject* object = it.get(); if (++it == end) // Global scope. return object; - if (object->hasProperty(exec, ident)) { - if (!isUnscopable(exec, scope, object, ident)) - return object; - ASSERT_WITH_MESSAGE(!exec->hadException(), "When an exception occurs, the result of isUnscopable becomes false"); - } + if (object->hasProperty(exec, ident)) + return object; } } -ResolveOp JSScope::abstractResolve(ExecState* exec, size_t depthOffset, JSScope* scope, const Identifier& ident, GetOrPut getOrPut, ResolveType unlinkedType) +ResolveOp JSScope::abstractResolve(ExecState* exec, JSScope* scope, const Identifier& ident, GetOrPut getOrPut, ResolveType unlinkedType) { ResolveOp op(Dynamic, 0, 0, 0, 0, 0); if (unlinkedType == Dynamic) return op; + size_t depth = 0; bool needsVarInjectionChecks = JSC::needsVarInjectionChecks(unlinkedType); - size_t depth = depthOffset; for (; scope; scope = scope->next()) { if (abstractAccess(exec, scope, ident, getOrPut, depth, needsVarInjectionChecks, op)) break; @@ -178,66 +157,4 @@ ResolveOp JSScope::abstractResolve(ExecState* exec, size_t depthOffset, JSScope* return op; } -void JSScope::collectVariablesUnderTDZ(JSScope* scope, VariableEnvironment& result) -{ - for (; scope; scope = scope->next()) { - if (!scope->isLexicalScope()) - continue; - SymbolTable* symbolTable = jsCast<JSLexicalEnvironment*>(scope)->symbolTable(); - ASSERT(symbolTable->scopeType() == SymbolTable::ScopeType::LexicalScope); - ConcurrentJITLocker locker(symbolTable->m_lock); - for (auto end = symbolTable->end(locker), iter = symbolTable->begin(locker); iter != end; ++iter) - result.add(iter->key); - } -} - -bool JSScope::isLexicalScope() -{ - JSLexicalEnvironment* lexicalEnvironment = jsDynamicCast<JSLexicalEnvironment*>(this); - if (!lexicalEnvironment) // Global object does not hold any lexical variables so we can ignore it. - return false; - - return lexicalEnvironment->symbolTable()->scopeType() == SymbolTable::ScopeType::LexicalScope; -} - -bool JSScope::isCatchScope() -{ - JSLexicalEnvironment* lexicalEnvironment = jsDynamicCast<JSLexicalEnvironment*>(this); - if (!lexicalEnvironment) - return false; - return lexicalEnvironment->symbolTable()->scopeType() == SymbolTable::ScopeType::CatchScope; -} - -bool JSScope::isFunctionNameScopeObject() -{ - JSLexicalEnvironment* lexicalEnvironment = jsDynamicCast<JSLexicalEnvironment*>(this); - if (!lexicalEnvironment) - return false; - return lexicalEnvironment->symbolTable()->scopeType() == SymbolTable::ScopeType::FunctionNameScope; -} - -const char* resolveModeName(ResolveMode mode) -{ - static const char* const names[] = { - "ThrowIfNotFound", - "DoNotThrowIfNotFound" - }; - return names[mode]; -} - -const char* resolveTypeName(ResolveType type) -{ - static const char* const names[] = { - "GlobalProperty", - "GlobalVar", - "ClosureVar", - "LocalClosureVar", - "GlobalPropertyWithVarInjectionChecks", - "GlobalVarWithVarInjectionChecks", - "ClosureVarWithVarInjectionChecks", - "Dynamic" - }; - return names[type]; -} - } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSScope.h b/Source/JavaScriptCore/runtime/JSScope.h index a65316749..3f62a45ac 100644 --- a/Source/JavaScriptCore/runtime/JSScope.h +++ b/Source/JavaScriptCore/runtime/JSScope.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013, 2014 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 @@ -27,12 +27,11 @@ #define JSScope_h #include "JSObject.h" -#include "VariableEnvironment.h" namespace JSC { class ScopeChainIterator; -class WatchpointSet; +class VariableWatchpointSet; enum ResolveMode { ThrowIfNotFound, @@ -44,7 +43,6 @@ enum ResolveType { GlobalProperty, GlobalVar, ClosureVar, - LocalClosureVar, // Ditto, but at least one intervening scope used non-strict eval, which // can inject an intercepting var delcaration at runtime. @@ -56,9 +54,6 @@ enum ResolveType { Dynamic }; -const char* resolveModeName(ResolveMode mode); -const char* resolveTypeName(ResolveType type); - inline ResolveType makeType(ResolveType type, bool needsVarInjectionChecks) { if (!needsVarInjectionChecks) @@ -70,7 +65,6 @@ inline ResolveType makeType(ResolveType type, bool needsVarInjectionChecks) case GlobalVar: return GlobalVarWithVarInjectionChecks; case ClosureVar: - case LocalClosureVar: return ClosureVarWithVarInjectionChecks; case GlobalPropertyWithVarInjectionChecks: case GlobalVarWithVarInjectionChecks: @@ -89,7 +83,6 @@ inline bool needsVarInjectionChecks(ResolveType type) case GlobalProperty: case GlobalVar: case ClosureVar: - case LocalClosureVar: return false; case GlobalPropertyWithVarInjectionChecks: case GlobalVarWithVarInjectionChecks: @@ -103,11 +96,11 @@ inline bool needsVarInjectionChecks(ResolveType type) } struct ResolveOp { - ResolveOp(ResolveType type, size_t depth, Structure* structure, JSLexicalEnvironment* lexicalEnvironment, WatchpointSet* watchpointSet, uintptr_t operand) + ResolveOp(ResolveType type, size_t depth, Structure* structure, JSActivation* activation, VariableWatchpointSet* watchpointSet, uintptr_t operand) : type(type) , depth(depth) , structure(structure) - , lexicalEnvironment(lexicalEnvironment) + , activation(activation) , watchpointSet(watchpointSet) , operand(operand) { @@ -116,8 +109,8 @@ struct ResolveOp { ResolveType type; size_t depth; Structure* structure; - JSLexicalEnvironment* lexicalEnvironment; - WatchpointSet* watchpointSet; + JSActivation* activation; + VariableWatchpointSet* watchpointSet; uintptr_t operand; }; @@ -150,27 +143,21 @@ enum GetOrPut { Get, Put }; class JSScope : public JSNonFinalObject { public: typedef JSNonFinalObject Base; - static const unsigned StructureFlags = Base::StructureFlags; friend class LLIntOffsetsExtractor; static size_t offsetOfNext(); - static JSObject* objectAtScope(JSScope*); + JS_EXPORT_PRIVATE static JSObject* objectAtScope(JSScope*); static JSValue resolve(ExecState*, JSScope*, const Identifier&); - static ResolveOp abstractResolve(ExecState*, size_t depthOffset, JSScope*, const Identifier&, GetOrPut, ResolveType); - - static void collectVariablesUnderTDZ(JSScope*, VariableEnvironment& result); + static ResolveOp abstractResolve(ExecState*, JSScope*, const Identifier&, GetOrPut, ResolveType); static void visitChildren(JSCell*, SlotVisitor&); - bool isLexicalScope(); - bool isCatchScope(); - bool isFunctionNameScopeObject(); - ScopeChainIterator begin(); ScopeChainIterator end(); JSScope* next(); + int depth(); JSGlobalObject* globalObject(); VM* vm(); @@ -178,6 +165,7 @@ public: protected: JSScope(VM&, Structure*, JSScope* next); + static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; private: WriteBarrier<JSScope> m_next; @@ -198,7 +186,6 @@ public: JSObject* get() const { return JSScope::objectAtScope(m_node); } JSObject* operator->() const { return JSScope::objectAtScope(m_node); } - JSScope* scope() const { return m_node; } ScopeChainIterator& operator++() { m_node = m_node->next(); return *this; } @@ -247,9 +234,20 @@ inline JSScope* Register::scope() const return jsCast<JSScope*>(jsValue()); } +inline VM& ExecState::vm() const +{ + ASSERT(scope()->vm()); + return *scope()->vm(); +} + inline JSGlobalObject* ExecState::lexicalGlobalObject() const { - return callee()->globalObject(); + return scope()->globalObject(); +} + +inline JSObject* ExecState::globalThisValue() const +{ + return scope()->globalThis(); } inline size_t JSScope::offsetOfNext() diff --git a/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp b/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp index 2502fa839..fedb8711b 100644 --- a/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp +++ b/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013, 2015 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 @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -29,44 +29,48 @@ #include "config.h" #include "JSSegmentedVariableObject.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { -ScopeOffset JSSegmentedVariableObject::findVariableIndex(void* variableAddress) +int JSSegmentedVariableObject::findRegisterIndex(void* registerAddress) { ConcurrentJITLocker locker(m_lock); - for (unsigned i = m_variables.size(); i--;) { - if (&m_variables[i] != variableAddress) + for (int i = m_registers.size(); i--;) { + if (&m_registers[i] != registerAddress) continue; - return ScopeOffset(i); + return i; } CRASH(); - return ScopeOffset(); + return -1; } -ScopeOffset JSSegmentedVariableObject::addVariables(unsigned numberOfVariablesToAdd) +int JSSegmentedVariableObject::addRegisters(int numberOfRegistersToAdd) { ConcurrentJITLocker locker(m_lock); - size_t oldSize = m_variables.size(); - m_variables.grow(oldSize + numberOfVariablesToAdd); + ASSERT(numberOfRegistersToAdd >= 0); - for (size_t i = numberOfVariablesToAdd; i--;) - m_variables[oldSize + i].setWithoutWriteBarrier(jsUndefined()); + size_t oldSize = m_registers.size(); + m_registers.grow(oldSize + numberOfRegistersToAdd); - return ScopeOffset(oldSize); + for (size_t i = numberOfRegistersToAdd; i--;) + m_registers[oldSize + i].setWithoutWriteBarrier(jsUndefined()); + + return static_cast<int>(oldSize); } void JSSegmentedVariableObject::visitChildren(JSCell* cell, SlotVisitor& slotVisitor) { JSSegmentedVariableObject* thisObject = jsCast<JSSegmentedVariableObject*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); JSSymbolTableObject::visitChildren(thisObject, slotVisitor); - for (unsigned i = thisObject->m_variables.size(); i--;) - slotVisitor.append(&thisObject->m_variables[i]); + for (unsigned i = thisObject->m_registers.size(); i--;) + slotVisitor.append(&thisObject->m_registers[i]); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h b/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h index feaf0bb0e..70f877f3e 100644 --- a/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h +++ b/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013, 2015 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 @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -41,11 +41,11 @@ namespace JSC { class LLIntOffsetsExtractor; class Register; -// This is a mostly drop-in replacement for JSEnvironmentRecord, except that it preserves +// This is a mostly drop-in replacement for JSVariableObject, except that it preserves // the invariant that after a variable is created, its address in memory will not change // so long as the JSSegmentedVariableObject is alive. This allows optimizations based // on getting the address of the variable and remembering it. As well, unlike a -// JSEnvironmentRecord, this will manage the memory for the registers itself and neither +// JSVariableObject, this will manage the memory for the registers itself and neither // requires nor allows for the subclasses to manage that memory. Finally, // JSSegmentedVariableObject has its own GC tracing functionality, since it knows the // exact dimensions of the variables array at all times. @@ -57,31 +57,30 @@ class JSSegmentedVariableObject : public JSSymbolTableObject { public: typedef JSSymbolTableObject Base; - // This is not thread-safe, since m_variables is a segmented vector, and its spine can resize with - // malloc/free if new variables - unrelated to the one you are accessing - are added. You can get - // around this by grabbing m_lock, or finding some other way to get to the variable pointer (global - // variable access bytecode instructions will have a direct pointer already). - WriteBarrier<Unknown>& variableAt(ScopeOffset offset) { return m_variables[offset.offset()]; } + WriteBarrier<Unknown>& registerAt(int index) { return m_registers[index]; } // This is a slow method call, which searches the register bank to find the index // given a pointer. It will CRASH() if it does not find the register. Only use this // in debug code (like bytecode dumping). - JS_EXPORT_PRIVATE ScopeOffset findVariableIndex(void*); + JS_EXPORT_PRIVATE int findRegisterIndex(void*); - WriteBarrier<Unknown>* assertVariableIsInThisObject(WriteBarrier<Unknown>* variablePointer) + WriteBarrier<Unknown>* assertRegisterIsInThisObject(WriteBarrier<Unknown>* registerPointer) { - if (!ASSERT_DISABLED) - findVariableIndex(variablePointer); - return variablePointer; +#if !ASSERT_DISABLED + findRegisterIndex(registerPointer); +#endif + return registerPointer; } // Adds numberOfRegistersToAdd registers, initializes them to Undefined, and returns // the index of the first one added. - JS_EXPORT_PRIVATE ScopeOffset addVariables(unsigned numberOfVariablesToAdd); + JS_EXPORT_PRIVATE int addRegisters(int numberOfRegistersToAdd); JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); protected: + static const unsigned StructureFlags = OverridesVisitChildren | JSSymbolTableObject::StructureFlags; + JSSegmentedVariableObject(VM& vm, Structure* structure, JSScope* scope) : JSSymbolTableObject(vm, structure, scope) { @@ -90,10 +89,9 @@ protected: void finishCreation(VM& vm) { Base::finishCreation(vm); - setSymbolTable(vm, SymbolTable::create(vm)); } - SegmentedVector<WriteBarrier<Unknown>, 16> m_variables; + SegmentedVector<WriteBarrier<Unknown>, 16> m_registers; ConcurrentJITLock m_lock; }; diff --git a/Source/JavaScriptCore/runtime/JSSet.cpp b/Source/JavaScriptCore/runtime/JSSet.cpp index d875345da..fdb6df548 100644 --- a/Source/JavaScriptCore/runtime/JSSet.cpp +++ b/Source/JavaScriptCore/runtime/JSSet.cpp @@ -27,56 +27,24 @@ #include "JSSet.h" #include "JSCJSValueInlines.h" -#include "JSSetIterator.h" -#include "MapDataInlines.h" +#include "MapData.h" #include "SlotVisitorInlines.h" -#include "StructureInlines.h" namespace JSC { -const ClassInfo JSSet::s_info = { "Set", &Base::s_info, 0, CREATE_METHOD_TABLE(JSSet) }; - -void JSSet::destroy(JSCell* cell) -{ - JSSet* thisObject = jsCast<JSSet*>(cell); - thisObject->JSSet::~JSSet(); -} +const ClassInfo JSSet::s_info = { "Set", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSSet) }; void JSSet::visitChildren(JSCell* cell, SlotVisitor& visitor) { Base::visitChildren(cell, visitor); - jsCast<JSSet*>(cell)->m_setData.visitChildren(cell, visitor); -} - -void JSSet::copyBackingStore(JSCell* cell, CopyVisitor& visitor, CopyToken token) -{ - Base::copyBackingStore(cell, visitor, token); - jsCast<JSSet*>(cell)->m_setData.copyBackingStore(visitor, token); -} - -bool JSSet::has(ExecState* exec, JSValue value) -{ - return m_setData.contains(exec, value); -} - -size_t JSSet::size(ExecState* exec) -{ - return m_setData.size(exec); -} - -void JSSet::add(ExecState* exec, JSValue value) -{ - m_setData.set(exec, this, value, value); -} - -void JSSet::clear(ExecState*) -{ - m_setData.clear(); + JSSet* thisObject = jsCast<JSSet*>(cell); + visitor.append(&thisObject->m_mapData); } -bool JSSet::remove(ExecState* exec, JSValue value) +void JSSet::finishCreation(VM& vm) { - return m_setData.remove(exec, value); + Base::finishCreation(vm); + m_mapData.set(vm, this, MapData::create(vm)); } } diff --git a/Source/JavaScriptCore/runtime/JSSet.h b/Source/JavaScriptCore/runtime/JSSet.h index e55362ebb..22c5d860b 100644 --- a/Source/JavaScriptCore/runtime/JSSet.h +++ b/Source/JavaScriptCore/runtime/JSSet.h @@ -26,63 +26,15 @@ #ifndef JSSet_h #define JSSet_h -#include "JSDestructibleObject.h" #include "JSObject.h" -#include "MapData.h" namespace JSC { -class JSSetIterator; +class MapData; -class JSSet : public JSDestructibleObject { +class JSSet : public JSNonFinalObject { public: - typedef JSDestructibleObject Base; - - friend class JSSetIterator; - - // Our marking functions expect Entry to maintain this layout, and have all - // fields be WriteBarrier<Unknown> - class Entry { - private: - WriteBarrier<Unknown> m_key; - - public: - const WriteBarrier<Unknown>& key() const - { - return m_key; - } - - const WriteBarrier<Unknown>& value() const - { - return m_key; - } - - void visitChildren(SlotVisitor& visitor) - { - visitor.append(&m_key); - } - - void setKey(VM& vm, const JSCell* owner, JSValue key) - { - m_key.set(vm, owner, key); - } - - void setKeyWithoutWriteBarrier(JSValue key) - { - m_key.setWithoutWriteBarrier(key); - } - - void setValue(VM&, const JSCell*, JSValue) - { - } - - void clear() - { - m_key.clear(); - } - }; - - typedef MapDataImpl<Entry, JSSetIterator> SetData; + typedef JSNonFinalObject Base; DECLARE_EXPORT_INFO; @@ -103,24 +55,22 @@ public: return create(exec->vm(), structure); } - bool has(ExecState*, JSValue); - size_t size(ExecState*); - JS_EXPORT_PRIVATE void add(ExecState*, JSValue); - void clear(ExecState*); - bool remove(ExecState*, JSValue); + MapData* mapData() { return m_mapData.get(); } private: + + static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; + JSSet(VM& vm, Structure* structure) : Base(vm, structure) - , m_setData(vm) { } - static void destroy(JSCell*); + JS_EXPORT_PRIVATE void finishCreation(VM&); + static void visitChildren(JSCell*, SlotVisitor&); - static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken); - - SetData m_setData; + + WriteBarrier<MapData> m_mapData; }; } diff --git a/Source/JavaScriptCore/runtime/JSSetIterator.cpp b/Source/JavaScriptCore/runtime/JSSetIterator.cpp index 3a0ddbeab..b1d8a6512 100644 --- a/Source/JavaScriptCore/runtime/JSSetIterator.cpp +++ b/Source/JavaScriptCore/runtime/JSSetIterator.cpp @@ -29,32 +29,27 @@ #include "JSCJSValueInlines.h" #include "JSCellInlines.h" #include "JSSet.h" -#include "MapDataInlines.h" #include "SlotVisitorInlines.h" -#include "StructureInlines.h" namespace JSC { -const ClassInfo JSSetIterator::s_info = { "Set Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(JSSetIterator) }; +const ClassInfo JSSetIterator::s_info = { "Set Iterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSSetIterator) }; void JSSetIterator::finishCreation(VM& vm, JSSet* iteratedObject) { Base::finishCreation(vm); - m_set.set(vm, this, iteratedObject); + m_iteratedObjectData.set(vm, this, iteratedObject->mapData()); } void JSSetIterator::visitChildren(JSCell* cell, SlotVisitor& visitor) { JSSetIterator* thisObject = jsCast<JSSetIterator*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + Base::visitChildren(thisObject, visitor); - visitor.append(&thisObject->m_set); -} - -void JSSetIterator::destroy(JSCell* cell) -{ - JSSetIterator* thisObject = jsCast<JSSetIterator*>(cell); - thisObject->JSSetIterator::~JSSetIterator(); + visitor.append(&thisObject->m_iteratedObjectData); } JSValue JSSetIterator::createPair(CallFrame* callFrame, JSValue key, JSValue value) @@ -66,11 +61,4 @@ JSValue JSSetIterator::createPair(CallFrame* callFrame, JSValue key, JSValue val return constructArray(callFrame, 0, globalObject, args); } -JSSetIterator* JSSetIterator::clone(ExecState* exec) -{ - auto clone = JSSetIterator::create(exec->vm(), exec->callee()->globalObject()->setIteratorStructure(), m_set.get(), m_kind); - clone->m_iterator = m_iterator; - return clone; -} - } diff --git a/Source/JavaScriptCore/runtime/JSSetIterator.h b/Source/JavaScriptCore/runtime/JSSetIterator.h index 6dad6b1b9..edf3bfbf9 100644 --- a/Source/JavaScriptCore/runtime/JSSetIterator.h +++ b/Source/JavaScriptCore/runtime/JSSetIterator.h @@ -58,13 +58,13 @@ public: bool next(CallFrame* callFrame, JSValue& value) { - WTF::KeyValuePair<JSValue, JSValue> pair; - if (!m_iterator.next(pair)) + if (!m_iterator.ensureSlot()) return false; if (m_kind == SetIterateValue || m_kind == SetIterateKey) - value = pair.key; + value = m_iterator.key(); else - value = createPair(callFrame, pair.key, pair.key); + value = createPair(callFrame, m_iterator.key(), m_iterator.key()); + ++m_iterator; return true; } @@ -73,30 +73,23 @@ public: m_iterator.finish(); } - SetIterationKind kind() const { return m_kind; } - JSValue iteratedValue() const { return m_set.get(); } - JSSetIterator* clone(ExecState*); +private: - JSSet::SetData::IteratorData* iteratorData() - { - return &m_iterator; - } + static const unsigned StructureFlags = Base::StructureFlags | OverridesVisitChildren; -private: JSSetIterator(VM& vm, Structure* structure, JSSet* iteratedObject, SetIterationKind kind) : Base(vm, structure) - , m_iterator(iteratedObject->m_setData.createIteratorData(this)) + , m_iterator(iteratedObject->mapData()->begin()) , m_kind(kind) { } - static void destroy(JSCell*); - JS_EXPORT_PRIVATE void finishCreation(VM&, JSSet*); - JS_EXPORT_PRIVATE JSValue createPair(CallFrame*, JSValue, JSValue); + void finishCreation(VM&, JSSet*); + JSValue createPair(CallFrame*, JSValue, JSValue); static void visitChildren(JSCell*, SlotVisitor&); - WriteBarrier<JSSet> m_set; - JSSet::SetData::IteratorData m_iterator; + WriteBarrier<MapData> m_iteratedObjectData; + MapData::const_iterator m_iterator; SetIterationKind m_kind; }; diff --git a/Source/JavaScriptCore/runtime/JSString.cpp b/Source/JavaScriptCore/runtime/JSString.cpp index eb046ed2d..3e4e3ffa1 100644 --- a/Source/JavaScriptCore/runtime/JSString.cpp +++ b/Source/JavaScriptCore/runtime/JSString.cpp @@ -26,14 +26,13 @@ #include "JSGlobalObject.h" #include "JSGlobalObjectFunctions.h" #include "JSObject.h" -#include "JSCInlines.h" +#include "Operations.h" #include "StringObject.h" #include "StringPrototype.h" -#include "StrongInlines.h" namespace JSC { -const ClassInfo JSString::s_info = { "string", 0, 0, CREATE_METHOD_TABLE(JSString) }; +const ClassInfo JSString::s_info = { "string", 0, 0, 0, CREATE_METHOD_TABLE(JSString) }; void JSRopeString::RopeBuilder::expand() { @@ -51,218 +50,98 @@ void JSString::destroy(JSCell* cell) thisObject->JSString::~JSString(); } -void JSString::dumpToStream(const JSCell* cell, PrintStream& out) -{ - const JSString* thisObject = jsCast<const JSString*>(cell); - out.printf("<%p, %s, [%u], ", thisObject, thisObject->className(), thisObject->length()); - if (thisObject->isRope()) - out.printf("[rope]"); - else { - WTF::StringImpl* ourImpl = thisObject->m_value.impl(); - if (ourImpl->is8Bit()) - out.printf("[8 %p]", ourImpl->characters8()); - else - out.printf("[16 %p]", ourImpl->characters16()); - } - out.printf(">"); -} - void JSString::visitChildren(JSCell* cell, SlotVisitor& visitor) { JSString* thisObject = jsCast<JSString*>(cell); Base::visitChildren(thisObject, visitor); + MARK_LOG_MESSAGE1("[%u]: ", thisObject->length()); + +#if ENABLE(OBJECT_MARK_LOGGING) + if (!thisObject->isRope()) { + WTF::StringImpl* ourImpl = thisObject->m_value.impl(); + if (ourImpl->is8Bit()) + MARK_LOG_MESSAGE1("[8 %p]", ourImpl->characters8()); + else + MARK_LOG_MESSAGE1("[16 %p]", ourImpl->characters16()); + } else + MARK_LOG_MESSAGE0("[rope]: "); +#endif + if (thisObject->isRope()) static_cast<JSRopeString*>(thisObject)->visitFibers(visitor); else { StringImpl* impl = thisObject->m_value.impl(); ASSERT(impl); - visitor.reportExtraMemoryVisited(thisObject, impl->costDuringGC()); + visitor.reportExtraMemoryUsage(thisObject, impl->costDuringGC()); } } void JSRopeString::visitFibers(SlotVisitor& visitor) { - if (isSubstring()) { - visitor.append(&substringBase()); - return; - } - for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) - visitor.append(&fiber(i)); -} - -static const unsigned maxLengthForOnStackResolve = 2048; - -void JSRopeString::resolveRopeInternal8(LChar* buffer) const -{ - if (isSubstring()) { - StringImpl::copyChars( - buffer, substringBase()->m_value.characters8() + substringOffset(), m_length); - return; - } - - resolveRopeInternal8NoSubstring(buffer); -} - -void JSRopeString::resolveRopeInternal8NoSubstring(LChar* buffer) const -{ - for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) { - if (fiber(i)->isRope()) { - resolveRopeSlowCase8(buffer); - return; - } - } - - LChar* position = buffer; - for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) { - const StringImpl& fiberString = *fiber(i)->m_value.impl(); - unsigned length = fiberString.length(); - StringImpl::copyChars(position, fiberString.characters8(), length); - position += length; - } - ASSERT((buffer + m_length) == position); -} - -void JSRopeString::resolveRopeInternal16(UChar* buffer) const -{ - if (isSubstring()) { - StringImpl::copyChars( - buffer, substringBase()->m_value.characters16() + substringOffset(), m_length); - return; - } - - resolveRopeInternal16NoSubstring(buffer); -} - -void JSRopeString::resolveRopeInternal16NoSubstring(UChar* buffer) const -{ - for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) { - if (fiber(i)->isRope()) { - resolveRopeSlowCase(buffer); - return; - } - } - - UChar* position = buffer; - for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) { - const StringImpl& fiberString = *fiber(i)->m_value.impl(); - unsigned length = fiberString.length(); - if (fiberString.is8Bit()) - StringImpl::copyChars(position, fiberString.characters8(), length); - else - StringImpl::copyChars(position, fiberString.characters16(), length); - position += length; - } - ASSERT((buffer + m_length) == position); -} - -void JSRopeString::resolveRopeToAtomicString(ExecState* exec) const -{ - if (m_length > maxLengthForOnStackResolve) { - resolveRope(exec); - m_value = AtomicString(m_value); - setIs8Bit(m_value.impl()->is8Bit()); - return; - } - - if (is8Bit()) { - LChar buffer[maxLengthForOnStackResolve]; - resolveRopeInternal8(buffer); - m_value = AtomicString(buffer, m_length); - setIs8Bit(m_value.impl()->is8Bit()); - } else { - UChar buffer[maxLengthForOnStackResolve]; - resolveRopeInternal16(buffer); - m_value = AtomicString(buffer, m_length); - setIs8Bit(m_value.impl()->is8Bit()); - } - - clearFibers(); - - // If we resolved a string that didn't previously exist, notify the heap that we've grown. - if (m_value.impl()->hasOneRef()) - Heap::heap(this)->reportExtraMemoryAllocated(m_value.impl()->cost()); -} - -void JSRopeString::clearFibers() const -{ - for (size_t i = 0; i < s_maxInternalRopeLength; ++i) - u[i].number = 0; -} - -RefPtr<AtomicStringImpl> JSRopeString::resolveRopeToExistingAtomicString(ExecState* exec) const -{ - if (m_length > maxLengthForOnStackResolve) { - resolveRope(exec); - if (RefPtr<AtomicStringImpl> existingAtomicString = AtomicStringImpl::lookUp(m_value.impl())) { - m_value = *existingAtomicString; - setIs8Bit(m_value.impl()->is8Bit()); - clearFibers(); - return existingAtomicString; - } - return nullptr; - } - - if (is8Bit()) { - LChar buffer[maxLengthForOnStackResolve]; - resolveRopeInternal8(buffer); - if (RefPtr<AtomicStringImpl> existingAtomicString = AtomicStringImpl::lookUp(buffer, m_length)) { - m_value = *existingAtomicString; - setIs8Bit(m_value.impl()->is8Bit()); - clearFibers(); - return existingAtomicString; - } - } else { - UChar buffer[maxLengthForOnStackResolve]; - resolveRopeInternal16(buffer); - if (RefPtr<AtomicStringImpl> existingAtomicString = AtomicStringImpl::lookUp(buffer, m_length)) { - m_value = *existingAtomicString; - setIs8Bit(m_value.impl()->is8Bit()); - clearFibers(); - return existingAtomicString; - } - } - - return nullptr; + for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) + visitor.append(&m_fibers[i]); } void JSRopeString::resolveRope(ExecState* exec) const { ASSERT(isRope()); - - if (isSubstring()) { - ASSERT(!substringBase()->isRope()); - m_value = substringBase()->m_value.substring(substringOffset(), m_length); - substringBase().clear(); - return; - } - + if (is8Bit()) { LChar* buffer; if (RefPtr<StringImpl> newImpl = StringImpl::tryCreateUninitialized(m_length, buffer)) { - Heap::heap(this)->reportExtraMemoryAllocated(newImpl->cost()); + Heap::heap(this)->reportExtraMemoryCost(newImpl->cost()); m_value = newImpl.release(); } else { outOfMemory(exec); return; } - resolveRopeInternal8NoSubstring(buffer); - clearFibers(); + + for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) { + if (m_fibers[i]->isRope()) + return resolveRopeSlowCase8(buffer); + } + + LChar* position = buffer; + for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) { + StringImpl* string = m_fibers[i]->m_value.impl(); + unsigned length = string->length(); + StringImpl::copyChars(position, string->characters8(), length); + position += length; + m_fibers[i].clear(); + } + ASSERT((buffer + m_length) == position); ASSERT(!isRope()); + return; } UChar* buffer; if (RefPtr<StringImpl> newImpl = StringImpl::tryCreateUninitialized(m_length, buffer)) { - Heap::heap(this)->reportExtraMemoryAllocated(newImpl->cost()); + Heap::heap(this)->reportExtraMemoryCost(newImpl->cost()); m_value = newImpl.release(); } else { outOfMemory(exec); return; } - resolveRopeInternal16NoSubstring(buffer); - clearFibers(); + for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) { + if (m_fibers[i]->isRope()) + return resolveRopeSlowCase(buffer); + } + + UChar* position = buffer; + for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) { + StringImpl* string = m_fibers[i]->m_value.impl(); + unsigned length = string->length(); + if (string->is8Bit()) + StringImpl::copyChars(position, string->characters8(), length); + else + StringImpl::copyChars(position, string->characters16(), length); + position += length; + m_fibers[i].clear(); + } + ASSERT((buffer + m_length) == position); ASSERT(!isRope()); } @@ -281,35 +160,31 @@ void JSRopeString::resolveRopeSlowCase8(LChar* buffer) const LChar* position = buffer + m_length; // We will be working backwards over the rope. 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 && fiber(i); ++i) - workQueue.append(fiber(i).get()); + for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) { + workQueue.append(m_fibers[i].get()); + // Clearing here works only because there are no GC points in this method. + m_fibers[i].clear(); + } while (!workQueue.isEmpty()) { JSString* currentFiber = workQueue.last(); workQueue.removeLast(); - const LChar* characters; - if (currentFiber->isRope()) { JSRopeString* currentFiberAsRope = static_cast<JSRopeString*>(currentFiber); - if (!currentFiberAsRope->isSubstring()) { - for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->fiber(i); ++i) - workQueue.append(currentFiberAsRope->fiber(i).get()); - continue; - } - ASSERT(!currentFiberAsRope->substringBase()->isRope()); - characters = - currentFiberAsRope->substringBase()->m_value.characters8() + - currentFiberAsRope->substringOffset(); - } else - characters = currentFiber->m_value.characters8(); - - unsigned length = currentFiber->length(); + for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->m_fibers[i]; ++i) + workQueue.append(currentFiberAsRope->m_fibers[i].get()); + continue; + } + + StringImpl* string = static_cast<StringImpl*>(currentFiber->m_value.impl()); + unsigned length = string->length(); position -= length; - StringImpl::copyChars(position, characters, length); + StringImpl::copyChars(position, string->characters8(), length); } ASSERT(buffer == position); + ASSERT(!isRope()); } void JSRopeString::resolveRopeSlowCase(UChar* buffer) const @@ -317,8 +192,8 @@ void JSRopeString::resolveRopeSlowCase(UChar* buffer) const UChar* position = buffer + m_length; // We will be working backwards over the rope. 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 && fiber(i); ++i) - workQueue.append(fiber(i).get()); + for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) + workQueue.append(m_fibers[i].get()); while (!workQueue.isEmpty()) { JSString* currentFiber = workQueue.last(); @@ -326,21 +201,8 @@ void JSRopeString::resolveRopeSlowCase(UChar* buffer) const if (currentFiber->isRope()) { JSRopeString* currentFiberAsRope = static_cast<JSRopeString*>(currentFiber); - if (currentFiberAsRope->isSubstring()) { - ASSERT(!currentFiberAsRope->substringBase()->isRope()); - StringImpl* string = static_cast<StringImpl*>( - currentFiberAsRope->substringBase()->m_value.impl()); - unsigned offset = currentFiberAsRope->substringOffset(); - unsigned length = currentFiberAsRope->length(); - position -= length; - if (string->is8Bit()) - StringImpl::copyChars(position, string->characters8() + offset, length); - else - StringImpl::copyChars(position, string->characters16() + offset, length); - continue; - } - for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->fiber(i); ++i) - workQueue.append(currentFiberAsRope->fiber(i).get()); + for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->m_fibers[i]; ++i) + workQueue.append(currentFiberAsRope->m_fibers[i].get()); continue; } @@ -354,17 +216,31 @@ void JSRopeString::resolveRopeSlowCase(UChar* buffer) const } ASSERT(buffer == position); + ASSERT(!isRope()); } void JSRopeString::outOfMemory(ExecState* exec) const { - clearFibers(); + for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) + m_fibers[i].clear(); ASSERT(isRope()); ASSERT(m_value.isNull()); if (exec) throwOutOfMemoryError(exec); } +JSString* JSRopeString::getIndexSlowCase(ExecState* exec, unsigned i) +{ + ASSERT(isRope()); + resolveRope(exec); + // Return a safe no-value result, this should never be used, since the excetion will be thrown. + if (exec->exception()) + return jsEmptyString(exec); + ASSERT(!isRope()); + RELEASE_ASSERT(i < m_value.length()); + return jsSingleCharacterSubstring(exec, m_value, i); +} + JSValue JSString::toPrimitive(ExecState*, PreferredPrimitiveType) const { return const_cast<JSString*>(this); @@ -373,13 +249,18 @@ JSValue JSString::toPrimitive(ExecState*, PreferredPrimitiveType) const bool JSString::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result) const { result = this; - number = jsToNumber(view(exec)); + number = jsToNumber(value(exec)); return false; } +bool JSString::toBoolean() const +{ + return m_length; +} + double JSString::toNumber(ExecState* exec) const { - return jsToNumber(view(exec)); + return jsToNumber(value(exec)); } inline StringObject* StringObject::create(VM& vm, JSGlobalObject* globalObject, JSString* string) @@ -408,23 +289,14 @@ bool JSString::getStringPropertyDescriptor(ExecState* exec, PropertyName propert return true; } - Optional<uint32_t> index = parseIndex(propertyName); - if (index && index.value() < m_length) { - descriptor.setDescriptor(getIndex(exec, index.value()), DontDelete | ReadOnly); + unsigned i = propertyName.asIndex(); + if (i < m_length) { + ASSERT(i != PropertyName::NotAnIndex); // No need for an explicit check, the above test would always fail! + descriptor.setDescriptor(getIndex(exec, i), DontDelete | ReadOnly); return true; } return false; } -JSString* jsStringWithCacheSlowCase(VM& vm, StringImpl& stringImpl) -{ - if (JSString* string = vm.stringCache.get(&stringImpl)) - return string; - - JSString* string = jsString(&vm, String(stringImpl)); - vm.lastCachedString.set(vm, string); - return string; -} - } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSString.h b/Source/JavaScriptCore/runtime/JSString.h index 068f52fbb..448ffc484 100644 --- a/Source/JavaScriptCore/runtime/JSString.h +++ b/Source/JavaScriptCore/runtime/JSString.h @@ -30,748 +30,537 @@ #include "PropertySlot.h" #include "Structure.h" #include <array> -#include <wtf/text/StringView.h> namespace JSC { -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* jsSubstring(VM*, const String&, unsigned offset, unsigned length); -JSString* jsSubstring(ExecState*, const String&, unsigned offset, unsigned length); -JSString* jsSubstring8(VM*, const String&, unsigned offset, unsigned length); -JSString* jsSubstring8(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&); -JSString* jsNontrivialString(ExecState*, 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*); - -bool isJSString(JSValue); -JSString* asString(JSValue); - -struct StringViewWithUnderlyingString { - StringView view; - String underlyingString; -}; - -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 unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | StructureIsImmortal; - - static const bool needsDestruction = true; - static void destroy(JSCell*); - -private: - JSString(VM& vm, PassRefPtr<StringImpl> value) - : JSCell(vm, vm.stringStructure.get()) - , m_flags(0) - , m_value(value) - { - } + class JSString; + class JSRopeString; + class LLIntOffsetsExtractor; - JSString(VM& vm) - : JSCell(vm, vm.stringStructure.get()) - , m_flags(0) - { - } + 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 - 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++; - } + 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); - 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)->reportExtraMemoryAllocated(cost); - vm.m_newStringsSinceLastHashCons++; - } + // 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&); -protected: - void finishCreation(VM& vm) - { - Base::finishCreation(vm); - m_length = 0; - setIs8Bit(true); - vm.m_newStringsSinceLastHashCons++; - } + // 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&); -public: - static JSString* create(VM& vm, PassRefPtr<StringImpl> value) - { - ASSERT(value); - int32_t length = value->length(); - RELEASE_ASSERT(length >= 0); - 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; - } + JSRopeString* jsStringBuilder(VM*); - Identifier toIdentifier(ExecState*) const; - AtomicString toAtomicString(ExecState*) const; - RefPtr<AtomicStringImpl> toExistingAtomicString(ExecState*) const; + 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; - class SafeView; - SafeView view(ExecState*) const; - StringViewWithUnderlyingString viewWithUnderlyingString(ExecState&) const; + typedef JSCell Base; - const String& value(ExecState*) const; - const String& tryGetValue() const; - const StringImpl* tryGetValueImpl() const; - unsigned length() const { return m_length; } + static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; + static void destroy(JSCell*); - JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; - bool toBoolean() const { return !!m_length; } - bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const; - JSObject* toObject(ExecState*, JSGlobalObject*) const; - double toNumber(ExecState*) const; + private: + JSString(VM& vm, PassRefPtr<StringImpl> value) + : JSCell(vm, vm.stringStructure.get()) + , m_flags(0) + , m_value(value) + { + } - bool getStringPropertySlot(ExecState*, PropertyName, PropertySlot&); - bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); - bool getStringPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&); + JSString(VM& vm) + : JSCell(vm, vm.stringStructure.get()) + , m_flags(0) + { + } - bool canGetIndex(unsigned i) { return i < m_length; } - JSString* getIndex(ExecState*, unsigned); + 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++; + } - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) - { - return Structure::create(vm, globalObject, proto, TypeInfo(StringType, StructureFlags), info()); - } + 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++; + } - 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); } + protected: + void finishCreation(VM& vm) + { + Base::finishCreation(vm); + m_length = 0; + setIs8Bit(true); + vm.m_newStringsSinceLastHashCons++; + } + + public: + static JSString* create(VM& vm, PassRefPtr<StringImpl> value) + { + ASSERT(value); + int32_t length = value->length(); + RELEASE_ASSERT(length >= 0); + 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; + } - DECLARE_EXPORT_INFO; + const String& value(ExecState*) const; + const String& tryGetValue() const; + const StringImpl* tryGetValueImpl() 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; + + 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); + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) + { + return Structure::create(vm, globalObject, proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero), info()); + } - static void dumpToStream(const JSCell*, PrintStream&); - static void visitChildren(JSCell*, SlotVisitor&); + 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); } - enum { - HashConsLock = 1u << 2, - IsHashConsSingleton = 1u << 1, - Is8Bit = 1u - }; + DECLARE_EXPORT_INFO; -protected: - friend class JSValue; + static void visitChildren(JSCell*, SlotVisitor&); - bool isRope() const { return m_value.isNull(); } - bool isSubstring() const; - bool is8Bit() const { return m_flags & Is8Bit; } - void setIs8Bit(bool flag) const - { - 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(); + enum { + HashConsLock = 1u << 2, + IsHashConsSingleton = 1u << 1, + Is8Bit = 1u + }; - mutable unsigned m_flags; + 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; - // A string is represented either by a String or a rope of fibers. - unsigned m_length; - mutable String m_value; + private: + friend class LLIntOffsetsExtractor; + + static JSValue toThis(JSCell*, ExecState*, ECMAMode); -private: - friend class LLIntOffsetsExtractor; + String& string() { ASSERT(!isRope()); return m_value; } - static JSValue toThis(JSCell*, ExecState*, ECMAMode); + friend JSValue jsString(ExecState*, JSString*, JSString*); + friend JSString* jsSubstring(ExecState*, JSString*, unsigned offset, unsigned length); + }; - String& string() { ASSERT(!isRope()); return m_value; } - StringView unsafeView(ExecState&) const; + class JSRopeString : public JSString { + friend class JSString; - friend JSValue jsString(ExecState*, JSString*, JSString*); - friend JSString* jsSubstring(ExecState*, JSString*, unsigned offset, unsigned length); -}; + friend JSRopeString* jsStringBuilder(VM*); -class JSRopeString final : public JSString { - friend class JSString; + class RopeBuilder { + public: + RopeBuilder(VM& vm) + : m_vm(vm) + , m_jsString(jsStringBuilder(&vm)) + , m_index(0) + { + } - friend JSRopeString* jsStringBuilder(VM*); + bool append(JSString* jsString) + { + if (m_index == JSRopeString::s_maxInternalRopeLength) + expand(); + if (static_cast<int32_t>(m_jsString->length() + jsString->length()) < 0) { + m_jsString = nullptr; + return false; + } + m_jsString->append(m_vm, m_index++, jsString); + return true; + } -public: - class RopeBuilder { - public: - RopeBuilder(VM& vm) - : m_vm(vm) - , m_jsString(jsStringBuilder(&vm)) - , m_index(0) + JSRopeString* release() + { + RELEASE_ASSERT(m_jsString); + JSRopeString* tmp = m_jsString; + m_jsString = 0; + return tmp; + } + + unsigned length() { return m_jsString->m_length; } + + private: + void expand(); + + VM& m_vm; + JSRopeString* m_jsString; + size_t m_index; + }; + + private: + JSRopeString(VM& vm) + : JSString(vm) { } - bool append(JSString* jsString) + void finishCreation(VM& vm, JSString* s1, JSString* s2) { - if (m_index == JSRopeString::s_maxInternalRopeLength) - expand(); - if (static_cast<int32_t>(m_jsString->length() + jsString->length()) < 0) { - m_jsString = nullptr; - return false; - } - m_jsString->append(m_vm, m_index++, jsString); - return true; + 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); + } + + void finishCreation(VM& vm, JSString* s1, JSString* s2, JSString* s3) + { + 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); + } + + void finishCreation(VM& vm) + { + JSString::finishCreation(vm); + } + + void append(VM& vm, size_t index, JSString* jsString) + { + m_fibers[index].set(vm, this, jsString); + m_length += jsString->m_length; + RELEASE_ASSERT(static_cast<int32_t>(m_length) >= 0); + setIs8Bit(is8Bit() && jsString->is8Bit()); + } + + static JSRopeString* createNull(VM& vm) + { + JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); + newString->finishCreation(vm); + return newString; } - JSRopeString* release() + public: + static JSString* create(VM& vm, JSString* s1, JSString* s2) + { + JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); + newString->finishCreation(vm, s1, s2); + return newString; + } + static JSString* create(VM& vm, JSString* s1, JSString* s2, JSString* s3) { - RELEASE_ASSERT(m_jsString); - JSRopeString* tmp = m_jsString; - m_jsString = 0; - return tmp; + JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); + newString->finishCreation(vm, s1, s2, s3); + return newString; } - unsigned length() const { return m_jsString->m_length; } + void visitFibers(SlotVisitor&); + + static ptrdiff_t offsetOfFibers() { return OBJECT_OFFSETOF(JSRopeString, m_fibers); } + static const unsigned s_maxInternalRopeLength = 3; + private: - void expand(); + friend JSValue jsStringFromRegisterArray(ExecState*, Register*, unsigned); + friend JSValue jsStringFromArguments(ExecState*, JSValue); - VM& m_vm; - JSRopeString* m_jsString; - size_t m_index; + JS_EXPORT_PRIVATE void resolveRope(ExecState*) const; + void resolveRopeSlowCase8(LChar*) const; + void resolveRopeSlowCase(UChar*) const; + void outOfMemory(ExecState*) const; + + JS_EXPORT_PRIVATE JSString* getIndexSlowCase(ExecState*, unsigned); + + mutable std::array<WriteBarrier<JSString>, s_maxInternalRopeLength> m_fibers; }; -private: - JSRopeString(VM& vm) - : JSString(vm) - { - } - void finishCreation(VM& vm, JSString* s1, JSString* s2) + inline const StringImpl* JSString::tryGetValueImpl() const { - Base::finishCreation(vm); - m_length = s1->length() + s2->length(); - setIs8Bit(s1->is8Bit() && s2->is8Bit()); - setIsSubstring(false); - fiber(0).set(vm, this, s1); - fiber(1).set(vm, this, s2); - fiber(2).clear(); + return m_value.impl(); } - void finishCreation(VM& vm, JSString* s1, JSString* s2, JSString* s3) + JSString* asString(JSValue); + + inline JSString* asString(JSValue value) { - Base::finishCreation(vm); - m_length = s1->length() + s2->length() + s3->length(); - setIs8Bit(s1->is8Bit() && s2->is8Bit() && s3->is8Bit()); - setIsSubstring(false); - fiber(0).set(vm, this, s1); - fiber(1).set(vm, this, s2); - fiber(2).set(vm, this, s3); + ASSERT(value.asCell()->isString()); + return jsCast<JSString*>(value.asCell()); } - void finishCreation(ExecState& exec, JSString& base, unsigned offset, unsigned length) + inline JSString* jsEmptyString(VM* vm) { - VM& vm = exec.vm(); - Base::finishCreation(vm); - ASSERT(!sumOverflows<int32_t>(offset, length)); - ASSERT(offset + length <= base.length()); - m_length = length; - setIs8Bit(base.is8Bit()); - setIsSubstring(true); - if (base.isSubstring()) { - JSRopeString& baseRope = static_cast<JSRopeString&>(base); - substringBase().set(vm, this, baseRope.substringBase().get()); - substringOffset() = baseRope.substringOffset() + offset; - } else { - substringBase().set(vm, this, &base); - substringOffset() = offset; - - // For now, let's not allow substrings with a rope base. - // Resolve non-substring rope bases so we don't have to deal with it. - // FIXME: Evaluate if this would be worth adding more branches. - if (base.isRope()) - static_cast<JSRopeString&>(base).resolveRope(&exec); - } + return vm->smallStrings.emptyString(); } - void finishCreation(VM& vm) + ALWAYS_INLINE JSString* jsSingleCharacterString(VM* vm, UChar c) { - JSString::finishCreation(vm); - setIsSubstring(false); - fiber(0).clear(); - fiber(1).clear(); - fiber(2).clear(); + if (c <= maxSingleCharacterString) + return vm->smallStrings.singleCharacterString(c); + return JSString::create(*vm, String(&c, 1).impl()); } - void append(VM& vm, size_t index, JSString* jsString) + ALWAYS_INLINE JSString* jsSingleCharacterSubstring(ExecState* exec, const String& s, unsigned offset) { - fiber(index).set(vm, this, jsString); - m_length += jsString->m_length; - RELEASE_ASSERT(static_cast<int32_t>(m_length) >= 0); - setIs8Bit(is8Bit() && jsString->is8Bit()); + VM* vm = &exec->vm(); + ASSERT(offset < static_cast<unsigned>(s.length())); + UChar c = s.characterAt(offset); + if (c <= maxSingleCharacterString) + return vm->smallStrings.singleCharacterString(c); + return JSString::create(*vm, StringImpl::create(s.impl(), offset, 1)); } - static JSRopeString* createNull(VM& vm) + inline JSString* jsNontrivialString(VM* vm, const String& s) { - JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); - newString->finishCreation(vm); - return newString; + ASSERT(s.length() > 1); + return JSString::create(*vm, s.impl()); } -public: - static JSString* create(VM& vm, JSString* s1, JSString* s2) + inline const String& JSString::value(ExecState* exec) const { - JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); - newString->finishCreation(vm, s1, s2); - return newString; + if (isRope()) + static_cast<const JSRopeString*>(this)->resolveRope(exec); + return m_value; } - static JSString* create(VM& vm, JSString* s1, JSString* s2, JSString* s3) + + inline const String& JSString::tryGetValue() const { - JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); - newString->finishCreation(vm, s1, s2, s3); - return newString; + if (isRope()) + static_cast<const JSRopeString*>(this)->resolveRope(0); + return m_value; } - static JSString* create(ExecState& exec, JSString& base, unsigned offset, unsigned length) + inline JSString* JSString::getIndex(ExecState* exec, unsigned i) { - JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(exec.vm().heap)) JSRopeString(exec.vm()); - newString->finishCreation(exec, base, offset, length); - return newString; + ASSERT(canGetIndex(i)); + if (isRope()) + return static_cast<JSRopeString*>(this)->getIndexSlowCase(exec, i); + ASSERT(i < m_value.length()); + return jsSingleCharacterSubstring(exec, m_value, i); } - void visitFibers(SlotVisitor&); - - static ptrdiff_t offsetOfFibers() { return OBJECT_OFFSETOF(JSRopeString, u); } - - static const unsigned s_maxInternalRopeLength = 3; - -private: - friend JSValue jsStringFromRegisterArray(ExecState*, Register*, unsigned); - friend JSValue jsStringFromArguments(ExecState*, JSValue); - - JS_EXPORT_PRIVATE void resolveRope(ExecState*) const; - JS_EXPORT_PRIVATE void resolveRopeToAtomicString(ExecState*) const; - JS_EXPORT_PRIVATE RefPtr<AtomicStringImpl> resolveRopeToExistingAtomicString(ExecState*) const; - void resolveRopeSlowCase8(LChar*) const; - void resolveRopeSlowCase(UChar*) const; - void outOfMemory(ExecState*) const; - void resolveRopeInternal8(LChar*) const; - void resolveRopeInternal8NoSubstring(LChar*) const; - void resolveRopeInternal16(UChar*) const; - void resolveRopeInternal16NoSubstring(UChar*) const; - void clearFibers() const; - StringView unsafeView(ExecState&) const; - StringViewWithUnderlyingString viewWithUnderlyingString(ExecState&) const; - - WriteBarrierBase<JSString>& fiber(unsigned i) const + inline JSString* jsString(VM* vm, const String& s) { - ASSERT(!isSubstring()); - ASSERT(i < s_maxInternalRopeLength); - return u[i].string; + 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(c); + } + return JSString::create(*vm, s.impl()); } - WriteBarrierBase<JSString>& substringBase() const + inline JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length) { - return u[1].string; + 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); } - uintptr_t& substringOffset() const + inline JSString* jsSubstring8(VM* vm, const String& s, unsigned offset, unsigned length) { - return u[2].number; + 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(c); + } + return JSString::createHasOtherOwner(*vm, StringImpl::create8(s.impl(), offset, length)); } - static uintptr_t notSubstringSentinel() + inline JSString* jsSubstring(VM* vm, const String& s, unsigned offset, unsigned length) { - return 0; + 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(c); + } + return JSString::createHasOtherOwner(*vm, StringImpl::create(s.impl(), offset, length)); } - static uintptr_t substringSentinel() + inline JSString* jsOwnedString(VM* vm, const String& s) { - return 1; + 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(c); + } + return JSString::createHasOtherOwner(*vm, s.impl()); } - bool isSubstring() const + inline JSRopeString* jsStringBuilder(VM* vm) { - return u[0].number == substringSentinel(); + return JSRopeString::createNull(*vm); } - void setIsSubstring(bool isSubstring) + 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) { - u[0].number = isSubstring ? substringSentinel() : notSubstringSentinel(); - } + if (propertyName == exec->propertyNames().length) { + slot.setValue(this, DontEnum | DontDelete | ReadOnly, jsNumber(m_length)); + return true; + } - mutable union { - uintptr_t number; - WriteBarrierBase<JSString> string; - } u[s_maxInternalRopeLength]; -}; - -class JSString::SafeView { -public: - SafeView(); - explicit SafeView(ExecState&, const JSString&); - operator StringView() const; - StringView get() const; - -private: - ExecState* m_state { nullptr }; - - // The following pointer is marked "volatile" to make the compiler leave it on the stack - // or in a register as long as this object is alive, even after the last use of the pointer. - // That's needed to prevent garbage collecting the string and possibly deleting the block - // with the characters in it, and then using the StringView after that. - const JSString* volatile m_string { nullptr }; -}; - -JS_EXPORT_PRIVATE JSString* jsStringWithCacheSlowCase(VM&, StringImpl&); - -inline const StringImpl* JSString::tryGetValueImpl() const -{ - return m_value.impl(); -} - -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(c); - return JSString::create(*vm, String(&c, 1).impl()); -} - -inline JSString* jsNontrivialString(VM* vm, const String& s) -{ - ASSERT(s.length() > 1); - return JSString::create(*vm, s.impl()); -} - -inline JSString* jsNontrivialString(VM* vm, String&& s) -{ - ASSERT(s.length() > 1); - return JSString::create(*vm, s.releaseImpl()); -} - -ALWAYS_INLINE Identifier JSString::toIdentifier(ExecState* exec) const -{ - return Identifier::fromString(exec, toAtomicString(exec)); -} - -ALWAYS_INLINE AtomicString JSString::toAtomicString(ExecState* exec) const -{ - if (isRope()) - static_cast<const JSRopeString*>(this)->resolveRopeToAtomicString(exec); - return AtomicString(m_value); -} - -ALWAYS_INLINE RefPtr<AtomicStringImpl> JSString::toExistingAtomicString(ExecState* exec) const -{ - if (isRope()) - return static_cast<const JSRopeString*>(this)->resolveRopeToExistingAtomicString(exec); - if (m_value.impl()->isAtomic()) - return static_cast<AtomicStringImpl*>(m_value.impl()); - return AtomicStringImpl::lookUp(m_value.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)); - return jsSingleCharacterString(exec, unsafeView(*exec)[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(c); - } - 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(); - if (!offset && length == s->length()) - return s; - return JSRopeString::create(*exec, *s, 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(c); - } - return JSString::createHasOtherOwner(*vm, StringImpl::createSubstringSharingImpl8(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(c); - } - return JSString::createHasOtherOwner(*vm, StringImpl::createSubstringSharingImpl(s.impl(), offset, length)); -} + 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(this, DontDelete | ReadOnly, getIndex(exec, i)); + return true; + } -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(c); - } - 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* jsNontrivialString(ExecState* exec, String&& s) { return jsNontrivialString(&exec->vm(), WTF::move(s)); } -inline JSString* jsOwnedString(ExecState* exec, const String& s) { return jsOwnedString(&exec->vm(), s); } - -ALWAYS_INLINE JSString* jsStringWithCache(ExecState* exec, const String& s) -{ - VM& vm = exec->vm(); - StringImpl* stringImpl = s.impl(); - if (!stringImpl || !stringImpl->length()) - return jsEmptyString(&vm); - - if (stringImpl->length() == 1) { - UChar singleCharacter = (*stringImpl)[0u]; - if (singleCharacter <= maxSingleCharacterString) - return vm.smallStrings.singleCharacterString(static_cast<unsigned char>(singleCharacter)); + return false; } + + ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) + { + if (propertyName < m_length) { + slot.setValue(this, DontDelete | ReadOnly, getIndex(exec, propertyName)); + return true; + } - if (JSString* lastCachedString = vm.lastCachedString.get()) { - if (lastCachedString->tryGetValueImpl() == stringImpl) - return lastCachedString; + return false; } - return jsStringWithCacheSlowCase(vm, *stringImpl); -} + inline bool isJSString(JSValue v) { return v.isCell() && v.asCell()->classInfo() == JSString::info(); } -ALWAYS_INLINE JSString* jsStringWithCache(ExecState* exec, const AtomicString& s) -{ - return jsStringWithCache(exec, s.string()); -} - -ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot) -{ - if (propertyName == exec->propertyNames().length) { - slot.setValue(this, DontEnum | DontDelete | ReadOnly, jsNumber(m_length)); - return true; + // --- 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. } - Optional<uint32_t> index = parseIndex(propertyName); - if (index && index.value() < m_length) { - slot.setValue(this, DontDelete | ReadOnly, getIndex(exec, index.value())); - return true; + inline JSString* JSValue::toString(ExecState* exec) const + { + if (isString()) + return jsCast<JSString*>(asCell()); + return toStringSlowCase(exec); } - return false; -} - -ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) -{ - if (propertyName < m_length) { - slot.setValue(this, DontDelete | ReadOnly, getIndex(exec, propertyName)); - return true; + inline String JSValue::toWTFString(ExecState* exec) const + { + if (isString()) + return static_cast<JSString*>(asCell())->value(exec); + return toWTFStringSlowCase(exec); } - return false; -} - -inline bool isJSString(JSValue v) -{ - return v.isCell() && v.asCell()->type() == StringType; -} + 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); -ALWAYS_INLINE StringView JSRopeString::unsafeView(ExecState& state) const -{ - if (isSubstring()) { - if (is8Bit()) - return StringView(substringBase()->m_value.characters8() + substringOffset(), m_length); - return StringView(substringBase()->m_value.characters16() + substringOffset(), m_length); - } - resolveRope(&state); - return m_value; -} - -ALWAYS_INLINE StringViewWithUnderlyingString JSRopeString::viewWithUnderlyingString(ExecState& state) const -{ - if (isSubstring()) { - auto& base = substringBase()->m_value; - if (is8Bit()) - return { { base.characters8() + substringOffset(), m_length }, base }; - return { { base.characters16() + substringOffset(), m_length }, base }; + return inlineJSValueNotStringtoString(*this, exec); } - resolveRope(&state); - return { m_value, m_value }; -} - -ALWAYS_INLINE StringView JSString::unsafeView(ExecState& state) const -{ - if (isRope()) - return static_cast<const JSRopeString*>(this)->unsafeView(state); - return m_value; -} - -ALWAYS_INLINE StringViewWithUnderlyingString JSString::viewWithUnderlyingString(ExecState& state) const -{ - if (isRope()) - return static_cast<const JSRopeString&>(*this).viewWithUnderlyingString(state); - return { m_value, m_value }; -} - -inline bool JSString::isSubstring() const -{ - return isRope() && static_cast<const JSRopeString*>(this)->isSubstring(); -} - -inline JSString::SafeView::SafeView() -{ -} - -inline JSString::SafeView::SafeView(ExecState& state, const JSString& string) - : m_state(&state) - , m_string(&string) -{ -} - -inline JSString::SafeView::operator StringView() const -{ - return m_string->unsafeView(*m_state); -} - -inline StringView JSString::SafeView::get() const -{ - return *this; -} - -ALWAYS_INLINE JSString::SafeView JSString::view(ExecState* exec) const -{ - return SafeView(*exec, *this); -} - -// --- 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); -} } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSStringBuilder.h b/Source/JavaScriptCore/runtime/JSStringBuilder.h index 34f43c4db..7b1c1a505 100644 --- a/Source/JavaScriptCore/runtime/JSStringBuilder.h +++ b/Source/JavaScriptCore/runtime/JSStringBuilder.h @@ -32,7 +32,6 @@ namespace JSC { -// FIXME: Should move the last few callers over from this to WTF::StringBuilder. class JSStringBuilder { public: JSStringBuilder() @@ -41,63 +40,72 @@ public: { } - void append(LChar character) + void append(const UChar u) { if (m_is8Bit) { - m_okay &= buffer8.tryAppend(&character, 1); - return; - } - UChar upconvertedCharacter = character; - m_okay &= buffer16.tryAppend(&upconvertedCharacter, 1); - } - - void append(UChar character) - { - if (m_is8Bit) { - if (character < 0x100) { - LChar narrowedCharacter = character; - m_okay &= buffer8.tryAppend(&narrowedCharacter, 1); + if (u < 0xff) { + LChar c = u; + m_okay &= buffer8.tryAppend(&c, 1); return; } upConvert(); } - m_okay &= buffer16.tryAppend(&character, 1); + m_okay &= buffer16.tryAppend(&u, 1); } void append(const char* str) { - append(reinterpret_cast<const LChar*>(str), strlen(str)); + append(str, strlen(str)); } - JSValue build(ExecState* exec) + void append(const char* str, size_t len) { - if (!m_okay) - return throwOutOfMemoryError(exec); if (m_is8Bit) { - buffer8.shrinkToFit(); - if (!buffer8.data()) - return throwOutOfMemoryError(exec); - return jsString(exec, String::adopt(buffer8)); + m_okay &= buffer8.tryAppend(reinterpret_cast<const LChar*>(str), len); + return; + } + m_okay &= buffer8.tryReserveCapacity(buffer16.size() + len); + for (size_t i = 0; i < len; i++) { + UChar u = static_cast<unsigned char>(str[i]); + m_okay &= buffer16.tryAppend(&u, 1); } - buffer16.shrinkToFit(); - if (!buffer16.data()) - return throwOutOfMemoryError(exec); - return jsString(exec, String::adopt(buffer16)); } -private: - void append(const LChar* characters, size_t length) + void append(const LChar* str, size_t len) { if (m_is8Bit) { - m_okay &= buffer8.tryAppend(characters, length); + m_okay &= buffer8.tryAppend(str, len); return; } - // FIXME: There must be a more efficient way of doing this. - m_okay &= buffer16.tryReserveCapacity(buffer16.size() + length); - for (size_t i = 0; i < length; i++) { - UChar upconvertedCharacter = characters[i]; - m_okay &= buffer16.tryAppend(&upconvertedCharacter, 1); + m_okay &= buffer8.tryReserveCapacity(buffer16.size() + len); + for (size_t i = 0; i < len; i++) { + UChar u = str[i]; + m_okay &= buffer16.tryAppend(&u, 1); + } + } + + void append(const UChar* str, size_t len) + { + if (m_is8Bit) + upConvert(); // FIXME: We could check character by character its size. + m_okay &= buffer16.tryAppend(str, len); + } + + void append(const String& str) + { + unsigned length = str.length(); + + if (!length) + return; + + if (m_is8Bit) { + if (str.is8Bit()) { + m_okay &= buffer8.tryAppend(str.characters8(), length); + return; + } + upConvert(); } + m_okay &= buffer16.tryAppend(str.deprecatedCharacters(), length); } void upConvert() @@ -112,25 +120,72 @@ private: m_is8Bit = false; } + JSValue build(ExecState* exec) + { + if (!m_okay) + return throwOutOfMemoryError(exec); + if (m_is8Bit) { + buffer8.shrinkToFit(); + if (!buffer8.data()) + return throwOutOfMemoryError(exec); + return jsString(exec, String::adopt(buffer8)); + } + buffer16.shrinkToFit(); + if (!buffer16.data()) + return throwOutOfMemoryError(exec); + return jsString(exec, String::adopt(buffer16)); + } + +protected: Vector<LChar, 64, UnsafeVectorOverflow> buffer8; Vector<UChar, 64, UnsafeVectorOverflow> buffer16; bool m_okay; bool m_is8Bit; }; -template<typename StringType> -inline JSValue jsMakeNontrivialString(ExecState* exec, StringType&& string) +template<typename StringType1, typename StringType2> +inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2) +{ + PassRefPtr<StringImpl> result = WTF::tryMakeString(string1, string2); + if (!result) + return throwOutOfMemoryError(exec); + return jsNontrivialString(exec, result); +} + +template<typename StringType1, typename StringType2, typename StringType3> +inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2, StringType3 string3) +{ + PassRefPtr<StringImpl> result = WTF::tryMakeString(string1, string2, string3); + if (!result) + return throwOutOfMemoryError(exec); + return jsNontrivialString(exec, result); +} + +template<typename StringType1, typename StringType2, typename StringType3, typename StringType4> +inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4) +{ + PassRefPtr<StringImpl> result = WTF::tryMakeString(string1, string2, string3, string4); + if (!result) + return throwOutOfMemoryError(exec); + return jsNontrivialString(exec, result); +} + +template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5> +inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5) { - return jsNontrivialString(exec, std::forward<StringType>(string)); + PassRefPtr<StringImpl> result = WTF::tryMakeString(string1, string2, string3, string4, string5); + if (!result) + return throwOutOfMemoryError(exec); + return jsNontrivialString(exec, result); } -template<typename StringType, typename... StringTypes> -inline JSValue jsMakeNontrivialString(ExecState* exec, const StringType& string, const StringTypes&... strings) +template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6> +inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6) { - RefPtr<StringImpl> result = WTF::tryMakeString(string, strings...); + PassRefPtr<StringImpl> result = WTF::tryMakeString(string1, string2, string3, string4, string5, string6); if (!result) return throwOutOfMemoryError(exec); - return jsNontrivialString(exec, result.release()); + return jsNontrivialString(exec, result); } } diff --git a/Source/JavaScriptCore/runtime/JSStringIterator.cpp b/Source/JavaScriptCore/runtime/JSStringIterator.cpp deleted file mode 100644 index c6fede7ad..000000000 --- a/Source/JavaScriptCore/runtime/JSStringIterator.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. - * - * 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 "JSStringIterator.h" - -#include "JSCJSValueInlines.h" -#include "JSCellInlines.h" -#include "StructureInlines.h" - -namespace JSC { - -const ClassInfo JSStringIterator::s_info = { "String Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(JSStringIterator) }; - -void JSStringIterator::finishCreation(VM& vm, JSGlobalObject*, JSString* iteratedString) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); - putDirect(vm, vm.propertyNames->iteratedStringPrivateName, iteratedString); - putDirect(vm, vm.propertyNames->stringIteratorNextIndexPrivateName, jsNumber(0)); -} - -JSValue JSStringIterator::iteratedValue(ExecState* exec) const -{ - return getDirect(exec->vm(), exec->vm().propertyNames->iteratedStringPrivateName); -} - -JSStringIterator* JSStringIterator::clone(ExecState* exec) -{ - VM& vm = exec->vm(); - JSValue iteratedString = getDirect(vm, vm.propertyNames->iteratedStringPrivateName); - JSValue nextIndex = getDirect(vm, vm.propertyNames->stringIteratorNextIndexPrivateName); - - auto clone = JSStringIterator::create(exec, exec->callee()->globalObject()->stringIteratorStructure(), asString(iteratedString)); - clone->putDirect(vm, vm.propertyNames->stringIteratorNextIndexPrivateName, nextIndex); - return clone; -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSStringIterator.h b/Source/JavaScriptCore/runtime/JSStringIterator.h deleted file mode 100644 index 6a789a319..000000000 --- a/Source/JavaScriptCore/runtime/JSStringIterator.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. - * - * 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 JSStringIterator_h -#define JSStringIterator_h - -#include "JSObject.h" - -namespace JSC { - -class JSStringIterator : public JSNonFinalObject { -public: - typedef JSNonFinalObject Base; - - DECLARE_EXPORT_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } - - static JSStringIterator* create(ExecState* exec, Structure* structure, JSString* iteratedString) - { - VM& vm = exec->vm(); - JSStringIterator* instance = new (NotNull, allocateCell<JSStringIterator>(vm.heap)) JSStringIterator(vm, structure); - instance->finishCreation(vm, structure->globalObject(), iteratedString); - return instance; - } - - JSValue iteratedValue(ExecState*) const; - JSStringIterator* clone(ExecState*); - -private: - JSStringIterator(VM& vm, Structure* structure) - : Base(vm, structure) - { - } - - void finishCreation(VM&, JSGlobalObject*, JSString* iteratedString); -}; - -} - -#endif // !defined(JSStringIterator_h) diff --git a/Source/JavaScriptCore/runtime/JSStringJoiner.cpp b/Source/JavaScriptCore/runtime/JSStringJoiner.cpp index 6f1959388..b6461c750 100644 --- a/Source/JavaScriptCore/runtime/JSStringJoiner.cpp +++ b/Source/JavaScriptCore/runtime/JSStringJoiner.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 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,94 +26,105 @@ #include "config.h" #include "JSStringJoiner.h" -#include "JSCInlines.h" +#include "ExceptionHelpers.h" +#include "JSScope.h" +#include "JSString.h" +#include "Operations.h" +#include <wtf/text/StringImpl.h> namespace JSC { -template<typename CharacterType> -static inline void appendStringToData(CharacterType*& data, StringView string) +// The destination is 16bits, at least one string is 16 bits. +static inline void appendStringToData(UChar*& data, const String& string) { - string.getCharactersWithUpconvert(data); - data += string.length(); -} + if (string.isNull()) + return; -template<typename CharacterType> -static inline String joinStrings(const Vector<StringViewWithUnderlyingString>& strings, StringView separator, unsigned joinedLength) -{ - ASSERT(joinedLength); + unsigned length = string.length(); + const StringImpl* stringImpl = string.impl(); - CharacterType* data; - String result = StringImpl::tryCreateUninitialized(joinedLength, data); - if (result.isNull()) - return result; - - appendStringToData(data, strings[0].view); - - unsigned size = strings.size(); - - switch (separator.length()) { - case 0: - for (unsigned i = 1; i < size; ++i) - appendStringToData(data, strings[i].view); - break; - case 1: { - CharacterType separatorCharacter = separator[0]; - for (unsigned i = 1; i < size; ++i) { - *data++ = separatorCharacter; - appendStringToData(data, strings[i].view); + if (stringImpl->is8Bit()) { + for (unsigned i = 0; i < length; ++i) { + *data = stringImpl->characters8()[i]; + ++data; } - break; - } - default: - for (unsigned i = 1; i < size; ++i) { - appendStringToData(data, separator); - appendStringToData(data, strings[i].view); + } else { + for (unsigned i = 0; i < length; ++i) { + *data = stringImpl->characters16()[i]; + ++data; } } - ASSERT(data == result.characters<CharacterType>() + joinedLength); - - return result; } -inline unsigned JSStringJoiner::joinedLength(ExecState& state) const +// If the destination is 8bits, we know every string has to be 8bit. +static inline void appendStringToData(LChar*& data, const String& string) { - unsigned numberOfStrings = m_strings.size(); - if (!numberOfStrings) - return 0; + if (string.isNull()) + return; + ASSERT(string.is8Bit()); - Checked<unsigned, RecordOverflow> separatorLength = m_separator.length(); - Checked<unsigned, RecordOverflow> totalSeparatorsLength = separatorLength * (numberOfStrings - 1); - Checked<unsigned, RecordOverflow> totalLength = totalSeparatorsLength + m_accumulatedStringsLength; + unsigned length = string.length(); + const StringImpl* stringImpl = string.impl(); - unsigned result; - if (totalLength.safeGet(result) == CheckedState::DidOverflow) { - throwOutOfMemoryError(&state); - return 0; + for (unsigned i = 0; i < length; ++i) { + *data = stringImpl->characters8()[i]; + ++data; } - return result; } -JSValue JSStringJoiner::join(ExecState& state) +template<typename CharacterType> +static inline PassRefPtr<StringImpl> joinStrings(const Vector<String>& strings, const String& separator, unsigned outputLength) { - ASSERT(m_strings.size() <= m_strings.capacity()); + ASSERT(outputLength); - unsigned length = joinedLength(state); - if (state.hadException()) - return jsUndefined(); + CharacterType* data; + RefPtr<StringImpl> outputStringImpl = StringImpl::tryCreateUninitialized(outputLength, data); + if (!outputStringImpl) + return PassRefPtr<StringImpl>(); + + const String firstString = strings.first(); + appendStringToData(data, firstString); - if (!length) - return jsEmptyString(&state); + for (size_t i = 1; i < strings.size(); ++i) { + appendStringToData(data, separator); + appendStringToData(data, strings[i]); + } + + ASSERT(data == (outputStringImpl->getCharacters<CharacterType>() + outputStringImpl->length())); + return outputStringImpl.release(); +} - String result; - if (m_isAll8Bit) - result = joinStrings<LChar>(m_strings, m_separator, length); +JSValue JSStringJoiner::join(ExecState* exec) +{ + if (!m_isValid) + return throwOutOfMemoryError(exec); + + if (!m_strings.size()) + return jsEmptyString(exec); + + Checked<unsigned, RecordOverflow> separatorLength = m_separator.length(); + // FIXME: add special cases of joinStrings() for (separatorLength == 0) and (separatorLength == 1). + ASSERT(m_strings.size() > 0); + Checked<unsigned, RecordOverflow> totalSeparactorsLength = separatorLength * (m_strings.size() - 1); + Checked<unsigned, RecordOverflow> outputStringSize = totalSeparactorsLength + m_accumulatedStringsLength; + + unsigned 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, finalSize); else - result = joinStrings<UChar>(m_strings, m_separator, length); + outputStringImpl = joinStrings<UChar>(m_strings, m_separator, finalSize); - if (result.isNull()) - return throwOutOfMemoryError(&state); + if (!outputStringImpl) + return throwOutOfMemoryError(exec); - return jsString(&state, WTF::move(result)); + return JSString::create(exec->vm(), outputStringImpl.release()); } } diff --git a/Source/JavaScriptCore/runtime/JSStringJoiner.h b/Source/JavaScriptCore/runtime/JSStringJoiner.h index 224784493..73950c6d7 100644 --- a/Source/JavaScriptCore/runtime/JSStringJoiner.h +++ b/Source/JavaScriptCore/runtime/JSStringJoiner.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 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,112 +26,50 @@ #ifndef JSStringJoiner_h #define JSStringJoiner_h -#include "ExceptionHelpers.h" #include "JSCJSValue.h" +#include <wtf/Vector.h> +#include <wtf/text/WTFString.h> namespace JSC { +class ExecState; + + class JSStringJoiner { public: - JSStringJoiner(ExecState&, LChar separator, unsigned stringCount); - JSStringJoiner(ExecState&, StringView separator, unsigned stringCount); + JSStringJoiner(const String& separator, size_t stringCount); - void append(ExecState&, JSValue); - void appendEmptyString(); - - JSValue join(ExecState&); + void append(const String&); + JSValue join(ExecState*); private: - void append(StringViewWithUnderlyingString&&); - void append8Bit(const String&); - void appendLiteral(const Identifier&); - unsigned joinedLength(ExecState&) const; + String m_separator; + Vector<String> m_strings; - LChar m_singleCharacterSeparator; - StringView m_separator; - Vector<StringViewWithUnderlyingString> m_strings; Checked<unsigned, RecordOverflow> m_accumulatedStringsLength; - bool m_isAll8Bit { true }; + bool m_isValid; + bool m_is8Bits; }; -inline JSStringJoiner::JSStringJoiner(ExecState& state, StringView separator, unsigned stringCount) +inline JSStringJoiner::JSStringJoiner(const String& separator, size_t stringCount) : m_separator(separator) - , m_isAll8Bit(m_separator.is8Bit()) -{ - if (!m_strings.tryReserveCapacity(stringCount)) - throwOutOfMemoryError(&state); -} - -inline JSStringJoiner::JSStringJoiner(ExecState& state, LChar separator, unsigned stringCount) - : m_singleCharacterSeparator(separator) - , m_separator { &m_singleCharacterSeparator, 1 } -{ - if (!m_strings.tryReserveCapacity(stringCount)) - throwOutOfMemoryError(&state); -} - -ALWAYS_INLINE void JSStringJoiner::append(StringViewWithUnderlyingString&& string) + , m_isValid(true) + , m_is8Bits(m_separator.is8Bit()) { - m_accumulatedStringsLength += string.view.length(); - m_isAll8Bit = m_isAll8Bit && string.view.is8Bit(); - m_strings.uncheckedAppend(WTF::move(string)); + ASSERT(!m_separator.isNull()); + m_isValid = m_strings.tryReserveCapacity(stringCount); } -ALWAYS_INLINE void JSStringJoiner::append8Bit(const String& string) +inline void JSStringJoiner::append(const String& str) { - ASSERT(string.is8Bit()); - m_accumulatedStringsLength += string.length(); - m_strings.uncheckedAppend({ string, string }); -} - -ALWAYS_INLINE void JSStringJoiner::appendLiteral(const Identifier& literal) -{ - m_accumulatedStringsLength += literal.length(); - ASSERT(literal.string().is8Bit()); - m_strings.uncheckedAppend({ literal.string(), { } }); -} - -ALWAYS_INLINE void JSStringJoiner::appendEmptyString() -{ - m_strings.uncheckedAppend({ { }, { } }); -} - -ALWAYS_INLINE void JSStringJoiner::append(ExecState& state, JSValue value) -{ - // The following code differs from using the result of JSValue::toString in the following ways: - // 1) It's inlined more than JSValue::toString is. - // 2) It includes conversion to WTF::String in a way that avoids allocating copies of substrings. - // 3) It doesn't create a JSString for numbers, true, or false. - // 4) It turns undefined and null into the empty string instead of "undefined" and "null". - // 5) It uses optimized code paths for all the cases known to be 8-bit and for the empty string. - - if (value.isCell()) { - if (value.asCell()->isString()) { - append(asString(value)->viewWithUnderlyingString(state)); - return; - } - append(value.toString(&state)->viewWithUnderlyingString(state)); + if (!m_isValid) return; - } - if (value.isInt32()) { - append8Bit(state.vm().numericStrings.add(value.asInt32())); - return; - } - if (value.isDouble()) { - append8Bit(state.vm().numericStrings.add(value.asDouble())); - return; - } - if (value.isTrue()) { - append8Bit(state.vm().propertyNames->trueKeyword.string()); - return; - } - if (value.isFalse()) { - append8Bit(state.vm().propertyNames->falseKeyword.string()); - return; + m_strings.append(str); + if (!str.isNull()) { + m_accumulatedStringsLength += str.length(); + m_is8Bits = m_is8Bits && str.is8Bit(); } - ASSERT(value.isUndefinedOrNull()); - appendEmptyString(); } } diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp b/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp index 83aa048ea..2ac2524c5 100644 --- a/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp +++ b/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -29,9 +29,10 @@ #include "config.h" #include "JSSymbolTableObject.h" +#include "JSActivation.h" #include "JSGlobalObject.h" -#include "JSLexicalEnvironment.h" -#include "JSCInlines.h" +#include "JSNameScope.h" +#include "Operations.h" #include "PropertyNameArray.h" namespace JSC { @@ -40,6 +41,9 @@ void JSSymbolTableObject::visitChildren(JSCell* cell, SlotVisitor& visitor) { JSSymbolTableObject* thisObject = jsCast<JSSymbolTableObject*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + Base::visitChildren(thisObject, visitor); visitor.append(&thisObject->m_symbolTable); } @@ -60,11 +64,8 @@ void JSSymbolTableObject::getOwnNonIndexPropertyNames(JSObject* object, ExecStat ConcurrentJITLocker locker(thisObject->symbolTable()->m_lock); SymbolTable::Map::iterator end = thisObject->symbolTable()->end(locker); for (SymbolTable::Map::iterator it = thisObject->symbolTable()->begin(locker); it != end; ++it) { - if (!(it->value.getAttributes() & DontEnum) || mode.includeDontEnumProperties()) { - if (it->key->isSymbol() && !propertyNames.includeSymbolProperties()) - continue; - propertyNames.add(Identifier::fromUid(exec, it->key.get())); - } + if (!(it->value.getAttributes() & DontEnum) || (mode == IncludeDontEnumProperties)) + propertyNames.add(Identifier(exec, it->key.get())); } } diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.h b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h index 9fe8384c6..b5b20a845 100644 --- a/Source/JavaScriptCore/runtime/JSSymbolTableObject.h +++ b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2014, 2015 Apple Inc. All rights reserved. + * 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 @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -32,47 +32,37 @@ #include "JSScope.h" #include "PropertyDescriptor.h" #include "SymbolTable.h" -#include "VariableWriteFireDetail.h" namespace JSC { -class JSSymbolTableObject; - class JSSymbolTableObject : public JSScope { public: typedef JSScope Base; - static const unsigned StructureFlags = Base::StructureFlags | IsEnvironmentRecord | OverridesGetPropertyNames; SymbolTable* symbolTable() const { return m_symbolTable.get(); } JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName); JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - static ptrdiff_t offsetOfSymbolTable() { return OBJECT_OFFSETOF(JSSymbolTableObject, m_symbolTable); } - protected: - JSSymbolTableObject(VM& vm, Structure* structure, JSScope* scope) - : Base(vm, structure, scope) - { - } + static const unsigned StructureFlags = IsEnvironmentRecord | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags; - JSSymbolTableObject(VM& vm, Structure* structure, JSScope* scope, SymbolTable* symbolTable) + JSSymbolTableObject(VM& vm, Structure* structure, JSScope* scope, SymbolTable* symbolTable = 0) : Base(vm, structure, scope) { - ASSERT(symbolTable); - setSymbolTable(vm, symbolTable); + if (symbolTable) + m_symbolTable.set(vm, this, symbolTable); } - - void setSymbolTable(VM& vm, SymbolTable* symbolTable) + + void finishCreation(VM& vm) { - ASSERT(!m_symbolTable); - symbolTable->singletonScope()->notifyWrite(vm, this, "Allocated a scope"); - m_symbolTable.set(vm, this, symbolTable); + Base::finishCreation(vm); + if (!m_symbolTable) + m_symbolTable.set(vm, this, SymbolTable::create(vm)); } - + static void visitChildren(JSCell*, SlotVisitor&); - -private: + WriteBarrier<SymbolTable> m_symbolTable; }; @@ -82,12 +72,12 @@ inline bool symbolTableGet( { SymbolTable& symbolTable = *object->symbolTable(); ConcurrentJITLocker locker(symbolTable.m_lock); - SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.uid()); + SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.publicName()); if (iter == symbolTable.end(locker)) return false; SymbolTableEntry::Fast entry = iter->value; ASSERT(!entry.isNull()); - slot.setValue(object, entry.getAttributes() | DontDelete, object->variableAt(entry.scopeOffset()).get()); + slot.setValue(object, entry.getAttributes() | DontDelete, object->registerAt(entry.getIndex()).get()); return true; } @@ -97,13 +87,13 @@ inline bool symbolTableGet( { SymbolTable& symbolTable = *object->symbolTable(); ConcurrentJITLocker locker(symbolTable.m_lock); - SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.uid()); + SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.publicName()); if (iter == symbolTable.end(locker)) return false; SymbolTableEntry::Fast entry = iter->value; ASSERT(!entry.isNull()); descriptor.setDescriptor( - object->variableAt(entry.scopeOffset()).get(), entry.getAttributes() | DontDelete); + object->registerAt(entry.getIndex()).get(), entry.getAttributes() | DontDelete); return true; } @@ -114,12 +104,12 @@ inline bool symbolTableGet( { SymbolTable& symbolTable = *object->symbolTable(); ConcurrentJITLocker locker(symbolTable.m_lock); - SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.uid()); + SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.publicName()); if (iter == symbolTable.end(locker)) return false; SymbolTableEntry::Fast entry = iter->value; ASSERT(!entry.isNull()); - slot.setValue(object, entry.getAttributes() | DontDelete, object->variableAt(entry.scopeOffset()).get()); + slot.setValue(object, entry.getAttributes() | DontDelete, object->registerAt(entry.getIndex()).get()); slotIsWriteable = !entry.isReadOnly(); return true; } @@ -133,13 +123,10 @@ inline bool symbolTablePut( ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object)); WriteBarrierBase<Unknown>* reg; - WatchpointSet* set; { SymbolTable& symbolTable = *object->symbolTable(); - // FIXME: This is very suspicious. We shouldn't need a GC-safe lock here. - // https://bugs.webkit.org/show_bug.cgi?id=134601 GCSafeConcurrentJITLocker locker(symbolTable.m_lock, exec->vm().heap); - SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.uid()); + SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.publicName()); if (iter == symbolTable.end(locker)) return false; bool wasFat; @@ -150,15 +137,14 @@ inline bool symbolTablePut( throwTypeError(exec, StrictModeReadonlyPropertyWriteError); return true; } - set = iter->value.watchpointSet(); - reg = &object->variableAt(fastEntry.scopeOffset()); + if (VariableWatchpointSet* set = iter->value.watchpointSet()) + set->notifyWrite(value); + reg = &object->registerAt(fastEntry.getIndex()); } // I'd prefer we not hold lock while executing barriers, since I prefer to reserve // the right for barriers to be able to trigger GC. And I don't want to hold VM // locks while GC'ing. reg->set(vm, object, value); - if (set) - VariableWriteFireDetail::touch(set, object, propertyName); return true; } @@ -170,22 +156,20 @@ inline bool symbolTablePutWithAttributes( ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object)); WriteBarrierBase<Unknown>* reg; - WatchpointSet* set; { SymbolTable& symbolTable = *object->symbolTable(); ConcurrentJITLocker locker(symbolTable.m_lock); - SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.uid()); + SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.publicName()); if (iter == symbolTable.end(locker)) return false; SymbolTableEntry& entry = iter->value; ASSERT(!entry.isNull()); - set = entry.watchpointSet(); + if (VariableWatchpointSet* set = entry.watchpointSet()) + set->notifyWrite(value); entry.setAttributes(attributes); - reg = &object->variableAt(entry.scopeOffset()); + reg = &object->registerAt(entry.getIndex()); } reg->set(vm, object, value); - if (set) - VariableWriteFireDetail::touch(set, object, propertyName); return true; } diff --git a/Source/JavaScriptCore/runtime/JSTemplateRegistryKey.cpp b/Source/JavaScriptCore/runtime/JSTemplateRegistryKey.cpp deleted file mode 100644 index e3f3ae990..000000000 --- a/Source/JavaScriptCore/runtime/JSTemplateRegistryKey.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. - * - * 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 "JSTemplateRegistryKey.h" - -#include "JSCJSValueInlines.h" -#include "JSCellInlines.h" -#include "StructureInlines.h" -#include "VM.h" - -namespace JSC { - -const ClassInfo JSTemplateRegistryKey::s_info = { "TemplateRegistryKey", &Base::s_info, nullptr, CREATE_METHOD_TABLE(JSTemplateRegistryKey) }; - - -JSTemplateRegistryKey::JSTemplateRegistryKey(VM& vm, const TemplateRegistryKey& templateRegistryKey) - : Base(vm, vm.templateRegistryKeyStructure.get()) - , m_templateRegistryKey(templateRegistryKey) -{ -} - -JSTemplateRegistryKey* JSTemplateRegistryKey::create(VM& vm, const TemplateRegistryKey& templateRegistryKey) -{ - JSTemplateRegistryKey* result = new (NotNull, allocateCell<JSTemplateRegistryKey>(vm.heap)) JSTemplateRegistryKey(vm, templateRegistryKey); - result->finishCreation(vm); - return result; -} - -void JSTemplateRegistryKey::destroy(JSCell* cell) -{ - static_cast<JSTemplateRegistryKey*>(cell)->JSTemplateRegistryKey::~JSTemplateRegistryKey(); -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSType.h b/Source/JavaScriptCore/runtime/JSType.h index 40326ce0f..10d98d2bd 100644 --- a/Source/JavaScriptCore/runtime/JSType.h +++ b/Source/JavaScriptCore/runtime/JSType.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 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 @@ -23,20 +23,18 @@ namespace JSC { -enum JSType : uint8_t { +enum JSType { UnspecifiedType, UndefinedType, BooleanType, NumberType, NullType, - - // The CellType value must come before any JSType that is a JSCell. - CellType, StringType, - SymbolType, + LeafType, + // The CompoundType value must come before any JSType that may have children. + CompoundType, GetterSetterType, - CustomGetterSetterType, APIValueWrapperType, EvalExecutableType, @@ -51,37 +49,21 @@ enum JSType : uint8_t { // The ObjectType value must come before any JSType that is a subclass of JSObject. ObjectType, FinalObjectType, - JSCalleeType, JSFunctionType, + NameInstanceType, NumberObjectType, ErrorInstanceType, - PureForwardingProxyType, - ImpureProxyType, + ProxyType, WithScopeType, - DirectArgumentsType, - ScopedArgumentsType, - - Int8ArrayType, - Int16ArrayType, - Int32ArrayType, - Uint8ArrayType, - Uint8ClampedArrayType, - Uint16ArrayType, - Uint32ArrayType, - Float32ArrayType, - Float64ArrayType, - DataViewType, NameScopeObjectType, - + // VariableObjectType must be less than MOST of the types of its subclasses and only its subclasses. + // We use >=VariableObjectType checks to test for Global & Activation objects, but exclude NameScopes. + VariableObjectType, GlobalObjectType, ActivationObjectType, - - LastJSCObjectType = ActivationObjectType, }; -COMPILE_ASSERT(sizeof(JSType) == sizeof(uint8_t), sizeof_jstype_is_one_byte); - } // namespace JSC #endif diff --git a/Source/JavaScriptCore/runtime/JSTypeInfo.h b/Source/JavaScriptCore/runtime/JSTypeInfo.h index 27863abf2..d70d6512e 100644 --- a/Source/JavaScriptCore/runtime/JSTypeInfo.h +++ b/Source/JavaScriptCore/runtime/JSTypeInfo.h @@ -1,6 +1,6 @@ // -*- mode: c++; c-basic-offset: 4 -*- /* - * Copyright (C) 2008, 2015 Apple Inc. All rights reserved. + * 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 @@ -11,10 +11,10 @@ * 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 + * 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 INC. OR + * 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 @@ -34,90 +34,79 @@ namespace JSC { -class LLIntOffsetsExtractor; - -static const unsigned MasqueradesAsUndefined = 1; // WebCore uses MasqueradesAsUndefined to make document.all undetectable. -static const unsigned ImplementsHasInstance = 1 << 1; -static const unsigned OverridesHasInstance = 1 << 2; -static const unsigned ImplementsDefaultHasInstance = 1 << 3; -static const unsigned TypeOfShouldCallGetCallData = 1 << 4; // Need this flag if you override getCallData() and you want typeof to use this to determine if it should say "function". Currently we always set this flag when we override getCallData(). -static const unsigned OverridesGetOwnPropertySlot = 1 << 5; -static const unsigned InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero = 1 << 6; -static const unsigned StructureIsImmortal = 1 << 7; - -static const unsigned OverridesGetPropertyNames = 1 << 8; -static const unsigned ProhibitsPropertyCaching = 1 << 9; -static const unsigned HasImpureGetOwnPropertySlot = 1 << 10; -static const unsigned NewImpurePropertyFiresWatchpoints = 1 << 11; -static const unsigned IsEnvironmentRecord = 1 << 12; - -class TypeInfo { -public: - typedef uint8_t InlineTypeFlags; - typedef uint8_t OutOfLineTypeFlags; - - TypeInfo(JSType type, unsigned flags = 0) - : TypeInfo(type, flags & 0xff, flags >> 8) - { - } - - TypeInfo(JSType type, InlineTypeFlags inlineTypeFlags, OutOfLineTypeFlags outOfLineTypeFlags) - : m_type(type) - , m_flags(inlineTypeFlags) - , m_flags2(outOfLineTypeFlags) - { - // No object that doesn't ImplementsHasInstance should override it! - ASSERT((m_flags & (ImplementsHasInstance | OverridesHasInstance)) != OverridesHasInstance); - // ImplementsDefaultHasInstance means (ImplementsHasInstance & !OverridesHasInstance) - if ((m_flags & (ImplementsHasInstance | OverridesHasInstance)) == ImplementsHasInstance) - m_flags |= ImplementsDefaultHasInstance; - } - - JSType type() const { return static_cast<JSType>(m_type); } - bool isObject() const { return isObject(type()); } - static bool isObject(JSType type) { return type >= ObjectType; } - bool isFinalObject() const { return type() == FinalObjectType; } - bool isNumberObject() const { return type() == NumberObjectType; } - - 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 overridesHasInstance() const { return isSetOnFlags1(OverridesHasInstance); } - bool implementsDefaultHasInstance() const { return isSetOnFlags1(ImplementsDefaultHasInstance); } - bool typeOfShouldCallGetCallData() const { return isSetOnFlags1(TypeOfShouldCallGetCallData); } - bool overridesGetOwnPropertySlot() const { return overridesGetOwnPropertySlot(inlineTypeFlags()); } - static bool overridesGetOwnPropertySlot(InlineTypeFlags flags) { return flags & OverridesGetOwnPropertySlot; } - bool interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero() const { return isSetOnFlags1(InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero); } - bool structureIsImmortal() const { return isSetOnFlags1(StructureIsImmortal); } - bool overridesGetPropertyNames() const { return isSetOnFlags2(OverridesGetPropertyNames); } - bool prohibitsPropertyCaching() const { return isSetOnFlags2(ProhibitsPropertyCaching); } - bool hasImpureGetOwnPropertySlot() const { return isSetOnFlags2(HasImpureGetOwnPropertySlot); } - bool newImpurePropertyFiresWatchpoints() const { return isSetOnFlags2(NewImpurePropertyFiresWatchpoints); } - bool isEnvironmentRecord() const { return isSetOnFlags2(IsEnvironmentRecord); } - - static ptrdiff_t flagsOffset() - { - return OBJECT_OFFSETOF(TypeInfo, m_flags); - } - - static ptrdiff_t typeOffset() - { - return OBJECT_OFFSETOF(TypeInfo, m_type); - } - - InlineTypeFlags inlineTypeFlags() const { return m_flags; } - OutOfLineTypeFlags outOfLineTypeFlags() const { return m_flags2; } - -private: - friend class LLIntOffsetsExtractor; - - bool isSetOnFlags1(unsigned flag) const { ASSERT(flag <= (1 << 7)); return m_flags & flag; } - bool isSetOnFlags2(unsigned flag) const { ASSERT(flag >= (1 << 8)); return m_flags2 & (flag >> 8); } - - unsigned char m_type; - unsigned char m_flags; - unsigned char m_flags2; -}; + class LLIntOffsetsExtractor; + + static const unsigned MasqueradesAsUndefined = 1; // WebCore uses MasqueradesAsUndefined to make document.all undetectable. + static const unsigned ImplementsHasInstance = 1 << 1; + static const unsigned OverridesHasInstance = 1 << 2; + static const unsigned ImplementsDefaultHasInstance = 1 << 3; + static const unsigned IsEnvironmentRecord = 1 << 4; + static const unsigned OverridesGetOwnPropertySlot = 1 << 5; + static const unsigned InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero = 1 << 6; + static const unsigned OverridesVisitChildren = 1 << 7; + static const unsigned OverridesGetPropertyNames = 1 << 8; + static const unsigned ProhibitsPropertyCaching = 1 << 9; + static const unsigned HasImpureGetOwnPropertySlot = 1 << 10; + static const unsigned NewImpurePropertyFiresWatchpoints = 1 << 11; + static const unsigned StructureHasRareData = 1 << 12; + + class TypeInfo { + public: + TypeInfo(JSType type, unsigned flags = 0) + : m_type(type) + , m_flags(flags & 0xff) + , m_flags2(flags >> 8) + { + ASSERT(static_cast<int>(type) <= 0xff); + ASSERT(type >= CompoundType || !(flags & OverridesVisitChildren)); + // No object that doesn't ImplementsHasInstance should override it! + ASSERT((m_flags & (ImplementsHasInstance | OverridesHasInstance)) != OverridesHasInstance); + // ImplementsDefaultHasInstance means (ImplementsHasInstance & !OverridesHasInstance) + if ((m_flags & (ImplementsHasInstance | OverridesHasInstance)) == ImplementsHasInstance) + m_flags |= ImplementsDefaultHasInstance; + } + + JSType type() const { return static_cast<JSType>(m_type); } + bool isObject() const { return type() >= ObjectType; } + bool isFinalObject() const { return type() == FinalObjectType; } + 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); } + bool overridesHasInstance() const { return isSetOnFlags1(OverridesHasInstance); } + bool implementsDefaultHasInstance() const { return isSetOnFlags1(ImplementsDefaultHasInstance); } + bool overridesGetOwnPropertySlot() const { return isSetOnFlags1(OverridesGetOwnPropertySlot); } + bool interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero() const { return isSetOnFlags1(InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero); } + bool overridesVisitChildren() const { return isSetOnFlags1(OverridesVisitChildren); } + bool overridesGetPropertyNames() const { return isSetOnFlags2(OverridesGetPropertyNames); } + bool prohibitsPropertyCaching() const { return isSetOnFlags2(ProhibitsPropertyCaching); } + bool hasImpureGetOwnPropertySlot() const { return isSetOnFlags2(HasImpureGetOwnPropertySlot); } + bool newImpurePropertyFiresWatchpoints() const { return isSetOnFlags2(NewImpurePropertyFiresWatchpoints); } + bool structureHasRareData() const { return isSetOnFlags2(StructureHasRareData); } + + static ptrdiff_t flagsOffset() + { + return OBJECT_OFFSETOF(TypeInfo, m_flags); + } + + static ptrdiff_t typeOffset() + { + return OBJECT_OFFSETOF(TypeInfo, m_type); + } + + private: + friend class LLIntOffsetsExtractor; + + bool isSetOnFlags1(unsigned flag) const { ASSERT(flag <= (1 << 7)); return m_flags & flag; } + bool isSetOnFlags2(unsigned flag) const { ASSERT(flag >= (1 << 8)); return m_flags2 & (flag >> 8); } + + unsigned char m_type; + unsigned char m_flags; + unsigned char m_flags2; + }; } diff --git a/Source/JavaScriptCore/runtime/JSTypedArrayConstructors.cpp b/Source/JavaScriptCore/runtime/JSTypedArrayConstructors.cpp index f42f31795..ec8dff40a 100644 --- a/Source/JavaScriptCore/runtime/JSTypedArrayConstructors.cpp +++ b/Source/JavaScriptCore/runtime/JSTypedArrayConstructors.cpp @@ -28,12 +28,12 @@ #include "JSGenericTypedArrayViewConstructorInlines.h" #include "JSGenericTypedArrayViewInlines.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { #define MAKE_S_INFO(type) \ - template<> const ClassInfo JS##type##Constructor::s_info = {"Function", &JS##type##Constructor::Base::s_info, 0, CREATE_METHOD_TABLE(JS##type##Constructor)} + template<> const ClassInfo JS##type##Constructor::s_info = {"Function", &JS##type##Constructor::Base::s_info, 0, 0, CREATE_METHOD_TABLE(JS##type##Constructor)} MAKE_S_INFO(Int8Array); MAKE_S_INFO(Int16Array); diff --git a/Source/JavaScriptCore/runtime/JSTypedArrayPrototypes.cpp b/Source/JavaScriptCore/runtime/JSTypedArrayPrototypes.cpp index c01d8f889..f89a3e276 100644 --- a/Source/JavaScriptCore/runtime/JSTypedArrayPrototypes.cpp +++ b/Source/JavaScriptCore/runtime/JSTypedArrayPrototypes.cpp @@ -27,12 +27,12 @@ #include "JSTypedArrayPrototypes.h" #include "JSGenericTypedArrayViewPrototypeInlines.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { #define MAKE_S_INFO(type) \ - template<> const ClassInfo JS##type##Prototype::s_info = {#type "Prototype", &JS##type##Prototype::Base::s_info, 0, CREATE_METHOD_TABLE(JS##type##Prototype)} + template<> const ClassInfo JS##type##Prototype::s_info = {#type "Prototype", &JS##type##Prototype::Base::s_info, 0, 0, CREATE_METHOD_TABLE(JS##type##Prototype)} MAKE_S_INFO(Int8Array); MAKE_S_INFO(Int16Array); diff --git a/Source/JavaScriptCore/runtime/JSTypedArrays.cpp b/Source/JavaScriptCore/runtime/JSTypedArrays.cpp index 2c5c4747b..d9f8cffa6 100644 --- a/Source/JavaScriptCore/runtime/JSTypedArrays.cpp +++ b/Source/JavaScriptCore/runtime/JSTypedArrays.cpp @@ -29,13 +29,13 @@ #include "CopyVisitorInlines.h" #include "GenericTypedArrayViewInlines.h" #include "JSGenericTypedArrayViewInlines.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { #define MAKE_S_INFO(type) \ template<> const ClassInfo JS##type##Array::s_info = { \ - #type "Array", &JS##type##Array::Base::s_info, 0, \ + #type "Array", &JS##type##Array::Base::s_info, 0, 0, \ CREATE_METHOD_TABLE(JS##type##Array) \ }; \ const ClassInfo* get##type##ArrayClassInfo() { return &JS##type##Array::s_info; } diff --git a/Source/JavaScriptCore/runtime/JSEnvironmentRecord.cpp b/Source/JavaScriptCore/runtime/JSVariableObject.cpp index f1d769592..fc262f5d8 100644 --- a/Source/JavaScriptCore/runtime/JSEnvironmentRecord.cpp +++ b/Source/JavaScriptCore/runtime/JSVariableObject.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2012, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 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 @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -27,20 +27,12 @@ */ #include "config.h" -#include "JSEnvironmentRecord.h" +#include "JSVariableObject.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { -const ClassInfo JSEnvironmentRecord::s_info = { "EnvironmentRecord", &Base::s_info, 0, CREATE_METHOD_TABLE(JSEnvironmentRecord) }; - -void JSEnvironmentRecord::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - JSEnvironmentRecord* thisObject = jsCast<JSEnvironmentRecord*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - Base::visitChildren(thisObject, visitor); - visitor.appendValues(thisObject->variables(), thisObject->symbolTable()->scopeSize()); -} +const ClassInfo JSVariableObject::s_info = { "VariableObject", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSVariableObject) }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/TypeProfilerLog.h b/Source/JavaScriptCore/runtime/JSVariableObject.h index 1dd188ab7..9bbb39196 100644 --- a/Source/JavaScriptCore/runtime/TypeProfilerLog.h +++ b/Source/JavaScriptCore/runtime/JSVariableObject.h @@ -1,18 +1,18 @@ /* - * Copyright (C) 2014 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 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. + * 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 Inc. ("Apple") nor the names of + * 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. + * 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 @@ -26,59 +26,51 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef TypeProfilerLog_h -#define TypeProfilerLog_h +#ifndef JSVariableObject_h +#define JSVariableObject_h -#include "JSCJSValue.h" -#include "Structure.h" -#include "TypeProfiler.h" +#include "JSObject.h" +#include "JSSymbolTableObject.h" +#include "Register.h" +#include "SymbolTable.h" namespace JSC { -class TypeLocation; +class LLIntOffsetsExtractor; +class Register; + +class JSVariableObject : public JSSymbolTableObject { + friend class JIT; + friend class LLIntOffsetsExtractor; -class TypeProfilerLog { - WTF_MAKE_FAST_ALLOCATED; public: - struct LogEntry { - public: - friend class LLIntOffsetsExtractor; + typedef JSSymbolTableObject Base; + + WriteBarrierBase<Unknown>* registers() { return m_registers; } + WriteBarrierBase<Unknown>& registerAt(int index) const { return m_registers[index]; } - JSValue value; - TypeLocation* location; - StructureID structureID; + WriteBarrierBase<Unknown>* const * addressOfRegisters() const { return &m_registers; } + static size_t offsetOfRegisters() { return OBJECT_OFFSETOF(JSVariableObject, m_registers); } - static ptrdiff_t structureIDOffset() { return OBJECT_OFFSETOF(LogEntry, structureID); } - static ptrdiff_t valueOffset() { return OBJECT_OFFSETOF(LogEntry, value); } - static ptrdiff_t locationOffset() { return OBJECT_OFFSETOF(LogEntry, location); } - }; + DECLARE_INFO; +protected: + static const unsigned StructureFlags = Base::StructureFlags; - TypeProfilerLog() - : m_logStartPtr(0) + JSVariableObject( + VM& vm, + Structure* structure, + Register* registers, + JSScope* scope, + SymbolTable* symbolTable = 0) + : Base(vm, structure, scope, symbolTable) + , m_registers(reinterpret_cast<WriteBarrierBase<Unknown>*>(registers)) { - initializeLog(); } - ~TypeProfilerLog(); - - JS_EXPORT_PRIVATE void processLogEntries(const String&); - LogEntry* logEndPtr() const { return m_logEndPtr; } - - static ptrdiff_t logStartOffset() { return OBJECT_OFFSETOF(TypeProfilerLog, m_logStartPtr); } - static ptrdiff_t currentLogEntryOffset() { return OBJECT_OFFSETOF(TypeProfilerLog, m_currentLogEntryPtr); } - -private: - friend class LLIntOffsetsExtractor; - - void initializeLog(); - - unsigned m_logSize; - LogEntry* m_logStartPtr; - LogEntry* m_currentLogEntryPtr; - LogEntry* m_logEndPtr; + WriteBarrierBase<Unknown>* m_registers; // "r" in the stack. }; } // namespace JSC -#endif // TypeProfilerLog_h +#endif // JSVariableObject_h diff --git a/Source/JavaScriptCore/runtime/JSWeakMap.cpp b/Source/JavaScriptCore/runtime/JSWeakMap.cpp index 80b46ce84..049686df2 100644 --- a/Source/JavaScriptCore/runtime/JSWeakMap.cpp +++ b/Source/JavaScriptCore/runtime/JSWeakMap.cpp @@ -28,13 +28,11 @@ #include "JSCJSValueInlines.h" #include "SlotVisitorInlines.h" -#include "StructureInlines.h" #include "WeakMapData.h" -#include "WriteBarrierInlines.h" namespace JSC { -const ClassInfo JSWeakMap::s_info = { "WeakMap", &Base::s_info, 0, CREATE_METHOD_TABLE(JSWeakMap) }; +const ClassInfo JSWeakMap::s_info = { "WeakMap", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSWeakMap) }; void JSWeakMap::finishCreation(VM& vm) { diff --git a/Source/JavaScriptCore/runtime/JSWeakMap.h b/Source/JavaScriptCore/runtime/JSWeakMap.h index a3229c265..81b3962de 100644 --- a/Source/JavaScriptCore/runtime/JSWeakMap.h +++ b/Source/JavaScriptCore/runtime/JSWeakMap.h @@ -65,6 +65,8 @@ public: void clear(CallFrame*); private: + static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; + JSWeakMap(VM& vm, Structure* structure) : Base(vm, structure) { diff --git a/Source/JavaScriptCore/runtime/JSWithScope.cpp b/Source/JavaScriptCore/runtime/JSWithScope.cpp index 1ffe8d1f2..82f2e210f 100644 --- a/Source/JavaScriptCore/runtime/JSWithScope.cpp +++ b/Source/JavaScriptCore/runtime/JSWithScope.cpp @@ -26,16 +26,19 @@ #include "config.h" #include "JSWithScope.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { -const ClassInfo JSWithScope::s_info = { "WithScope", &Base::s_info, 0, CREATE_METHOD_TABLE(JSWithScope) }; +const ClassInfo JSWithScope::s_info = { "WithScope", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSWithScope) }; void JSWithScope::visitChildren(JSCell* cell, SlotVisitor& visitor) { JSWithScope* thisObject = jsCast<JSWithScope*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + Base::visitChildren(thisObject, visitor); visitor.append(&thisObject->m_object); } diff --git a/Source/JavaScriptCore/runtime/JSWithScope.h b/Source/JavaScriptCore/runtime/JSWithScope.h index 8e5d09fa1..9b7e1826d 100644 --- a/Source/JavaScriptCore/runtime/JSWithScope.h +++ b/Source/JavaScriptCore/runtime/JSWithScope.h @@ -34,6 +34,13 @@ class JSWithScope : public JSScope { public: typedef JSScope Base; + static JSWithScope* create(ExecState* exec, JSObject* object) + { + JSWithScope* withScope = new (NotNull, allocateCell<JSWithScope>(*exec->heap())) JSWithScope(exec, object); + 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); @@ -52,7 +59,20 @@ public: DECLARE_EXPORT_INFO; +protected: + static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; + private: + JSWithScope(ExecState* exec, JSObject* object) + : Base( + exec->vm(), + exec->lexicalGlobalObject()->withScopeStructure(), + exec->scope() + ) + , m_object(exec->vm(), this, object) + { + } + JSWithScope(ExecState* exec, JSObject* object, JSScope* next) : Base( exec->vm(), diff --git a/Source/JavaScriptCore/runtime/JSWrapperObject.cpp b/Source/JavaScriptCore/runtime/JSWrapperObject.cpp index b6fadadb0..3853207ff 100644 --- a/Source/JavaScriptCore/runtime/JSWrapperObject.cpp +++ b/Source/JavaScriptCore/runtime/JSWrapperObject.cpp @@ -22,7 +22,7 @@ #include "config.h" #include "JSWrapperObject.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { @@ -32,6 +32,9 @@ void JSWrapperObject::visitChildren(JSCell* cell, SlotVisitor& visitor) { JSWrapperObject* thisObject = jsCast<JSWrapperObject*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + JSObject::visitChildren(thisObject, visitor); visitor.append(&thisObject->m_internalValue); } diff --git a/Source/JavaScriptCore/runtime/JSWrapperObject.h b/Source/JavaScriptCore/runtime/JSWrapperObject.h index 1036add59..349c75e6a 100644 --- a/Source/JavaScriptCore/runtime/JSWrapperObject.h +++ b/Source/JavaScriptCore/runtime/JSWrapperObject.h @@ -26,61 +26,62 @@ namespace JSC { -// This class is used as a base for classes such as String, -// Number, Boolean and Date which are wrappers for primitive types. -class JSWrapperObject : public JSDestructibleObject { -public: - typedef JSDestructibleObject Base; - - static size_t allocationSize(size_t inlineCapacity) - { - ASSERT_UNUSED(inlineCapacity, !inlineCapacity); - return sizeof(JSWrapperObject); - } - - JSValue internalValue() const; - void setInternalValue(VM&, JSValue); - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } - - static ptrdiff_t internalValueOffset() { return OBJECT_OFFSETOF(JSWrapperObject, m_internalValue); } - static ptrdiff_t internalValueCellOffset() - { + // This class is used as a base for classes such as String, + // Number, Boolean and Date which are wrappers for primitive types. + class JSWrapperObject : public JSDestructibleObject { + public: + typedef JSDestructibleObject Base; + + static size_t allocationSize(size_t inlineCapacity) + { + ASSERT_UNUSED(inlineCapacity, !inlineCapacity); + return sizeof(JSWrapperObject); + } + + JSValue internalValue() const; + void setInternalValue(VM&, JSValue); + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } + + static ptrdiff_t internalValueOffset() { return OBJECT_OFFSETOF(JSWrapperObject, m_internalValue); } + static ptrdiff_t internalValueCellOffset() + { #if USE(JSVALUE64) - return internalValueOffset(); + return internalValueOffset(); #else - return internalValueOffset() + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload); + return internalValueOffset() + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload); #endif - } + } -protected: - explicit JSWrapperObject(VM&, Structure*); + protected: + explicit JSWrapperObject(VM&, Structure*); + static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; - JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); + static void visitChildren(JSCell*, SlotVisitor&); -private: - WriteBarrier<Unknown> m_internalValue; -}; + private: + WriteBarrier<Unknown> m_internalValue; + }; -inline JSWrapperObject::JSWrapperObject(VM& vm, Structure* structure) - : JSDestructibleObject(vm, structure) -{ -} + inline JSWrapperObject::JSWrapperObject(VM& vm, Structure* structure) + : JSDestructibleObject(vm, structure) + { + } -inline JSValue JSWrapperObject::internalValue() const -{ - return m_internalValue.get(); -} + inline JSValue JSWrapperObject::internalValue() const + { + return m_internalValue.get(); + } -inline void JSWrapperObject::setInternalValue(VM& vm, JSValue value) -{ - ASSERT(value); - ASSERT(!value.isObject()); - m_internalValue.set(vm, this, value); -} + inline void JSWrapperObject::setInternalValue(VM& vm, JSValue value) + { + ASSERT(value); + ASSERT(!value.isObject()); + m_internalValue.set(vm, this, value); + } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/LiteralParser.cpp b/Source/JavaScriptCore/runtime/LiteralParser.cpp index 3aed10d9b..21f6cc301 100644 --- a/Source/JavaScriptCore/runtime/LiteralParser.cpp +++ b/Source/JavaScriptCore/runtime/LiteralParser.cpp @@ -33,7 +33,7 @@ #include "JSString.h" #include "Lexer.h" #include "ObjectConstructor.h" -#include "JSCInlines.h" +#include "Operations.h" #include "StrongInlines.h" #include <wtf/ASCIICType.h> #include <wtf/dtoa.h> @@ -57,20 +57,20 @@ bool LiteralParser<CharType>::tryJSONPParse(Vector<JSONPData>& results, bool nee do { Vector<JSONPPathEntry> path; // Unguarded next to start off the lexer - Identifier name = Identifier::fromString(&m_exec->vm(), 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->vm().propertyNames->varKeyword) { if (m_lexer.next() != TokIdentifier) return false; entry.m_type = JSONPPathEntryTypeDeclare; - entry.m_pathEntryName = Identifier::fromString(&m_exec->vm(), 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::fromString(&m_exec->vm(), 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 (isLexerKeyword(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) @@ -94,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::fromString(&m_exec->vm(), 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: { @@ -135,17 +135,17 @@ ALWAYS_INLINE const Identifier LiteralParser<CharType>::makeIdentifier(const LCh if (!length) return m_exec->vm().propertyNames->emptyIdentifier; if (characters[0] >= MaximumCachableCharacter) - return Identifier::fromString(&m_exec->vm(), 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::fromString(&m_exec->vm(), 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::fromString(&m_exec->vm(), characters, length); + m_recentIdentifiers[characters[0]] = Identifier(&m_exec->vm(), characters, length); return m_recentIdentifiers[characters[0]]; } @@ -155,17 +155,17 @@ ALWAYS_INLINE const Identifier LiteralParser<CharType>::makeIdentifier(const UCh if (!length) return m_exec->vm().propertyNames->emptyIdentifier; if (characters[0] >= MaximumCachableCharacter) - return Identifier::fromString(&m_exec->vm(), 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::fromString(&m_exec->vm(), 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::fromString(&m_exec->vm(), characters, length); + m_recentIdentifiers[characters[0]] = Identifier(&m_exec->vm(), characters, length); return m_recentIdentifiers[characters[0]]; } @@ -281,7 +281,7 @@ template <ParserMode mode> TokenType LiteralParser<CharType>::Lexer::lex(Literal return lexString<mode, '\''>(token); } } - m_lexErrorMessage = String::format("Unrecognized token '%c'", *m_ptr); + m_lexErrorMessage = String::format("Unrecognized token '%c'", *m_ptr).impl(); return TokError; } @@ -406,7 +406,7 @@ template <ParserMode mode, char terminator> ALWAYS_INLINE TokenType LiteralParse } // uNNNN == 5 characters for (int i = 1; i < 5; i++) { if (!isASCIIHexDigit(m_ptr[i])) { - m_lexErrorMessage = String::format("\"\\%s\" is not a valid unicode escape", String(m_ptr, 5).ascii().data()); + m_lexErrorMessage = String::format("\"\\%s\" is not a valid unicode escape", String(m_ptr, 5).ascii().data()).impl(); return TokError; } } @@ -420,7 +420,7 @@ template <ParserMode mode, char terminator> ALWAYS_INLINE TokenType LiteralParse m_ptr++; break; } - m_lexErrorMessage = String::format("Invalid escape character %c", *m_ptr); + m_lexErrorMessage = String::format("Invalid escape character %c", *m_ptr).impl(); return TokError; } } @@ -497,7 +497,7 @@ TokenType LiteralParser<CharType>::Lexer::lexNumber(LiteralParserToken<CharType> while (m_ptr < m_end && isASCIIDigit(*m_ptr)) ++m_ptr; } else if (m_ptr < m_end && (*m_ptr != 'e' && *m_ptr != 'E') && (m_ptr - token.start) < 10) { - double result = 0; + int result = 0; token.type = TokNumber; token.end = m_ptr; const CharType* digit = token.start; @@ -548,7 +548,6 @@ JSValue LiteralParser<CharType>::parse(ParserState initialState) JSValue lastValue; Vector<ParserState, 16, UnsafeVectorOverflow> stateStack; Vector<Identifier, 16, UnsafeVectorOverflow> identifierStack; - HashSet<JSObject*> visitedUnderscoreProto; while (1) { switch(state) { startParseArray: @@ -650,20 +649,11 @@ JSValue LiteralParser<CharType>::parse(ParserState initialState) { JSObject* object = asObject(objectStack.last()); PropertyName ident = identifierStack.last(); - if (m_mode != StrictJSON && ident == m_exec->vm().propertyNames->underscoreProto) { - if (!visitedUnderscoreProto.add(object).isNewEntry) { - m_parseErrorMessage = ASCIILiteral("Attempted to redefine __proto__ property"); - return JSValue(); - } - CodeBlock* codeBlock = m_exec->codeBlock(); - PutPropertySlot slot(object, codeBlock ? codeBlock->isStrictMode() : false); - objectStack.last().put(m_exec, ident, lastValue, slot); - } else { - if (Optional<uint32_t> index = parseIndex(ident)) - object->putDirectIndex(m_exec, index.value(), lastValue); - else - object->putDirect(m_exec->vm(), ident, lastValue); - } + unsigned i = ident.asIndex(); + if (i != PropertyName::NotAnIndex) + object->putDirectIndex(m_exec, i, lastValue); + else + object->putDirect(m_exec->vm(), ident, lastValue); identifierStack.removeLast(); if (m_lexer.currentToken().type == TokComma) goto doParseObjectStartExpression; @@ -721,9 +711,9 @@ JSValue LiteralParser<CharType>::parse(ParserState initialState) case TokIdentifier: { const LiteralParserToken<CharType>& token = m_lexer.currentToken(); if (token.stringIs8Bit) - m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", String(m_lexer.currentToken().stringToken8, m_lexer.currentToken().stringLength).ascii().data()); + m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", String(m_lexer.currentToken().stringToken8, m_lexer.currentToken().stringLength).ascii().data()).impl(); else - m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", String(m_lexer.currentToken().stringToken16, m_lexer.currentToken().stringLength).ascii().data()); + m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", String(m_lexer.currentToken().stringToken16, m_lexer.currentToken().stringLength).ascii().data()).impl(); return JSValue(); } case TokColon: diff --git a/Source/JavaScriptCore/runtime/LiteralParser.h b/Source/JavaScriptCore/runtime/LiteralParser.h index fcb79fa40..f05f03204 100644 --- a/Source/JavaScriptCore/runtime/LiteralParser.h +++ b/Source/JavaScriptCore/runtime/LiteralParser.h @@ -98,9 +98,9 @@ public: String getErrorMessage() { if (!m_lexer.getErrorMessage().isEmpty()) - return String::format("JSON Parse error: %s", m_lexer.getErrorMessage().ascii().data()); + return String::format("JSON Parse error: %s", m_lexer.getErrorMessage().ascii().data()).impl(); if (!m_parseErrorMessage.isEmpty()) - return String::format("JSON Parse error: %s", m_parseErrorMessage.ascii().data()); + return String::format("JSON Parse error: %s", m_parseErrorMessage.ascii().data()).impl(); return ASCIILiteral("JSON Parse error: Unable to parse JSON string"); } diff --git a/Source/JavaScriptCore/runtime/Lookup.cpp b/Source/JavaScriptCore/runtime/Lookup.cpp index 7df15b486..a806dd052 100644 --- a/Source/JavaScriptCore/runtime/Lookup.cpp +++ b/Source/JavaScriptCore/runtime/Lookup.cpp @@ -21,32 +21,56 @@ #include "Lookup.h" #include "Executable.h" -#include "GetterSetter.h" #include "JSFunction.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { -void reifyStaticAccessor(VM& vm, const HashTableValue& value, JSObject& thisObj, PropertyName propertyName) +void HashTable::createTable(VM& vm) const { - JSGlobalObject* globalObject = thisObj.globalObject(); - GetterSetter* accessor = GetterSetter::create(vm, globalObject); - if (value.accessorGetter()) { - RefPtr<StringImpl> getterName = WTF::tryMakeString(ASCIILiteral("get "), String(*propertyName.publicName())); - if (!getterName) - return; - accessor->setGetter(vm, globalObject, JSFunction::create(vm, globalObject, 0, *getterName, value.accessorGetter())); + ASSERT(!table); + int linkIndex = compactHashSizeMask + 1; + HashEntry* entries = new HashEntry[compactSize]; + for (int i = 0; i < compactSize; ++i) + entries[i].setKey(0); + for (int i = 0; values[i].key; ++i) { + StringImpl* identifier = Identifier::add(&vm, values[i].key).leakRef(); + int hashIndex = identifier->existingHash() & compactHashSizeMask; + HashEntry* entry = &entries[hashIndex]; + + if (entry->key()) { + while (entry->next()) { + entry = entry->next(); + } + ASSERT(linkIndex < compactSize); + entry->setNext(&entries[linkIndex++]); + entry = entry->next(); + } + + entry->initialize(identifier, values[i].attributes, values[i].value1, values[i].value2, values[i].intrinsic); } - thisObj.putDirectNonIndexAccessor(vm, propertyName, accessor, value.attributes()); + table = entries; } -bool setUpStaticFunctionSlot(ExecState* exec, const HashTableValue* entry, JSObject* thisObj, PropertyName propertyName, PropertySlot& slot) +void HashTable::deleteTable() const +{ + if (table) { + int max = compactSize; + for (int i = 0; i != max; ++i) { + if (StringImpl* key = table[i].key()) + key->deref(); + } + delete [] table; + table = 0; + } +} + +bool setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, PropertyName propertyName, PropertySlot& slot) { ASSERT(thisObj->globalObject()); - ASSERT(entry->attributes() & BuiltinOrFunctionOrAccessor); + ASSERT(entry->attributes() & Function); VM& vm = exec->vm(); unsigned attributes; - bool isAccessor = entry->attributes() & Accessor; PropertyOffset offset = thisObj->getDirectOffset(vm, propertyName, attributes); if (!isValidOffset(offset)) { @@ -54,26 +78,15 @@ bool setUpStaticFunctionSlot(ExecState* exec, const HashTableValue* entry, JSObj // all static functions at that time - after this we shouldn't be re-adding anything. if (thisObj->staticFunctionsReified()) return false; - - if (entry->attributes() & Builtin) - thisObj->putDirectBuiltinFunction(vm, thisObj->globalObject(), propertyName, entry->builtinGenerator()(vm), entry->attributes()); - else if (entry->attributes() & Function) { - thisObj->putDirectNativeFunction( - vm, thisObj->globalObject(), propertyName, entry->functionLength(), - entry->function(), entry->intrinsic(), entry->attributes()); - } else { - ASSERT(isAccessor); - reifyStaticAccessor(vm, *entry, *thisObj, propertyName); - } - + + thisObj->putDirectNativeFunction( + vm, thisObj->globalObject(), propertyName, entry->functionLength(), + entry->function(), entry->intrinsic(), entry->attributes()); offset = thisObj->getDirectOffset(vm, propertyName, attributes); ASSERT(isValidOffset(offset)); } - if (isAccessor) - slot.setCacheableGetterSlot(thisObj, attributes, jsCast<GetterSetter*>(thisObj->getDirect(offset)), offset); - else - slot.setValue(thisObj, attributes, thisObj->getDirect(offset), offset); + slot.setValue(thisObj, attributes, thisObj->getDirect(offset), offset); return true; } diff --git a/Source/JavaScriptCore/runtime/Lookup.h b/Source/JavaScriptCore/runtime/Lookup.h index 6f6023651..bde83d4a6 100644 --- a/Source/JavaScriptCore/runtime/Lookup.h +++ b/Source/JavaScriptCore/runtime/Lookup.h @@ -21,302 +21,305 @@ #ifndef Lookup_h #define Lookup_h -#include "BatchedTransitionOptimizer.h" #include "CallFrame.h" -#include "CustomGetterSetter.h" -#include "Identifier.h" -#include "IdentifierInlines.h" #include "Intrinsic.h" +#include "Identifier.h" #include "JSGlobalObject.h" #include "PropertySlot.h" #include "PutPropertySlot.h" #include <wtf/Assertions.h> namespace JSC { + // Hash table generated by the create_hash_table script. + struct HashTableValue { + const char* key; // property name + unsigned char attributes; // JSObject attributes + Intrinsic intrinsic; + intptr_t value1; + intptr_t value2; + }; -struct CompactHashIndex { - const int16_t value; - const int16_t next; -}; - -// FIXME: There is no reason this get function can't be simpler. -// ie. typedef JSValue (*GetFunction)(ExecState*, JSObject* baseObject) -typedef PropertySlot::GetValueFunc GetFunction; -typedef PutPropertySlot::PutValueFunc PutFunction; -typedef FunctionExecutable* (*BuiltinGenerator)(VM&); - -// Hash table generated by the create_hash_table script. -struct HashTableValue { - const char* m_key; // property name - unsigned m_attributes; // JSObject attributes - Intrinsic m_intrinsic; - union ValueStorage { - constexpr ValueStorage(intptr_t value1, intptr_t value2) - : value1(value1) - , value2(value2) - { } - constexpr ValueStorage(long long constant) - : constant(constant) - { } - - struct { - intptr_t value1; - intptr_t value2; - }; - long long constant; - } m_values; + // FIXME: There is no reason this get function can't be simpler. + // ie. typedef JSValue (*GetFunction)(ExecState*, JSObject* baseObject) + typedef PropertySlot::GetValueFunc GetFunction; + typedef PutPropertySlot::PutValueFunc PutFunction; - unsigned attributes() const { return m_attributes; } + class HashEntry { + WTF_MAKE_FAST_ALLOCATED; + public: + void initialize(StringImpl* key, unsigned char attributes, intptr_t v1, intptr_t v2, Intrinsic intrinsic) + { + m_key = key; + m_attributes = attributes; + m_u.store.value1 = v1; + m_u.store.value2 = v2; + m_intrinsic = intrinsic; + m_next = 0; + } - Intrinsic intrinsic() const { ASSERT(m_attributes & Function); return m_intrinsic; } - BuiltinGenerator builtinGenerator() const { ASSERT(m_attributes & Builtin); return reinterpret_cast<BuiltinGenerator>(m_values.value1); } - NativeFunction function() const { ASSERT(m_attributes & Function); return reinterpret_cast<NativeFunction>(m_values.value1); } - unsigned char functionLength() const { ASSERT(m_attributes & Function); return static_cast<unsigned char>(m_values.value2); } + void setKey(StringImpl* key) { m_key = key; } + StringImpl* key() const { return m_key; } - GetFunction propertyGetter() const { ASSERT(!(m_attributes & BuiltinOrFunctionOrAccessorOrConstant)); return reinterpret_cast<GetFunction>(m_values.value1); } - PutFunction propertyPutter() const { ASSERT(!(m_attributes & BuiltinOrFunctionOrAccessorOrConstant)); return reinterpret_cast<PutFunction>(m_values.value2); } + unsigned char attributes() const { return m_attributes; } - NativeFunction accessorGetter() const { ASSERT(m_attributes & Accessor); return reinterpret_cast<NativeFunction>(m_values.value1); } - NativeFunction accessorSetter() const { ASSERT(m_attributes & Accessor); return reinterpret_cast<NativeFunction>(m_values.value2); } + Intrinsic intrinsic() const + { + ASSERT(m_attributes & Function); + return m_intrinsic; + } - long long constantInteger() const { ASSERT(m_attributes & ConstantInteger); return m_values.constant; } + NativeFunction function() const { ASSERT(m_attributes & Function); return m_u.function.functionValue; } + unsigned char functionLength() const { ASSERT(m_attributes & Function); return static_cast<unsigned char>(m_u.function.length); } - intptr_t lexerValue() const { ASSERT(!m_attributes); return m_values.value1; } -}; + GetFunction propertyGetter() const { ASSERT(!(m_attributes & Function)); return m_u.property.get; } + PutFunction propertyPutter() const { ASSERT(!(m_attributes & Function)); return m_u.property.put; } -struct HashTable { - int numberOfValues; - int indexMask; - bool hasSetterOrReadonlyProperties; + intptr_t lexerValue() const { ASSERT(!m_attributes); return m_u.lexer.value; } - const HashTableValue* values; // Fixed values generated by script. - const CompactHashIndex* index; + void setNext(HashEntry *next) { m_next = next; } + HashEntry* next() const { return m_next; } - // Find an entry in the table, and return the entry. - ALWAYS_INLINE const HashTableValue* entry(PropertyName propertyName) const - { - if (propertyName.isSymbol()) - return nullptr; - - auto uid = propertyName.uid(); - if (!uid) - return nullptr; - - int indexEntry = IdentifierRepHash::hash(uid) & indexMask; - int valueIndex = index[indexEntry].value; - if (valueIndex == -1) - return nullptr; - - while (true) { - if (WTF::equal(uid, values[valueIndex].m_key)) - return &values[valueIndex]; - - indexEntry = index[indexEntry].next; - if (indexEntry == -1) - return nullptr; - valueIndex = index[indexEntry].value; - ASSERT(valueIndex != -1); - }; - } + private: + StringImpl* m_key; + unsigned char m_attributes; // JSObject attributes + Intrinsic m_intrinsic; + + union { + struct { + intptr_t value1; + intptr_t value2; + } store; + struct { + NativeFunction functionValue; + intptr_t length; // number of arguments for function + } function; + struct { + GetFunction get; + PutFunction put; + } property; + struct { + intptr_t value; + intptr_t unused; + } lexer; + } m_u; + + HashEntry* m_next; + }; - class ConstIterator { - public: - ConstIterator(const HashTable* table, int position) - : m_table(table) - , m_position(position) + struct HashTable { + + int compactSize; + int compactHashSizeMask; + bool hasSetterOrReadonlyProperties; + + const HashTableValue* values; // Fixed values generated by script. + mutable const HashEntry* table; // Table allocated at runtime. + + ALWAYS_INLINE HashTable copy() const { - skipInvalidKeys(); + // Don't copy dynamic table since it's thread specific. + HashTable result = { compactSize, compactHashSizeMask, hasSetterOrReadonlyProperties, values, 0 }; + return result; } - const HashTableValue* value() + ALWAYS_INLINE void initializeIfNeeded(VM& vm) const { - return &m_table->values[m_position]; + if (!table) + createTable(vm); } - const char* key() + ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const { - return m_table->values[m_position].m_key; + if (!table) + createTable(exec->vm()); } - const HashTableValue* operator->() + JS_EXPORT_PRIVATE void deleteTable() const; + + // Find an entry in the table, and return the entry. + ALWAYS_INLINE const HashEntry* entry(VM& vm, PropertyName identifier) const { - return value(); + initializeIfNeeded(vm); + return entry(identifier); } - bool operator!=(const ConstIterator& other) + ALWAYS_INLINE const HashEntry* entry(ExecState* exec, PropertyName identifier) const { - ASSERT(m_table == other.m_table); - return m_position != other.m_position; + initializeIfNeeded(exec); + return entry(identifier); } - ConstIterator& operator++() + class ConstIterator { + public: + ConstIterator(const HashTable* table, int position) + : m_table(table) + , m_position(position) + { + skipInvalidKeys(); + } + + const HashEntry* operator->() + { + return &m_table->table[m_position]; + } + + const HashEntry* operator*() + { + return &m_table->table[m_position]; + } + + bool operator!=(const ConstIterator& other) + { + ASSERT(m_table == other.m_table); + return m_position != other.m_position; + } + + ConstIterator& operator++() + { + ASSERT(m_position < m_table->compactSize); + ++m_position; + skipInvalidKeys(); + return *this; + } + + private: + void skipInvalidKeys() + { + ASSERT(m_position <= m_table->compactSize); + while (m_position < m_table->compactSize && !m_table->table[m_position].key()) + ++m_position; + ASSERT(m_position <= m_table->compactSize); + } + + const HashTable* m_table; + int m_position; + }; + + ConstIterator begin(VM& vm) const + { + initializeIfNeeded(vm); + return ConstIterator(this, 0); + } + ConstIterator end(VM& vm) const { - ASSERT(m_position < m_table->numberOfValues); - ++m_position; - skipInvalidKeys(); - return *this; + initializeIfNeeded(vm); + return ConstIterator(this, compactSize); } private: - void skipInvalidKeys() + ALWAYS_INLINE const HashEntry* entry(PropertyName propertyName) const { - ASSERT(m_position <= m_table->numberOfValues); - while (m_position < m_table->numberOfValues && !m_table->values[m_position].m_key) - ++m_position; - ASSERT(m_position <= m_table->numberOfValues); + StringImpl* impl = propertyName.publicName(); + if (!impl) + return 0; + + ASSERT(table); + + const HashEntry* entry = &table[impl->existingHash() & compactHashSizeMask]; + + if (!entry->key()) + return 0; + + do { + if (entry->key() == impl) + return entry; + entry = entry->next(); + } while (entry); + + return 0; } - const HashTable* m_table; - int m_position; + // Convert the hash table keys to identifiers. + JS_EXPORT_PRIVATE void createTable(VM&) const; }; - ConstIterator begin() const - { - return ConstIterator(this, 0); - } - ConstIterator end() const - { - return ConstIterator(this, numberOfValues); - } -}; - -JS_EXPORT_PRIVATE bool setUpStaticFunctionSlot(ExecState*, const HashTableValue*, JSObject* thisObject, PropertyName, PropertySlot&); -JS_EXPORT_PRIVATE void reifyStaticAccessor(VM&, const HashTableValue&, JSObject& thisObject, PropertyName); + JS_EXPORT_PRIVATE bool setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, PropertyName, PropertySlot&); -/** - * This method does it all (looking in the hashtable, checking for function - * overrides, creating the function or retrieving from cache, calling - * getValueProperty in case of a non-function property, forwarding to parent if - * unknown property). - */ -template <class ThisImp, class ParentImp> -inline bool getStaticPropertySlot(ExecState* exec, const HashTable& table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot) -{ - const HashTableValue* entry = table.entry(propertyName); + /** + * This method does it all (looking in the hashtable, checking for function + * overrides, creating the function or retrieving from cache, calling + * getValueProperty in case of a non-function property, forwarding to parent if + * unknown property). + */ + template <class ThisImp, class ParentImp> + inline bool getStaticPropertySlot(ExecState* exec, const HashTable& table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot) + { + const HashEntry* entry = table.entry(exec, propertyName); - if (!entry) // not found, forward to parent - return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot); + if (!entry) // not found, forward to parent + return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot); - if (entry->attributes() & BuiltinOrFunctionOrAccessor) - return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot); + if (entry->attributes() & Function) + return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot); - if (entry->attributes() & ConstantInteger) { - slot.setValue(thisObj, entry->attributes(), jsNumber(entry->constantInteger())); + slot.setCacheableCustom(thisObj, entry->attributes(), entry->propertyGetter()); return true; } - slot.setCacheableCustom(thisObj, entry->attributes(), entry->propertyGetter()); - return true; -} - -/** - * Simplified version of getStaticPropertySlot in case there are only functions. - * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing - * a dummy getValueProperty. - */ -template <class ParentImp> -inline bool getStaticFunctionSlot(ExecState* exec, const HashTable& table, JSObject* thisObj, PropertyName propertyName, PropertySlot& slot) -{ - if (ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot)) - return true; + /** + * Simplified version of getStaticPropertySlot in case there are only functions. + * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing + * a dummy getValueProperty. + */ + template <class ParentImp> + inline bool getStaticFunctionSlot(ExecState* exec, const HashTable& table, JSObject* thisObj, PropertyName propertyName, PropertySlot& slot) + { + if (ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot)) + return true; - const HashTableValue* entry = table.entry(propertyName); - if (!entry) - return false; + const HashEntry* entry = table.entry(exec, propertyName); + if (!entry) + return false; - return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot); -} + return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot); + } -/** - * Simplified version of getStaticPropertySlot in case there are no functions, only "values". - * Using this instead of getStaticPropertySlot removes the need for a FuncImp class. - */ -template <class ThisImp, class ParentImp> -inline bool getStaticValueSlot(ExecState* exec, const HashTable& table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot) -{ - const HashTableValue* entry = table.entry(propertyName); + /** + * Simplified version of getStaticPropertySlot in case there are no functions, only "values". + * Using this instead of getStaticPropertySlot removes the need for a FuncImp class. + */ + template <class ThisImp, class ParentImp> + inline bool getStaticValueSlot(ExecState* exec, const HashTable& table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot) + { + const HashEntry* entry = table.entry(exec, propertyName); - if (!entry) // not found, forward to parent - return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot); + if (!entry) // not found, forward to parent + return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot); - ASSERT(!(entry->attributes() & BuiltinOrFunctionOrAccessor)); + ASSERT(!(entry->attributes() & Function)); - if (entry->attributes() & ConstantInteger) { - slot.setValue(thisObj, entry->attributes(), jsNumber(entry->constantInteger())); + slot.setCacheableCustom(thisObj, entry->attributes(), entry->propertyGetter()); return true; } - slot.setCacheableCustom(thisObj, entry->attributes(), entry->propertyGetter()); - return true; -} - -inline void putEntry(ExecState* exec, const HashTableValue* entry, JSObject* base, PropertyName propertyName, JSValue value, PutPropertySlot& slot) -{ - // If this is a function put it as an override property. - if (entry->attributes() & BuiltinOrFunction) { - if (JSObject* thisObject = jsDynamicCast<JSObject*>(slot.thisValue())) - thisObject->putDirect(exec->vm(), propertyName, value); - } else if (entry->attributes() & Accessor) { - if (slot.isStrictMode()) + inline void putEntry(ExecState* exec, const HashEntry* entry, JSObject* base, PropertyName propertyName, JSValue value, PutPropertySlot& slot) + { + // If this is a function put it as an override property. + if (entry->attributes() & Function) { + if (JSObject* thisObject = jsDynamicCast<JSObject*>(slot.thisValue())) + thisObject->putDirect(exec->vm(), propertyName, value); + } else if (!(entry->attributes() & ReadOnly)) { + entry->propertyPutter()(exec, base, JSValue::encode(slot.thisValue()), JSValue::encode(value)); + slot.setCustomProperty(base, entry->propertyPutter()); + } else if (slot.isStrictMode()) throwTypeError(exec, StrictModeReadonlyPropertyWriteError); - } else if (!(entry->attributes() & ReadOnly)) { - entry->propertyPutter()(exec, base, JSValue::encode(slot.thisValue()), JSValue::encode(value)); - slot.setCustomProperty(base, entry->propertyPutter()); - } else if (slot.isStrictMode()) - throwTypeError(exec, StrictModeReadonlyPropertyWriteError); -} - -/** - * This one is for "put". - * It looks up a hash entry for the property to be set. If an entry - * is found it sets the value and returns true, else it returns false. - */ -inline bool lookupPut(ExecState* exec, PropertyName propertyName, JSObject* base, JSValue value, const HashTable& table, PutPropertySlot& slot) -{ - const HashTableValue* entry = table.entry(propertyName); - - if (!entry) - return false; - - putEntry(exec, entry, base, propertyName, value, slot); - return true; -} - -template<unsigned numberOfValues> -inline void reifyStaticProperties(VM& vm, const HashTableValue (&values)[numberOfValues], JSObject& thisObj) -{ - BatchedTransitionOptimizer transitionOptimizer(vm, &thisObj); - for (auto& value : values) { - if (!value.m_key) - continue; - - Identifier propertyName = Identifier::fromString(&vm, reinterpret_cast<const LChar*>(value.m_key), strlen(value.m_key)); - if (value.attributes() & Builtin) { - thisObj.putDirectBuiltinFunction(vm, thisObj.globalObject(), propertyName, value.builtinGenerator()(vm), value.attributes()); - continue; - } - - if (value.attributes() & Function) { - thisObj.putDirectNativeFunction(vm, thisObj.globalObject(), propertyName, value.functionLength(), - value.function(), value.intrinsic(), value.attributes()); - continue; - } + } - if (value.attributes() & ConstantInteger) { - thisObj.putDirect(vm, propertyName, jsNumber(value.constantInteger()), value.attributes()); - continue; - } + /** + * This one is for "put". + * It looks up a hash entry for the property to be set. If an entry + * is found it sets the value and returns true, else it returns false. + */ + inline bool lookupPut(ExecState* exec, PropertyName propertyName, JSObject* base, JSValue value, const HashTable& table, PutPropertySlot& slot) + { + const HashEntry* entry = table.entry(exec, propertyName); - if (value.attributes() & Accessor) { - reifyStaticAccessor(vm, value, thisObj, propertyName); - continue; - } + if (!entry) + return false; - CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, value.propertyGetter(), value.propertyPutter()); - thisObj.putDirectCustomAccessor(vm, propertyName, customGetterSetter, value.attributes()); + putEntry(exec, entry, base, propertyName, value, slot); + return true; } -} - } // namespace JSC #endif // Lookup_h diff --git a/Source/JavaScriptCore/runtime/MapConstructor.cpp b/Source/JavaScriptCore/runtime/MapConstructor.cpp index fad52c056..9e3a4bf3b 100644 --- a/Source/JavaScriptCore/runtime/MapConstructor.cpp +++ b/Source/JavaScriptCore/runtime/MapConstructor.cpp @@ -27,17 +27,15 @@ #include "MapConstructor.h" #include "Error.h" -#include "IteratorOperations.h" #include "JSCJSValueInlines.h" #include "JSCellInlines.h" #include "JSGlobalObject.h" #include "JSMap.h" #include "MapPrototype.h" -#include "StructureInlines.h" namespace JSC { -const ClassInfo MapConstructor::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(MapConstructor) }; +const ClassInfo MapConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(MapConstructor) }; void MapConstructor::finishCreation(VM& vm, MapPrototype* mapPrototype) { @@ -46,87 +44,18 @@ void MapConstructor::finishCreation(VM& vm, MapPrototype* mapPrototype) putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), ReadOnly | DontEnum | DontDelete); } -static EncodedJSValue JSC_HOST_CALL callMap(ExecState* exec) -{ - return JSValue::encode(throwTypeError(exec, ASCIILiteral("Map cannot be called as a function"))); -} - static EncodedJSValue JSC_HOST_CALL constructMap(ExecState* exec) { + // Until we have iterators we throw if we've been given + // any arguments that could require us to throw. + if (!exec->argument(0).isUndefinedOrNull()) + return JSValue::encode(throwTypeError(exec, ASCIILiteral("Map constructor does not accept arguments"))); + if (!exec->argument(1).isUndefined()) + return throwVMError(exec, createRangeError(exec, WTF::ASCIILiteral("Invalid comparator function"))); + JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject(); Structure* mapStructure = globalObject->mapStructure(); - JSMap* map = JSMap::create(exec, mapStructure); - JSValue iterable = exec->argument(0); - if (iterable.isUndefinedOrNull()) - return JSValue::encode(map); - - JSValue adderFunction = map->JSObject::get(exec, exec->propertyNames().set); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - CallData adderFunctionCallData; - CallType adderFunctionCallType = getCallData(adderFunction, adderFunctionCallData); - if (adderFunctionCallType == CallTypeNone) - return JSValue::encode(throwTypeError(exec)); - - JSValue iteratorFunction = iterable.get(exec, exec->propertyNames().iteratorSymbol); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - CallData iteratorFunctionCallData; - CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData); - if (iteratorFunctionCallType == CallTypeNone) - return JSValue::encode(throwTypeError(exec)); - - ArgList iteratorFunctionArguments; - JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - if (!iterator.isObject()) - return JSValue::encode(throwTypeError(exec)); - - while (true) { - JSValue next = iteratorStep(exec, iterator); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - if (next.isFalse()) - return JSValue::encode(map); - - JSValue nextItem = iteratorValue(exec, next); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - if (!nextItem.isObject()) { - throwTypeError(exec); - iteratorClose(exec, iterator); - return JSValue::encode(jsUndefined()); - } - - JSValue key = nextItem.get(exec, 0); - if (exec->hadException()) { - iteratorClose(exec, iterator); - return JSValue::encode(jsUndefined()); - } - - JSValue value = nextItem.get(exec, 1); - if (exec->hadException()) { - iteratorClose(exec, iterator); - return JSValue::encode(jsUndefined()); - } - - MarkedArgumentBuffer arguments; - arguments.append(key); - arguments.append(value); - call(exec, adderFunction, adderFunctionCallType, adderFunctionCallData, map, arguments); - if (exec->hadException()) { - iteratorClose(exec, iterator); - return JSValue::encode(jsUndefined()); - } - } - RELEASE_ASSERT_NOT_REACHED(); - return JSValue::encode(map); + return JSValue::encode(JSMap::create(exec, mapStructure)); } ConstructType MapConstructor::getConstructData(JSCell*, ConstructData& constructData) @@ -137,7 +66,7 @@ ConstructType MapConstructor::getConstructData(JSCell*, ConstructData& construct CallType MapConstructor::getCallData(JSCell*, CallData& callData) { - callData.native.function = callMap; + callData.native.function = constructMap; return CallTypeHost; } diff --git a/Source/JavaScriptCore/runtime/MapData.cpp b/Source/JavaScriptCore/runtime/MapData.cpp new file mode 100644 index 000000000..f5a3e7610 --- /dev/null +++ b/Source/JavaScriptCore/runtime/MapData.cpp @@ -0,0 +1,256 @@ +/* + * 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 "MapData.h" + +#include "CopiedAllocator.h" +#include "CopyVisitorInlines.h" +#include "ExceptionHelpers.h" +#include "JSCJSValueInlines.h" +#include "SlotVisitorInlines.h" + +#include <wtf/CryptographicallyRandomNumber.h> +#include <wtf/MathExtras.h> + + +namespace JSC { + +const ClassInfo MapData::s_info = { "MapData", 0, 0, 0, CREATE_METHOD_TABLE(MapData) }; + +static const int32_t minimumMapSize = 8; + +MapData::MapData(VM& vm) + : Base(vm, vm.mapDataStructure.get()) + , m_capacity(0) + , m_size(0) + , m_deletedCount(0) + , m_iteratorCount(0) + , m_entries(0) +{ +} + +MapData::Entry* MapData::find(CallFrame* callFrame, KeyType key) +{ + if (key.value.isString()) { + auto iter = m_stringKeyedTable.find(asString(key.value)->value(callFrame).impl()); + if (iter == m_stringKeyedTable.end()) + return 0; + return &m_entries[iter->value]; + } + if (key.value.isCell()) { + auto iter = m_cellKeyedTable.find(key.value.asCell()); + if (iter == m_cellKeyedTable.end()) + return 0; + return &m_entries[iter->value]; + } + + auto iter = m_valueKeyedTable.find(JSValue::encode(key.value)); + if (iter == m_valueKeyedTable.end()) + return 0; + return &m_entries[iter->value]; +} + +bool MapData::contains(CallFrame* callFrame, KeyType key) +{ + return find(callFrame, key); +} + +template <typename Map, typename Key> MapData::Entry* MapData::add(CallFrame* callFrame, Map& map, Key key, KeyType keyValue) +{ + typename Map::iterator location = map.find(key); + if (location != map.end()) + return &m_entries[location->value]; + + if (!ensureSpaceForAppend(callFrame)) + return 0; + + auto result = map.add(key, m_size); + RELEASE_ASSERT(result.isNewEntry); + Entry* entry = &m_entries[m_size++]; + new (entry) Entry(); + entry->key.set(callFrame->vm(), this, keyValue.value); + return entry; +} + +void MapData::set(CallFrame* callFrame, KeyType key, JSValue value) +{ + Entry* location = add(callFrame, key); + if (!location) + return; + location->value.set(callFrame->vm(), this, value); +} + +MapData::Entry* MapData::add(CallFrame* callFrame, KeyType key) +{ + if (key.value.isString()) + return add(callFrame, m_stringKeyedTable, asString(key.value)->value(callFrame).impl(), key); + if (key.value.isCell()) + return add(callFrame, m_cellKeyedTable, key.value.asCell(), key); + return add(callFrame, m_valueKeyedTable, JSValue::encode(key.value), key); +} + +JSValue MapData::get(CallFrame* callFrame, KeyType key) +{ + if (Entry* entry = find(callFrame, key)) + return entry->value.get(); + return JSValue(); +} + +bool MapData::remove(CallFrame* callFrame, KeyType key) +{ + int32_t location; + if (key.value.isString()) { + auto iter = m_stringKeyedTable.find(asString(key.value)->value(callFrame).impl()); + if (iter == m_stringKeyedTable.end()) + return false; + location = iter->value; + m_stringKeyedTable.remove(iter); + } else if (key.value.isCell()) { + auto iter = m_cellKeyedTable.find(key.value.asCell()); + if (iter == m_cellKeyedTable.end()) + return false; + location = iter->value; + m_cellKeyedTable.remove(iter); + } else { + auto iter = m_valueKeyedTable.find(JSValue::encode(key.value)); + if (iter == m_valueKeyedTable.end()) + return false; + location = iter->value; + m_valueKeyedTable.remove(iter); + } + m_entries[location].key.clear(); + m_entries[location].value.clear(); + m_deletedCount++; + return true; +} + +void MapData::replaceAndPackBackingStore(Entry* destination, int32_t newCapacity) +{ + ASSERT(shouldPack()); + int32_t newEnd = 0; + RELEASE_ASSERT(newCapacity > 0); + for (int32_t i = 0; i < m_size; i++) { + Entry& entry = m_entries[i]; + if (!entry.key) + continue; + ASSERT(newEnd < newCapacity); + destination[newEnd] = entry; + + // We overwrite the old entry with a forwarding index for the new entry, + // so that we can fix up our hash tables below without doing additional + // hash lookups + entry.value.setWithoutWriteBarrier(jsNumber(newEnd)); + newEnd++; + } + + // Fixup for the hashmaps + for (auto ptr = m_valueKeyedTable.begin(); ptr != m_valueKeyedTable.end(); ++ptr) + ptr->value = m_entries[ptr->value].value.get().asInt32(); + for (auto ptr = m_stringKeyedTable.begin(); ptr != m_stringKeyedTable.end(); ++ptr) + ptr->value = m_entries[ptr->value].value.get().asInt32(); + + ASSERT((m_size - newEnd) == m_deletedCount); + m_deletedCount = 0; + + m_capacity = newCapacity; + m_size = newEnd; + m_entries = destination; + +} + +void MapData::replaceBackingStore(Entry* destination, int32_t newCapacity) +{ + ASSERT(!shouldPack()); + RELEASE_ASSERT(newCapacity > 0); + ASSERT(newCapacity >= m_capacity); + memcpy(destination, m_entries, sizeof(Entry) * m_size); + m_capacity = newCapacity; + m_entries = destination; +} + +CheckedBoolean MapData::ensureSpaceForAppend(CallFrame* callFrame) +{ + if (m_capacity > m_size) + return true; + + size_t requiredSize = std::max(m_capacity + (m_capacity / 2) + 1, minimumMapSize); + void* newStorage = 0; + DeferGC defer(*callFrame->heap()); + if (!callFrame->heap()->tryAllocateStorage(this, requiredSize * sizeof(Entry), &newStorage)) { + throwOutOfMemoryError(callFrame); + return false; + } + Entry* newEntries = static_cast<Entry*>(newStorage); + if (shouldPack()) + replaceAndPackBackingStore(newEntries, requiredSize); + else + replaceBackingStore(newEntries, requiredSize); + Heap::writeBarrier(this); + return true; +} + +void MapData::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + Base::visitChildren(cell, visitor); + MapData* thisObject = jsCast<MapData*>(cell); + Entry* entries = thisObject->m_entries; + if (!entries) + return; + size_t size = thisObject->m_size; + if (thisObject->m_deletedCount) { + for (size_t i = 0; i < size; i++) { + if (!entries[i].key) + continue; + visitor.append(&entries[i].key); + visitor.append(&entries[i].value); + } + } else + visitor.appendValues(&entries[0].key, size * (sizeof(Entry) / sizeof(WriteBarrier<Unknown>))); + + visitor.copyLater(thisObject, MapBackingStoreCopyToken, entries, thisObject->capacityInBytes()); +} + +void MapData::copyBackingStore(JSCell* cell, CopyVisitor& visitor, CopyToken token) +{ + MapData* thisObject = jsCast<MapData*>(cell); + if (token == MapBackingStoreCopyToken && visitor.checkIfShouldCopy(thisObject->m_entries)) { + Entry* oldEntries = thisObject->m_entries; + Entry* newEntries = static_cast<Entry*>(visitor.allocateNewSpace(thisObject->capacityInBytes())); + if (thisObject->shouldPack()) + thisObject->replaceAndPackBackingStore(newEntries, thisObject->m_capacity); + else + thisObject->replaceBackingStore(newEntries, thisObject->m_capacity); + visitor.didCopy(oldEntries, thisObject->capacityInBytes()); + } + Base::copyBackingStore(cell, visitor, token); +} + +void MapData::destroy(JSCell* cell) +{ + static_cast<MapData*>(cell)->~MapData(); +} + +} diff --git a/Source/JavaScriptCore/runtime/MapData.h b/Source/JavaScriptCore/runtime/MapData.h index 3b5863efc..9c2bb559f 100644 --- a/Source/JavaScriptCore/runtime/MapData.h +++ b/Source/JavaScriptCore/runtime/MapData.h @@ -27,65 +27,41 @@ #define MapData_h #include "JSCell.h" -#include "WeakGCMapInlines.h" +#include "Structure.h" #include <wtf/HashFunctions.h> #include <wtf/HashMap.h> #include <wtf/MathExtras.h> -#include <wtf/RefCounted.h> -#include <wtf/RefPtr.h> -#include <wtf/Vector.h> namespace JSC { -class ExecState; -class VM; - -template<typename Entry, typename JSIterator> -class MapDataImpl { +class MapData : public JSCell { public: - enum : int32_t { - minimumMapSize = 8 - }; - - class IteratorData { - public: - friend class MapDataImpl; - - IteratorData(const MapDataImpl*); - bool next(WTF::KeyValuePair<JSValue, JSValue>&); - - // This function is called while packing a map's backing store. The - // passed-in index is the new index the entry would have after packing. - void didRemoveEntry(int32_t packedIndex) - { - if (isFinished()) - return; - - if (m_index <= packedIndex) - return; - - --m_index; - } - - void didRemoveAllEntries() - { - if (isFinished()) - return; - m_index = 0; - } - - void finish() - { - m_index = -1; - } + typedef JSCell Base; + + struct const_iterator { + const_iterator(const MapData*); + ~const_iterator(); + const WTF::KeyValuePair<JSValue, JSValue> operator*() const; + JSValue key() const { RELEASE_ASSERT(!atEnd()); return m_mapData->m_entries[m_index].key.get(); } + JSValue value() const { RELEASE_ASSERT(!atEnd()); return m_mapData->m_entries[m_index].value.get(); } + void operator++() { ASSERT(!atEnd()); internalIncrement(); } + static const_iterator end(const MapData*); + bool operator!=(const const_iterator& other); + bool operator==(const const_iterator& other); + void finish() { m_index = std::numeric_limits<int32_t>::max(); } + + bool ensureSlot(); private: - bool ensureSlot() const; - bool isFinished() const { return m_index == -1; } - int32_t refreshCursor() const; - - const MapDataImpl* m_mapData; - mutable int32_t m_index; + // This is a bit gnarly. We use an index of -1 to indicate the + // "end()" iterator. By casting to unsigned we can immediately + // test if both iterators are at the end of their iteration. + // We need this in order to keep the common case (eg. iter != end()) + // fast. + bool atEnd() const { return static_cast<size_t>(m_index) >= static_cast<size_t>(m_mapData->m_size); } + void internalIncrement(); + const MapData* m_mapData; + int32_t m_index; }; struct KeyType { @@ -94,37 +70,63 @@ public: JSValue value; }; - MapDataImpl(VM&); + static MapData* create(VM& vm) + { + MapData* mapData = new (NotNull, allocateCell<MapData>(vm.heap)) MapData(vm); + mapData->finishCreation(vm); + return mapData; + } + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, StructureFlags), info()); + } + + static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; - void set(ExecState*, JSCell* owner, KeyType, JSValue); - JSValue get(ExecState*, KeyType); - bool remove(ExecState*, KeyType); - bool contains(ExecState*, KeyType); - size_t size(ExecState*) const { return m_size - m_deletedCount; } + JS_EXPORT_PRIVATE void set(CallFrame*, KeyType, JSValue); + JSValue get(CallFrame*, KeyType); + bool remove(CallFrame*, KeyType); + bool contains(CallFrame*, KeyType); + size_t size(CallFrame*) const { return m_size - m_deletedCount; } - IteratorData createIteratorData(JSIterator*); + const_iterator begin() const { return const_iterator(this); } + const_iterator end() const { return const_iterator::end(this); } void clear(); - void visitChildren(JSCell* owner, SlotVisitor&); - void copyBackingStore(CopyVisitor&, CopyToken); + DECLARE_INFO; + static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; private: typedef WTF::UnsignedWithZeroKeyHashTraits<int32_t> IndexTraits; + // Our marking functions expect Entry to maintain this layout, and have all + // fields be WriteBarrier<Unknown> + struct Entry { + WriteBarrier<Unknown> key; + WriteBarrier<Unknown> value; + }; + typedef HashMap<JSCell*, int32_t, typename WTF::DefaultHash<JSCell*>::Hash, WTF::HashTraits<JSCell*>, IndexTraits> CellKeyedMap; typedef HashMap<EncodedJSValue, int32_t, EncodedJSValueHash, EncodedJSValueHashTraits, IndexTraits> ValueKeyedMap; typedef HashMap<StringImpl*, int32_t, typename WTF::DefaultHash<StringImpl*>::Hash, WTF::HashTraits<StringImpl*>, IndexTraits> StringKeyedMap; - typedef HashMap<SymbolImpl*, int32_t, typename WTF::PtrHash<SymbolImpl*>, WTF::HashTraits<SymbolImpl*>, IndexTraits> SymbolKeyedMap; size_t capacityInBytes() { return m_capacity * sizeof(Entry); } - ALWAYS_INLINE Entry* find(ExecState*, KeyType); - ALWAYS_INLINE Entry* add(ExecState*, JSCell* owner, KeyType); - template <typename Map, typename Key> ALWAYS_INLINE Entry* add(ExecState*, JSCell* owner, Map&, Key, KeyType); + MapData(VM&); + static void destroy(JSCell*); + static void visitChildren(JSCell*, SlotVisitor&); + static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken); + + + ALWAYS_INLINE Entry* find(CallFrame*, KeyType); + ALWAYS_INLINE Entry* add(CallFrame*, KeyType); + template <typename Map, typename Key> ALWAYS_INLINE Entry* add(CallFrame*, Map&, Key, KeyType); - ALWAYS_INLINE bool shouldPack() const { return m_deletedCount; } - CheckedBoolean ensureSpaceForAppend(ExecState*, JSCell* owner); + ALWAYS_INLINE bool shouldPack() const { return m_deletedCount && !m_iteratorCount; } + CheckedBoolean ensureSpaceForAppend(CallFrame*); ALWAYS_INLINE void replaceAndPackBackingStore(Entry* destination, int32_t newSize); ALWAYS_INLINE void replaceBackingStore(Entry* destination, int32_t newSize); @@ -132,33 +134,31 @@ private: CellKeyedMap m_cellKeyedTable; ValueKeyedMap m_valueKeyedTable; StringKeyedMap m_stringKeyedTable; - SymbolKeyedMap m_symbolKeyedTable; int32_t m_capacity; int32_t m_size; int32_t m_deletedCount; + mutable int32_t m_iteratorCount; Entry* m_entries; - WeakGCMap<JSIterator*, JSIterator> m_iterators; }; -template<typename Entry, typename JSIterator> -ALWAYS_INLINE MapDataImpl<Entry, JSIterator>::MapDataImpl(VM& vm) - : m_capacity(0) - , m_size(0) - , m_deletedCount(0) - , m_entries(nullptr) - , m_iterators(vm) +ALWAYS_INLINE void MapData::clear() { + m_valueKeyedTable.clear(); + m_stringKeyedTable.clear(); + m_capacity = 0; + m_size = 0; + m_deletedCount = 0; + m_entries = 0; } -template<typename Entry, typename JSIterator> -ALWAYS_INLINE MapDataImpl<Entry, JSIterator>::KeyType::KeyType(JSValue v) +ALWAYS_INLINE MapData::KeyType::KeyType(JSValue v) { if (!v.isDouble()) { value = v; return; } double d = v.asDouble(); - if (std::isnan(d)) { + if (std::isnan(d) || (std::signbit(d) && d == 0.0)) { value = v; return; } @@ -170,45 +170,65 @@ ALWAYS_INLINE MapDataImpl<Entry, JSIterator>::KeyType::KeyType(JSValue v) value = jsNumber(i); } -template<typename Entry, typename JSIterator> -ALWAYS_INLINE MapDataImpl<Entry, JSIterator>::IteratorData::IteratorData(const MapDataImpl<Entry, JSIterator>* mapData) +ALWAYS_INLINE void MapData::const_iterator::internalIncrement() +{ + Entry* entries = m_mapData->m_entries; + size_t index = m_index + 1; + size_t end = m_mapData->m_size; + while (index < end && !entries[index].key) + index++; + m_index = index; +} + +ALWAYS_INLINE bool MapData::const_iterator::ensureSlot() +{ + // When an iterator exists outside of host cost it is possible for + // the containing map to be modified + Entry* entries = m_mapData->m_entries; + size_t index = m_index; + size_t end = m_mapData->m_size; + if (index < end && entries[index].key) + return true; + internalIncrement(); + return static_cast<size_t>(m_index) < end; +} + +ALWAYS_INLINE MapData::const_iterator::const_iterator(const MapData* mapData) : m_mapData(mapData) - , m_index(0) + , m_index(-1) { + internalIncrement(); } -template<typename Entry, typename JSIterator> -ALWAYS_INLINE bool MapDataImpl<Entry, JSIterator>::IteratorData::next(WTF::KeyValuePair<JSValue, JSValue>& pair) +ALWAYS_INLINE MapData::const_iterator::~const_iterator() +{ + m_mapData->m_iteratorCount--; +} + +ALWAYS_INLINE const WTF::KeyValuePair<JSValue, JSValue> MapData::const_iterator::operator*() const { - if (!ensureSlot()) - return false; Entry* entry = &m_mapData->m_entries[m_index]; - pair = WTF::KeyValuePair<JSValue, JSValue>(entry->key().get(), entry->value().get()); - m_index += 1; - return true; + return WTF::KeyValuePair<JSValue, JSValue>(entry->key.get(), entry->value.get()); } -// This is a bit gnarly. We use an index of -1 to indicate the -// finished state. By casting to unsigned we can immediately -// test if both iterators are at the end of their iteration. -template<typename Entry, typename JSIterator> -ALWAYS_INLINE bool MapDataImpl<Entry, JSIterator>::IteratorData::ensureSlot() const +ALWAYS_INLINE MapData::const_iterator MapData::const_iterator::end(const MapData* mapData) { - int32_t index = refreshCursor(); - return static_cast<size_t>(index) < static_cast<size_t>(m_mapData->m_size); + const_iterator result(mapData); + result.m_index = -1; + return result; } -template<typename Entry, typename JSIterator> -ALWAYS_INLINE int32_t MapDataImpl<Entry, JSIterator>::IteratorData::refreshCursor() const +ALWAYS_INLINE bool MapData::const_iterator::operator!=(const const_iterator& other) { - if (isFinished()) - return m_index; + ASSERT(other.m_mapData == m_mapData); + if (atEnd() && other.atEnd()) + return false; + return m_index != other.m_index; +} - Entry* entries = m_mapData->m_entries; - size_t end = m_mapData->m_size; - while (static_cast<size_t>(m_index) < end && !entries[m_index].key()) - m_index++; - return m_index; +ALWAYS_INLINE bool MapData::const_iterator::operator==(const const_iterator& other) +{ + return !(*this != other); } } diff --git a/Source/JavaScriptCore/runtime/MapDataInlines.h b/Source/JavaScriptCore/runtime/MapDataInlines.h deleted file mode 100644 index 176acc1b3..000000000 --- a/Source/JavaScriptCore/runtime/MapDataInlines.h +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright (C) 2013 Apple Inc. All rights reserved. - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. - * - * 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 "CopiedAllocator.h" -#include "CopyVisitorInlines.h" -#include "ExceptionHelpers.h" -#include "JSCJSValueInlines.h" -#include "MapData.h" -#include "SlotVisitorInlines.h" - -#include <wtf/CryptographicallyRandomNumber.h> -#include <wtf/MathExtras.h> - - -namespace JSC { - -template<typename Entry, typename JSIterator> -inline void MapDataImpl<Entry, JSIterator>::clear() -{ - m_cellKeyedTable.clear(); - m_valueKeyedTable.clear(); - m_stringKeyedTable.clear(); - m_symbolKeyedTable.clear(); - m_capacity = 0; - m_size = 0; - m_deletedCount = 0; - m_entries = nullptr; - m_iterators.forEach([](JSIterator* iterator, JSIterator*) { - iterator->iteratorData()->didRemoveAllEntries(); - }); -} - -template<typename Entry, typename JSIterator> -inline Entry* MapDataImpl<Entry, JSIterator>::find(ExecState* exec, KeyType key) -{ - if (key.value.isString()) { - auto iter = m_stringKeyedTable.find(asString(key.value)->value(exec).impl()); - if (iter == m_stringKeyedTable.end()) - return 0; - return &m_entries[iter->value]; - } - if (key.value.isSymbol()) { - auto iter = m_symbolKeyedTable.find(asSymbol(key.value)->privateName().uid()); - if (iter == m_symbolKeyedTable.end()) - return 0; - return &m_entries[iter->value]; - } - if (key.value.isCell()) { - auto iter = m_cellKeyedTable.find(key.value.asCell()); - if (iter == m_cellKeyedTable.end()) - return 0; - return &m_entries[iter->value]; - } - - auto iter = m_valueKeyedTable.find(JSValue::encode(key.value)); - if (iter == m_valueKeyedTable.end()) - return 0; - return &m_entries[iter->value]; -} - -template<typename Entry, typename JSIterator> -inline bool MapDataImpl<Entry, JSIterator>::contains(ExecState* exec, KeyType key) -{ - return find(exec, key); -} - -template<typename Entry, typename JSIterator> -template <typename Map, typename Key> -inline Entry* MapDataImpl<Entry, JSIterator>::add(ExecState* exec, JSCell* owner, Map& map, Key key, KeyType keyValue) -{ - typename Map::iterator location = map.find(key); - if (location != map.end()) - return &m_entries[location->value]; - - if (!ensureSpaceForAppend(exec, owner)) - return 0; - - auto result = map.add(key, m_size); - RELEASE_ASSERT(result.isNewEntry); - Entry* entry = &m_entries[m_size++]; - new (entry) Entry(); - entry->setKey(exec->vm(), owner, keyValue.value); - return entry; -} - -template<typename Entry, typename JSIterator> -inline void MapDataImpl<Entry, JSIterator>::set(ExecState* exec, JSCell* owner, KeyType key, JSValue value) -{ - Entry* location = add(exec, owner, key); - if (!location) - return; - location->setValue(exec->vm(), owner, value); -} - -template<typename Entry, typename JSIterator> -inline Entry* MapDataImpl<Entry, JSIterator>::add(ExecState* exec, JSCell* owner, KeyType key) -{ - if (key.value.isString()) - return add(exec, owner, m_stringKeyedTable, asString(key.value)->value(exec).impl(), key); - if (key.value.isSymbol()) - return add(exec, owner, m_symbolKeyedTable, asSymbol(key.value)->privateName().uid(), key); - if (key.value.isCell()) - return add(exec, owner, m_cellKeyedTable, key.value.asCell(), key); - return add(exec, owner, m_valueKeyedTable, JSValue::encode(key.value), key); -} - -template<typename Entry, typename JSIterator> -inline JSValue MapDataImpl<Entry, JSIterator>::get(ExecState* exec, KeyType key) -{ - if (Entry* entry = find(exec, key)) - return entry->value().get(); - return JSValue(); -} - -template<typename Entry, typename JSIterator> -inline bool MapDataImpl<Entry, JSIterator>::remove(ExecState* exec, KeyType key) -{ - int32_t location; - if (key.value.isString()) { - auto iter = m_stringKeyedTable.find(asString(key.value)->value(exec).impl()); - if (iter == m_stringKeyedTable.end()) - return false; - location = iter->value; - m_stringKeyedTable.remove(iter); - } else if (key.value.isSymbol()) { - auto iter = m_symbolKeyedTable.find(asSymbol(key.value)->privateName().uid()); - if (iter == m_symbolKeyedTable.end()) - return false; - location = iter->value; - m_symbolKeyedTable.remove(iter); - } else if (key.value.isCell()) { - auto iter = m_cellKeyedTable.find(key.value.asCell()); - if (iter == m_cellKeyedTable.end()) - return false; - location = iter->value; - m_cellKeyedTable.remove(iter); - } else { - auto iter = m_valueKeyedTable.find(JSValue::encode(key.value)); - if (iter == m_valueKeyedTable.end()) - return false; - location = iter->value; - m_valueKeyedTable.remove(iter); - } - m_entries[location].clear(); - m_deletedCount++; - return true; -} - -template<typename Entry, typename JSIterator> -inline void MapDataImpl<Entry, JSIterator>::replaceAndPackBackingStore(Entry* destination, int32_t newCapacity) -{ - ASSERT(shouldPack()); - int32_t newEnd = 0; - RELEASE_ASSERT(newCapacity > 0); - for (int32_t i = 0; i < m_size; i++) { - Entry& entry = m_entries[i]; - if (!entry.key()) { - m_iterators.forEach([newEnd](JSIterator* iterator, JSIterator*) { - iterator->iteratorData()->didRemoveEntry(newEnd); - }); - continue; - } - ASSERT(newEnd < newCapacity); - destination[newEnd] = entry; - - // We overwrite the old entry with a forwarding index for the new entry, - // so that we can fix up our hash tables below without doing additional - // hash lookups - entry.setKeyWithoutWriteBarrier(jsNumber(newEnd)); - newEnd++; - } - - // Fixup for the hashmaps - for (auto ptr = m_valueKeyedTable.begin(); ptr != m_valueKeyedTable.end(); ++ptr) - ptr->value = m_entries[ptr->value].key().get().asInt32(); - for (auto ptr = m_cellKeyedTable.begin(); ptr != m_cellKeyedTable.end(); ++ptr) - ptr->value = m_entries[ptr->value].key().get().asInt32(); - for (auto ptr = m_stringKeyedTable.begin(); ptr != m_stringKeyedTable.end(); ++ptr) - ptr->value = m_entries[ptr->value].key().get().asInt32(); - for (auto ptr = m_symbolKeyedTable.begin(); ptr != m_symbolKeyedTable.end(); ++ptr) - ptr->value = m_entries[ptr->value].key().get().asInt32(); - - ASSERT((m_size - newEnd) == m_deletedCount); - m_deletedCount = 0; - - m_capacity = newCapacity; - m_size = newEnd; - m_entries = destination; -} - -template<typename Entry, typename JSIterator> -inline void MapDataImpl<Entry, JSIterator>::replaceBackingStore(Entry* destination, int32_t newCapacity) -{ - ASSERT(!shouldPack()); - RELEASE_ASSERT(newCapacity > 0); - ASSERT(newCapacity >= m_capacity); - memcpy(destination, m_entries, sizeof(Entry) * m_size); - m_capacity = newCapacity; - m_entries = destination; -} - -template<typename Entry, typename JSIterator> -inline CheckedBoolean MapDataImpl<Entry, JSIterator>::ensureSpaceForAppend(ExecState* exec, JSCell* owner) -{ - if (m_capacity > m_size) - return true; - - size_t requiredSize = std::max(m_capacity + (m_capacity / 2) + 1, static_cast<int32_t>(minimumMapSize)); - void* newStorage = nullptr; - DeferGC defer(*exec->heap()); - if (!exec->heap()->tryAllocateStorage(owner, requiredSize * sizeof(Entry), &newStorage)) { - throwOutOfMemoryError(exec); - return false; - } - Entry* newEntries = static_cast<Entry*>(newStorage); - if (shouldPack()) - replaceAndPackBackingStore(newEntries, requiredSize); - else - replaceBackingStore(newEntries, requiredSize); - exec->heap()->writeBarrier(owner); - return true; -} - -template<typename Entry, typename JSIterator> -inline void MapDataImpl<Entry, JSIterator>::visitChildren(JSCell* owner, SlotVisitor& visitor) -{ - Entry* entries = m_entries; - if (!entries) - return; - if (m_deletedCount) { - for (int32_t i = 0; i < m_size; i++) { - if (!entries[i].key()) - continue; - entries[i].visitChildren(visitor); - } - } else { - // Guaranteed that all fields of Entry type is WriteBarrier<Unknown>. - visitor.appendValues(reinterpret_cast<WriteBarrier<Unknown>*>(&entries[0]), m_size * (sizeof(Entry) / sizeof(WriteBarrier<Unknown>))); - } - - visitor.copyLater(owner, MapBackingStoreCopyToken, entries, capacityInBytes()); -} - -template<typename Entry, typename JSIterator> -inline void MapDataImpl<Entry, JSIterator>::copyBackingStore(CopyVisitor& visitor, CopyToken token) -{ - if (token == MapBackingStoreCopyToken && visitor.checkIfShouldCopy(m_entries)) { - Entry* oldEntries = m_entries; - Entry* newEntries = static_cast<Entry*>(visitor.allocateNewSpace(capacityInBytes())); - if (shouldPack()) - replaceAndPackBackingStore(newEntries, m_capacity); - else - replaceBackingStore(newEntries, m_capacity); - visitor.didCopy(oldEntries, capacityInBytes()); - } -} - -template<typename Entry, typename JSIterator> -inline auto MapDataImpl<Entry, JSIterator>::createIteratorData(JSIterator* iterator) -> IteratorData -{ - m_iterators.set(iterator, iterator); - return IteratorData(this); -} - -} diff --git a/Source/JavaScriptCore/runtime/NullGetterFunction.cpp b/Source/JavaScriptCore/runtime/MapIteratorConstructor.cpp index 4243e5c41..fbc6c8b73 100644 --- a/Source/JavaScriptCore/runtime/NullGetterFunction.cpp +++ b/Source/JavaScriptCore/runtime/MapIteratorConstructor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Apple Inc. All rights reserved. + * 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 @@ -20,33 +20,26 @@ * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" -#include "NullGetterFunction.h" +#include "MapIteratorConstructor.h" #include "JSCJSValueInlines.h" -#include "JSCInlines.h" +#include "JSCellInlines.h" +#include "JSGlobalObject.h" +#include "JSMapIterator.h" +#include "MapIteratorPrototype.h" namespace JSC { -const ClassInfo NullGetterFunction::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(NullGetterFunction) }; +const ClassInfo MapIteratorConstructor::s_info = { "MapIterator Iterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(MapIteratorConstructor) }; -static EncodedJSValue JSC_HOST_CALL callReturnUndefined(ExecState*) +void MapIteratorConstructor::finishCreation(VM& vm, MapIteratorPrototype* prototype) { - return JSValue::encode(jsUndefined()); -} - -CallType NullGetterFunction::getCallData(JSCell*, CallData& callData) -{ - callData.native.function = callReturnUndefined; - return CallTypeHost; -} - -ConstructType NullGetterFunction::getConstructData(JSCell*, ConstructData&) -{ - return ConstructTypeNone; + Base::finishCreation(vm); + putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, DontEnum | DontDelete | ReadOnly); } } diff --git a/Source/JavaScriptCore/runtime/IteratorPrototype.h b/Source/JavaScriptCore/runtime/MapIteratorConstructor.h index c15971dab..45ba5b7ff 100644 --- a/Source/JavaScriptCore/runtime/IteratorPrototype.h +++ b/Source/JavaScriptCore/runtime/MapIteratorConstructor.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. + * 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 @@ -20,26 +20,27 @@ * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef IteratorPrototype_h -#define IteratorPrototype_h +#ifndef MapIteratorConstructor_h +#define MapIteratorConstructor_h #include "JSObject.h" namespace JSC { -class IteratorPrototype : public JSNonFinalObject { +class MapIteratorPrototype; + +class MapIteratorConstructor : public JSNonFinalObject { public: typedef JSNonFinalObject Base; - static const unsigned StructureFlags = Base::StructureFlags; - static IteratorPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) + static MapIteratorConstructor* create(VM& vm, Structure* structure, MapIteratorPrototype* prototype) { - IteratorPrototype* prototype = new (NotNull, allocateCell<IteratorPrototype>(vm.heap)) IteratorPrototype(vm, structure); - prototype->finishCreation(vm, globalObject); - return prototype; + MapIteratorConstructor* constructor = new (NotNull, allocateCell<MapIteratorConstructor>(vm.heap)) MapIteratorConstructor(vm, structure); + constructor->finishCreation(vm, prototype); + return constructor; } DECLARE_INFO; @@ -50,13 +51,13 @@ public: } private: - IteratorPrototype(VM& vm, Structure* structure) + MapIteratorConstructor(VM& vm, Structure* structure) : Base(vm, structure) { } - void finishCreation(VM&, JSGlobalObject*); + void finishCreation(VM&, MapIteratorPrototype*); }; } -#endif // !defined(IteratorPrototype_h) +#endif // !defined(MapConstructor_h) diff --git a/Source/JavaScriptCore/runtime/MapIteratorPrototype.cpp b/Source/JavaScriptCore/runtime/MapIteratorPrototype.cpp index 5e7ec33f9..048bf932c 100644 --- a/Source/JavaScriptCore/runtime/MapIteratorPrototype.cpp +++ b/Source/JavaScriptCore/runtime/MapIteratorPrototype.cpp @@ -26,25 +26,31 @@ #include "config.h" #include "MapIteratorPrototype.h" -#include "IteratorOperations.h" #include "JSCJSValueInlines.h" #include "JSCellInlines.h" #include "JSMapIterator.h" -#include "StructureInlines.h" namespace JSC { -const ClassInfo MapIteratorPrototype::s_info = { "Map Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(MapIteratorPrototype) }; +const ClassInfo MapIteratorPrototype::s_info = { "Map Iterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(MapIteratorPrototype) }; +static EncodedJSValue JSC_HOST_CALL MapIteratorPrototypeFuncIterator(ExecState*); static EncodedJSValue JSC_HOST_CALL MapIteratorPrototypeFuncNext(ExecState*); + void MapIteratorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) { Base::finishCreation(vm); ASSERT(inherits(info())); vm.prototypeMap.addPrototype(this); - JSC_NATIVE_FUNCTION(vm.propertyNames->next, MapIteratorPrototypeFuncNext, DontEnum, 0); + JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorPrivateName, MapIteratorPrototypeFuncIterator, DontEnum, 0); + JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorNextPrivateName, MapIteratorPrototypeFuncNext, DontEnum, 0); +} + +EncodedJSValue JSC_HOST_CALL MapIteratorPrototypeFuncIterator(CallFrame* callFrame) +{ + return JSValue::encode(callFrame->thisValue()); } EncodedJSValue JSC_HOST_CALL MapIteratorPrototypeFuncNext(CallFrame* callFrame) @@ -52,12 +58,12 @@ EncodedJSValue JSC_HOST_CALL MapIteratorPrototypeFuncNext(CallFrame* callFrame) JSMapIterator* iterator = jsDynamicCast<JSMapIterator*>(callFrame->thisValue()); if (!iterator) return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot call MapIterator.next() on a non-MapIterator object"))); - + JSValue result; if (iterator->next(callFrame, result)) - return JSValue::encode(createIteratorResultObject(callFrame, result, false)); + return JSValue::encode(result); iterator->finish(); - return JSValue::encode(createIteratorResultObject(callFrame, jsUndefined(), true)); + return JSValue::encode(callFrame->vm().iterationTerminator.get()); } diff --git a/Source/JavaScriptCore/runtime/MapPrototype.cpp b/Source/JavaScriptCore/runtime/MapPrototype.cpp index 96deae714..889599e0e 100644 --- a/Source/JavaScriptCore/runtime/MapPrototype.cpp +++ b/Source/JavaScriptCore/runtime/MapPrototype.cpp @@ -34,12 +34,11 @@ #include "JSFunctionInlines.h" #include "JSMap.h" #include "JSMapIterator.h" -#include "MapDataInlines.h" -#include "StructureInlines.h" +#include "MapData.h" namespace JSC { -const ClassInfo MapPrototype::s_info = { "Map", &Base::s_info, 0, CREATE_METHOD_TABLE(MapPrototype) }; +const ClassInfo MapPrototype::s_info = { "Map", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(MapPrototype) }; static EncodedJSValue JSC_HOST_CALL mapProtoFuncClear(ExecState*); static EncodedJSValue JSC_HOST_CALL mapProtoFuncDelete(ExecState*); @@ -67,52 +66,50 @@ void MapPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) JSC_NATIVE_FUNCTION(vm.propertyNames->set, mapProtoFuncSet, DontEnum, 2); JSC_NATIVE_FUNCTION(vm.propertyNames->keys, mapProtoFuncKeys, DontEnum, 0); JSC_NATIVE_FUNCTION(vm.propertyNames->values, mapProtoFuncValues, DontEnum, 0); + JSC_NATIVE_FUNCTION(vm.propertyNames->entries, mapProtoFuncEntries, DontEnum, 0); + JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorPrivateName, mapProtoFuncEntries, DontEnum, 0); - JSFunction* entries = JSFunction::create(vm, globalObject, 0, vm.propertyNames->entries.string(), mapProtoFuncEntries); - putDirectWithoutTransition(vm, vm.propertyNames->entries, entries, DontEnum); - putDirectWithoutTransition(vm, vm.propertyNames->iteratorSymbol, entries, DontEnum); - - GetterSetter* accessor = GetterSetter::create(vm, globalObject); + GetterSetter* accessor = GetterSetter::create(vm); JSFunction* function = JSFunction::create(vm, globalObject, 0, vm.propertyNames->size.string(), mapProtoFuncSize); - accessor->setGetter(vm, globalObject, function); + accessor->setGetter(vm, function); putDirectNonIndexAccessor(vm, vm.propertyNames->size, accessor, DontEnum | Accessor); } -ALWAYS_INLINE static JSMap* getMap(CallFrame* callFrame, JSValue thisValue) +ALWAYS_INLINE static MapData* getMapData(CallFrame* callFrame, JSValue thisValue) { if (!thisValue.isObject()) { throwVMError(callFrame, createNotAnObjectError(callFrame, thisValue)); - return nullptr; + return 0; } JSMap* map = jsDynamicCast<JSMap*>(thisValue); if (!map) { throwTypeError(callFrame, ASCIILiteral("Map operation called on non-Map object")); - return nullptr; + return 0; } - return map; + return map->mapData(); } EncodedJSValue JSC_HOST_CALL mapProtoFuncClear(CallFrame* callFrame) { - JSMap* map = getMap(callFrame, callFrame->thisValue()); - if (!map) + MapData* data = getMapData(callFrame, callFrame->thisValue()); + if (!data) return JSValue::encode(jsUndefined()); - map->clear(callFrame); + data->clear(); return JSValue::encode(jsUndefined()); } EncodedJSValue JSC_HOST_CALL mapProtoFuncDelete(CallFrame* callFrame) { - JSMap* map = getMap(callFrame, callFrame->thisValue()); - if (!map) + MapData* data = getMapData(callFrame, callFrame->thisValue()); + if (!data) return JSValue::encode(jsUndefined()); - return JSValue::encode(jsBoolean(map->remove(callFrame, callFrame->argument(0)))); + return JSValue::encode(jsBoolean(data->remove(callFrame, callFrame->argument(0)))); } EncodedJSValue JSC_HOST_CALL mapProtoFuncForEach(CallFrame* callFrame) { - JSMap* map = getMap(callFrame, callFrame->thisValue()); - if (!map) + MapData* data = getMapData(callFrame, callFrame->thisValue()); + if (!data) return JSValue::encode(jsUndefined()); JSValue callBack = callFrame->argument(0); CallData callData; @@ -121,64 +118,60 @@ EncodedJSValue JSC_HOST_CALL mapProtoFuncForEach(CallFrame* callFrame) return JSValue::encode(throwTypeError(callFrame, WTF::ASCIILiteral("Map.prototype.forEach called without callback"))); JSValue thisValue = callFrame->argument(1); VM* vm = &callFrame->vm(); - JSMapIterator* iterator = JSMapIterator::create(*vm, callFrame->callee()->globalObject()->mapIteratorStructure(), map, MapIterateKeyValue); - JSValue key, value; if (callType == CallTypeJS) { JSFunction* function = jsCast<JSFunction*>(callBack); - CachedCall cachedCall(callFrame, function, 3); - while (iterator->nextKeyValue(key, value) && !vm->exception()) { + CachedCall cachedCall(callFrame, function, 2); + for (auto ptr = data->begin(), end = data->end(); ptr != end && !vm->exception(); ++ptr) { cachedCall.setThis(thisValue); - cachedCall.setArgument(0, value); - cachedCall.setArgument(1, key); - cachedCall.setArgument(2, map); + cachedCall.setArgument(0, ptr.value()); + cachedCall.setArgument(1, ptr.key()); cachedCall.call(); } - iterator->finish(); } else { - while (iterator->nextKeyValue(key, value) && !vm->exception()) { + for (auto ptr = data->begin(), end = data->end(); ptr != end && !vm->exception(); ++ptr) { MarkedArgumentBuffer args; - args.append(value); - args.append(key); - args.append(map); + args.append(ptr.value()); + args.append(ptr.key()); JSC::call(callFrame, callBack, callType, callData, thisValue, args); } - iterator->finish(); } return JSValue::encode(jsUndefined()); } EncodedJSValue JSC_HOST_CALL mapProtoFuncGet(CallFrame* callFrame) { - JSMap* map = getMap(callFrame, callFrame->thisValue()); - if (!map) + MapData* data = getMapData(callFrame, callFrame->thisValue()); + if (!data) return JSValue::encode(jsUndefined()); - return JSValue::encode(map->get(callFrame, callFrame->argument(0))); + JSValue result = data->get(callFrame, callFrame->argument(0)); + if (!result) + result = jsUndefined(); + return JSValue::encode(result); } EncodedJSValue JSC_HOST_CALL mapProtoFuncHas(CallFrame* callFrame) { - JSMap* map = getMap(callFrame, callFrame->thisValue()); - if (!map) + MapData* data = getMapData(callFrame, callFrame->thisValue()); + if (!data) return JSValue::encode(jsUndefined()); - return JSValue::encode(jsBoolean(map->has(callFrame, callFrame->argument(0)))); + return JSValue::encode(jsBoolean(data->contains(callFrame, callFrame->argument(0)))); } EncodedJSValue JSC_HOST_CALL mapProtoFuncSet(CallFrame* callFrame) { - JSValue thisValue = callFrame->thisValue(); - JSMap* map = getMap(callFrame, thisValue); - if (!map) + MapData* data = getMapData(callFrame, callFrame->thisValue()); + if (!data) return JSValue::encode(jsUndefined()); - map->set(callFrame, callFrame->argument(0), callFrame->argument(1)); - return JSValue::encode(thisValue); + data->set(callFrame, callFrame->argument(0), callFrame->argument(1)); + return JSValue::encode(callFrame->thisValue()); } EncodedJSValue JSC_HOST_CALL mapProtoFuncSize(CallFrame* callFrame) { - JSMap* map = getMap(callFrame, callFrame->thisValue()); - if (!map) + MapData* data = getMapData(callFrame, callFrame->thisValue()); + if (!data) return JSValue::encode(jsUndefined()); - return JSValue::encode(jsNumber(map->size(callFrame))); + return JSValue::encode(jsNumber(data->size(callFrame))); } EncodedJSValue JSC_HOST_CALL mapProtoFuncValues(CallFrame* callFrame) @@ -193,7 +186,7 @@ EncodedJSValue JSC_HOST_CALL mapProtoFuncEntries(CallFrame* callFrame) { JSMap* thisObj = jsDynamicCast<JSMap*>(callFrame->thisValue()); if (!thisObj) - return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot create a Map entry iterator for a non-Map object."))); + return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot create a Map key iterator for a non-Map object."))); return JSValue::encode(JSMapIterator::create(callFrame->vm(), callFrame->callee()->globalObject()->mapIteratorStructure(), thisObj, MapIterateKeyValue)); } @@ -201,7 +194,7 @@ EncodedJSValue JSC_HOST_CALL mapProtoFuncKeys(CallFrame* callFrame) { JSMap* thisObj = jsDynamicCast<JSMap*>(callFrame->thisValue()); if (!thisObj) - return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot create a Map key iterator for a non-Map object."))); + return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot create a Map entry iterator for a non-Map object."))); return JSValue::encode(JSMapIterator::create(callFrame->vm(), callFrame->callee()->globalObject()->mapIteratorStructure(), thisObj, MapIterateKey)); } diff --git a/Source/JavaScriptCore/runtime/MathCommon.cpp b/Source/JavaScriptCore/runtime/MathCommon.cpp deleted file mode 100644 index d6882c03e..000000000 --- a/Source/JavaScriptCore/runtime/MathCommon.cpp +++ /dev/null @@ -1,443 +0,0 @@ -/* - * Copyright (C) 2015 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 "MathCommon.h" - -#include <cmath> -#include "PureNaN.h" - -namespace JSC { - -#if PLATFORM(IOS) && CPU(ARM_THUMB2) - -// The following code is taken from netlib.org: -// http://www.netlib.org/fdlibm/fdlibm.h -// http://www.netlib.org/fdlibm/e_pow.c -// http://www.netlib.org/fdlibm/s_scalbn.c -// -// And was originally distributed under the following license: - -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* - * ==================================================== - * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. - * - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -/* __ieee754_pow(x,y) return x**y - * - * n - * Method: Let x = 2 * (1+f) - * 1. Compute and return log2(x) in two pieces: - * log2(x) = w1 + w2, - * where w1 has 53-24 = 29 bit trailing zeros. - * 2. Perform y*log2(x) = n+y' by simulating muti-precision - * arithmetic, where |y'|<=0.5. - * 3. Return x**y = 2**n*exp(y'*log2) - * - * Special cases: - * 1. (anything) ** 0 is 1 - * 2. (anything) ** 1 is itself - * 3. (anything) ** NAN is NAN - * 4. NAN ** (anything except 0) is NAN - * 5. +-(|x| > 1) ** +INF is +INF - * 6. +-(|x| > 1) ** -INF is +0 - * 7. +-(|x| < 1) ** +INF is +0 - * 8. +-(|x| < 1) ** -INF is +INF - * 9. +-1 ** +-INF is NAN - * 10. +0 ** (+anything except 0, NAN) is +0 - * 11. -0 ** (+anything except 0, NAN, odd integer) is +0 - * 12. +0 ** (-anything except 0, NAN) is +INF - * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF - * 14. -0 ** (odd integer) = -( +0 ** (odd integer) ) - * 15. +INF ** (+anything except 0,NAN) is +INF - * 16. +INF ** (-anything except 0,NAN) is +0 - * 17. -INF ** (anything) = -0 ** (-anything) - * 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) - * 19. (-anything except 0 and inf) ** (non-integer) is NAN - * - * Accuracy: - * pow(x,y) returns x**y nearly rounded. In particular - * pow(integer,integer) - * always returns the correct integer provided it is - * representable. - * - * Constants : - * The hexadecimal values are the intended ones for the following - * constants. The decimal values may be used, provided that the - * compiler will convert from decimal to binary accurately enough - * to produce the hexadecimal values shown. - */ - -#define __HI(x) *(1+(int*)&x) -#define __LO(x) *(int*)&x - -static const double -bp[] = {1.0, 1.5,}, -dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */ -dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */ -zero = 0.0, -one = 1.0, -two = 2.0, -two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */ -huge = 1.0e300, -tiny = 1.0e-300, -/* for scalbn */ -two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */ -twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */ -/* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ -L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */ -L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */ -L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */ -L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */ -L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */ -L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */ -P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ -P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ -P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ -P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ -P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */ -lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ -lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */ -lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */ -ovt = 8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */ -cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */ -cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */ -cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/ -ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */ -ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/ -ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/ - -inline double fdlibmScalbn (double x, int n) -{ - int k,hx,lx; - hx = __HI(x); - lx = __LO(x); - k = (hx&0x7ff00000)>>20; /* extract exponent */ - if (k==0) { /* 0 or subnormal x */ - if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */ - x *= two54; - hx = __HI(x); - k = ((hx&0x7ff00000)>>20) - 54; - if (n< -50000) return tiny*x; /*underflow*/ - } - if (k==0x7ff) return x+x; /* NaN or Inf */ - k = k+n; - if (k > 0x7fe) return huge*copysign(huge,x); /* overflow */ - if (k > 0) /* normal result */ - {__HI(x) = (hx&0x800fffff)|(k<<20); return x;} - if (k <= -54) { - if (n > 50000) /* in case integer overflow in n+k */ - return huge*copysign(huge,x); /*overflow*/ - else return tiny*copysign(tiny,x); /*underflow*/ - } - k += 54; /* subnormal result */ - __HI(x) = (hx&0x800fffff)|(k<<20); - return x*twom54; -} - -static double fdlibmPow(double x, double y) -{ - double z,ax,z_h,z_l,p_h,p_l; - double y1,t1,t2,r,s,t,u,v,w; - int i0,i1,i,j,k,yisint,n; - int hx,hy,ix,iy; - unsigned lx,ly; - - i0 = ((*(int*)&one)>>29)^1; i1=1-i0; - hx = __HI(x); lx = __LO(x); - hy = __HI(y); ly = __LO(y); - ix = hx&0x7fffffff; iy = hy&0x7fffffff; - - /* y==zero: x**0 = 1 */ - if((iy|ly)==0) return one; - - /* +-NaN return x+y */ - if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) || - iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0))) - return x+y; - - /* determine if y is an odd int when x < 0 - * yisint = 0 ... y is not an integer - * yisint = 1 ... y is an odd int - * yisint = 2 ... y is an even int - */ - yisint = 0; - if(hx<0) { - if(iy>=0x43400000) yisint = 2; /* even integer y */ - else if(iy>=0x3ff00000) { - k = (iy>>20)-0x3ff; /* exponent */ - if(k>20) { - j = ly>>(52-k); - if(static_cast<unsigned>(j<<(52-k))==ly) yisint = 2-(j&1); - } else if(ly==0) { - j = iy>>(20-k); - if((j<<(20-k))==iy) yisint = 2-(j&1); - } - } - } - - /* special value of y */ - if(ly==0) { - if (iy==0x7ff00000) { /* y is +-inf */ - if(((ix-0x3ff00000)|lx)==0) - return y - y; /* inf**+-1 is NaN */ - else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */ - return (hy>=0)? y: zero; - else /* (|x|<1)**-,+inf = inf,0 */ - return (hy<0)?-y: zero; - } - if(iy==0x3ff00000) { /* y is +-1 */ - if(hy<0) return one/x; else return x; - } - if(hy==0x40000000) return x*x; /* y is 2 */ - if(hy==0x3fe00000) { /* y is 0.5 */ - if(hx>=0) /* x >= +0 */ - return sqrt(x); - } - } - - ax = fabs(x); - /* special value of x */ - if(lx==0) { - if(ix==0x7ff00000||ix==0||ix==0x3ff00000){ - z = ax; /*x is +-0,+-inf,+-1*/ - if(hy<0) z = one/z; /* z = (1/|x|) */ - if(hx<0) { - if(((ix-0x3ff00000)|yisint)==0) { - z = (z-z)/(z-z); /* (-1)**non-int is NaN */ - } else if(yisint==1) - z = -z; /* (x<0)**odd = -(|x|**odd) */ - } - return z; - } - } - - n = (hx>>31)+1; - - /* (x<0)**(non-int) is NaN */ - if((n|yisint)==0) return (x-x)/(x-x); - - s = one; /* s (sign of result -ve**odd) = -1 else = 1 */ - if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */ - - /* |y| is huge */ - if(iy>0x41e00000) { /* if |y| > 2**31 */ - if(iy>0x43f00000){ /* if |y| > 2**64, must o/uflow */ - if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny; - if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny; - } - /* over/underflow if x is not close to one */ - if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny; - if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny; - /* now |1-x| is tiny <= 2**-20, suffice to compute - log(x) by x-x^2/2+x^3/3-x^4/4 */ - t = ax-one; /* t has 20 trailing zeros */ - w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25)); - u = ivln2_h*t; /* ivln2_h has 21 sig. bits */ - v = t*ivln2_l-w*ivln2; - t1 = u+v; - __LO(t1) = 0; - t2 = v-(t1-u); - } else { - double ss,s2,s_h,s_l,t_h,t_l; - n = 0; - /* take care subnormal number */ - if(ix<0x00100000) - {ax *= two53; n -= 53; ix = __HI(ax); } - n += ((ix)>>20)-0x3ff; - j = ix&0x000fffff; - /* determine interval */ - ix = j|0x3ff00000; /* normalize ix */ - if(j<=0x3988E) k=0; /* |x|<sqrt(3/2) */ - else if(j<0xBB67A) k=1; /* |x|<sqrt(3) */ - else {k=0;n+=1;ix -= 0x00100000;} - __HI(ax) = ix; - - /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */ - u = ax-bp[k]; /* bp[0]=1.0, bp[1]=1.5 */ - v = one/(ax+bp[k]); - ss = u*v; - s_h = ss; - __LO(s_h) = 0; - /* t_h=ax+bp[k] High */ - t_h = zero; - __HI(t_h)=((ix>>1)|0x20000000)+0x00080000+(k<<18); - t_l = ax - (t_h-bp[k]); - s_l = v*((u-s_h*t_h)-s_h*t_l); - /* compute log(ax) */ - s2 = ss*ss; - r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); - r += s_l*(s_h+ss); - s2 = s_h*s_h; - t_h = 3.0+s2+r; - __LO(t_h) = 0; - t_l = r-((t_h-3.0)-s2); - /* u+v = ss*(1+...) */ - u = s_h*t_h; - v = s_l*t_h+t_l*ss; - /* 2/(3log2)*(ss+...) */ - p_h = u+v; - __LO(p_h) = 0; - p_l = v-(p_h-u); - z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ - z_l = cp_l*p_h+p_l*cp+dp_l[k]; - /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ - t = (double)n; - t1 = (((z_h+z_l)+dp_h[k])+t); - __LO(t1) = 0; - t2 = z_l-(((t1-t)-dp_h[k])-z_h); - } - - /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ - y1 = y; - __LO(y1) = 0; - p_l = (y-y1)*t1+y*t2; - p_h = y1*t1; - z = p_l+p_h; - j = __HI(z); - i = __LO(z); - if (j>=0x40900000) { /* z >= 1024 */ - if(((j-0x40900000)|i)!=0) /* if z > 1024 */ - return s*huge*huge; /* overflow */ - else { - if(p_l+ovt>z-p_h) return s*huge*huge; /* overflow */ - } - } else if((j&0x7fffffff)>=0x4090cc00 ) { /* z <= -1075 */ - if(((j-0xc090cc00)|i)!=0) /* z < -1075 */ - return s*tiny*tiny; /* underflow */ - else { - if(p_l<=z-p_h) return s*tiny*tiny; /* underflow */ - } - } - /* - * compute 2**(p_h+p_l) - */ - i = j&0x7fffffff; - k = (i>>20)-0x3ff; - n = 0; - if(i>0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */ - n = j+(0x00100000>>(k+1)); - k = ((n&0x7fffffff)>>20)-0x3ff; /* new k for n */ - t = zero; - __HI(t) = (n&~(0x000fffff>>k)); - n = ((n&0x000fffff)|0x00100000)>>(20-k); - if(j<0) n = -n; - p_h -= t; - } - t = p_l+p_h; - __LO(t) = 0; - u = t*lg2_h; - v = (p_l-(t-p_h))*lg2+t*lg2_l; - z = u+v; - w = v-(z-u); - t = z*z; - t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); - r = (z*t1)/(t1-two)-(w+z*w); - z = one-(r-z); - j = __HI(z); - j += (n<<20); - if((j>>20)<=0) z = fdlibmScalbn(z,n); /* subnormal output */ - else __HI(z) += (n<<20); - return s*z; -} - -static ALWAYS_INLINE bool isDenormal(double x) -{ - static const uint64_t signbit = 0x8000000000000000ULL; - static const uint64_t minNormal = 0x0001000000000000ULL; - return (bitwise_cast<uint64_t>(x) & ~signbit) - 1 < minNormal - 1; -} - -static ALWAYS_INLINE bool isEdgeCase(double x) -{ - static const uint64_t signbit = 0x8000000000000000ULL; - static const uint64_t infinity = 0x7fffffffffffffffULL; - return (bitwise_cast<uint64_t>(x) & ~signbit) - 1 >= infinity - 1; -} - -static ALWAYS_INLINE double mathPowInternal(double x, double y) -{ - if (!isDenormal(x) && !isDenormal(y)) { - double libmResult = std::pow(x, y); - if (libmResult || isEdgeCase(x) || isEdgeCase(y)) - return libmResult; - } - return fdlibmPow(x, y); -} - -#else - -ALWAYS_INLINE double mathPowInternal(double x, double y) -{ - return pow(x, y); -} - -#endif - -double JIT_OPERATION operationMathPow(double x, double y) -{ - if (std::isnan(y)) - return PNaN; - if (std::isinf(y) && fabs(x) == 1) - return PNaN; - int32_t yAsInt = y; - if (static_cast<double>(yAsInt) != y || yAsInt < 0) - return mathPowInternal(x, y); - - // If the exponent is a positive int32 integer, we do a fast exponentiation - double result = 1; - while (yAsInt) { - if (yAsInt & 1) - result *= x; - x *= x; - yAsInt >>= 1; - } - return result; -} - -extern "C" { -double jsRound(double value) -{ - double integer = ceil(value); - return integer - (integer - value > 0.5); -} -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/MathCommon.h b/Source/JavaScriptCore/runtime/MathCommon.h deleted file mode 100644 index 2f84ed727..000000000 --- a/Source/JavaScriptCore/runtime/MathCommon.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2015 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 MathCommon_h -#define MathCommon_h - -#include "JITOperations.h" - -#ifndef JIT_OPERATION -#define JIT_OPERATION -#endif - -namespace JSC { -double JIT_OPERATION operationMathPow(double x, double y) WTF_INTERNAL; - -inline int clz32(uint32_t number) -{ -#if COMPILER(GCC_OR_CLANG) - int zeroCount = 32; - if (number) - zeroCount = __builtin_clz(number); - return zeroCount; -#else - int zeroCount = 0; - for (int i = 31; i >= 0; i--) { - if (!(number >> i)) - zeroCount++; - else - break; - } - return zeroCount; -#endif -} - -extern "C" { -double JIT_OPERATION jsRound(double value) REFERENCED_FROM_ASM WTF_INTERNAL; -} - -} - -#endif // MathCommon_h diff --git a/Source/JavaScriptCore/runtime/MathObject.cpp b/Source/JavaScriptCore/runtime/MathObject.cpp index d23e46b6b..ca355ed44 100644 --- a/Source/JavaScriptCore/runtime/MathObject.cpp +++ b/Source/JavaScriptCore/runtime/MathObject.cpp @@ -22,59 +22,56 @@ #include "MathObject.h" #include "Lookup.h" -#include "MathCommon.h" #include "ObjectPrototype.h" -#include "JSCInlines.h" +#include "Operations.h" #include <time.h> #include <wtf/Assertions.h> #include <wtf/MathExtras.h> #include <wtf/RandomNumber.h> #include <wtf/RandomNumberSeed.h> -#include <wtf/Vector.h> namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(MathObject); -EncodedJSValue JSC_HOST_CALL mathProtoFuncACos(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncACosh(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncASin(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncASinh(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncATan(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncATanh(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncATan2(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncCbrt(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncClz32(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncCos(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncCosh(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncExp(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncExpm1(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncFround(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncHypot(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncLog(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncLog1p(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncLog10(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncLog2(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncMax(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncMin(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncRound(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncSign(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncSin(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncSinh(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncTan(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncTanh(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncTrunc(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncIMul(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncAbs(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncACos(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncACosh(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncASin(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncASinh(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncATan(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncATanh(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncATan2(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncCbrt(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncCos(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncCosh(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncExp(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncExpm1(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncFround(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncLog(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncLog1p(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncLog10(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncLog2(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncMax(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncMin(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncRound(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncSin(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncSinh(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncTan(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncTanh(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncTrunc(ExecState*); +static EncodedJSValue JSC_HOST_CALL mathProtoFuncIMul(ExecState*); } namespace JSC { -const ClassInfo MathObject::s_info = { "Math", &Base::s_info, 0, CREATE_METHOD_TABLE(MathObject) }; +const ClassInfo MathObject::s_info = { "Math", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(MathObject) }; MathObject::MathObject(VM& vm, Structure* structure) : JSNonFinalObject(vm, structure) @@ -86,50 +83,47 @@ void MathObject::finishCreation(VM& vm, JSGlobalObject* globalObject) Base::finishCreation(vm); ASSERT(inherits(info())); - putDirectWithoutTransition(vm, Identifier::fromString(&vm, "E"), jsNumber(exp(1.0)), DontDelete | DontEnum | ReadOnly); - putDirectWithoutTransition(vm, Identifier::fromString(&vm, "LN2"), jsNumber(log(2.0)), DontDelete | DontEnum | ReadOnly); - putDirectWithoutTransition(vm, Identifier::fromString(&vm, "LN10"), jsNumber(log(10.0)), DontDelete | DontEnum | ReadOnly); - putDirectWithoutTransition(vm, Identifier::fromString(&vm, "LOG2E"), jsNumber(1.0 / log(2.0)), DontDelete | DontEnum | ReadOnly); - putDirectWithoutTransition(vm, Identifier::fromString(&vm, "LOG10E"), jsNumber(0.4342944819032518), DontDelete | DontEnum | ReadOnly); - putDirectWithoutTransition(vm, Identifier::fromString(&vm, "PI"), jsNumber(piDouble), DontDelete | DontEnum | ReadOnly); - putDirectWithoutTransition(vm, Identifier::fromString(&vm, "SQRT1_2"), jsNumber(sqrt(0.5)), DontDelete | DontEnum | ReadOnly); - putDirectWithoutTransition(vm, Identifier::fromString(&vm, "SQRT2"), jsNumber(sqrt(2.0)), DontDelete | DontEnum | ReadOnly); - - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "abs"), 1, mathProtoFuncAbs, AbsIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "acos"), 1, mathProtoFuncACos, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "asin"), 1, mathProtoFuncASin, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "atan"), 1, mathProtoFuncATan, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "acosh"), 1, mathProtoFuncACosh, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "asinh"), 1, mathProtoFuncASinh, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "atanh"), 1, mathProtoFuncATanh, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "atan2"), 2, mathProtoFuncATan2, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "cbrt"), 1, mathProtoFuncCbrt, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "ceil"), 1, mathProtoFuncCeil, CeilIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "clz32"), 1, mathProtoFuncClz32, Clz32Intrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "cos"), 1, mathProtoFuncCos, CosIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "cosh"), 1, mathProtoFuncCosh, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "exp"), 1, mathProtoFuncExp, ExpIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "expm1"), 1, mathProtoFuncExpm1, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "floor"), 1, mathProtoFuncFloor, FloorIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "fround"), 1, mathProtoFuncFround, FRoundIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "hypot"), 2, mathProtoFuncHypot, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "log"), 1, mathProtoFuncLog, LogIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "log10"), 1, mathProtoFuncLog10, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "log1p"), 1, mathProtoFuncLog1p, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "log2"), 1, mathProtoFuncLog2, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "max"), 2, mathProtoFuncMax, MaxIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "min"), 2, mathProtoFuncMin, MinIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "pow"), 2, mathProtoFuncPow, PowIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "random"), 0, mathProtoFuncRandom, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "round"), 1, mathProtoFuncRound, RoundIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "sign"), 1, mathProtoFuncSign, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "sin"), 1, mathProtoFuncSin, SinIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "sinh"), 1, mathProtoFuncSinh, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "sqrt"), 1, mathProtoFuncSqrt, SqrtIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "tan"), 1, mathProtoFuncTan, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "tanh"), 1, mathProtoFuncTanh, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "trunc"), 1, mathProtoFuncTrunc, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "imul"), 2, mathProtoFuncIMul, IMulIntrinsic, DontEnum | Function); + putDirectWithoutTransition(vm, Identifier(&vm, "E"), jsNumber(exp(1.0)), DontDelete | DontEnum | ReadOnly); + putDirectWithoutTransition(vm, Identifier(&vm, "LN2"), jsNumber(log(2.0)), DontDelete | DontEnum | ReadOnly); + putDirectWithoutTransition(vm, Identifier(&vm, "LN10"), jsNumber(log(10.0)), DontDelete | DontEnum | ReadOnly); + putDirectWithoutTransition(vm, Identifier(&vm, "LOG2E"), jsNumber(1.0 / log(2.0)), DontDelete | DontEnum | ReadOnly); + putDirectWithoutTransition(vm, Identifier(&vm, "LOG10E"), jsNumber(0.4342944819032518), DontDelete | DontEnum | ReadOnly); + putDirectWithoutTransition(vm, Identifier(&vm, "PI"), jsNumber(piDouble), DontDelete | DontEnum | ReadOnly); + putDirectWithoutTransition(vm, Identifier(&vm, "SQRT1_2"), jsNumber(sqrt(0.5)), DontDelete | DontEnum | ReadOnly); + putDirectWithoutTransition(vm, Identifier(&vm, "SQRT2"), jsNumber(sqrt(2.0)), DontDelete | DontEnum | ReadOnly); + + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "abs"), 1, mathProtoFuncAbs, AbsIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "acos"), 1, mathProtoFuncACos, NoIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "asin"), 1, mathProtoFuncASin, NoIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "atan"), 1, mathProtoFuncATan, NoIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "acosh"), 1, mathProtoFuncACosh, NoIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "asinh"), 1, mathProtoFuncASinh, NoIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "atanh"), 1, mathProtoFuncATanh, NoIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "atan2"), 2, mathProtoFuncATan2, NoIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "cbrt"), 1, mathProtoFuncCbrt, NoIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "ceil"), 1, mathProtoFuncCeil, CeilIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "cos"), 1, mathProtoFuncCos, CosIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "cosh"), 1, mathProtoFuncCosh, NoIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "exp"), 1, mathProtoFuncExp, ExpIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "expm1"), 1, mathProtoFuncExpm1, NoIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "floor"), 1, mathProtoFuncFloor, FloorIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "fround"), 1, mathProtoFuncFround, NoIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "log"), 1, mathProtoFuncLog, LogIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "log10"), 1, mathProtoFuncLog10, NoIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "log1p"), 1, mathProtoFuncLog1p, NoIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "log2"), 1, mathProtoFuncLog2, NoIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "max"), 2, mathProtoFuncMax, MaxIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "min"), 2, mathProtoFuncMin, MinIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "pow"), 2, mathProtoFuncPow, PowIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "random"), 0, mathProtoFuncRandom, NoIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "round"), 1, mathProtoFuncRound, RoundIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "sin"), 1, mathProtoFuncSin, SinIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "sinh"), 1, mathProtoFuncSinh, NoIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "sqrt"), 1, mathProtoFuncSqrt, SqrtIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "tan"), 1, mathProtoFuncTan, NoIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "tanh"), 1, mathProtoFuncTanh, NoIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "trunc"), 1, mathProtoFuncTrunc, NoIntrinsic, DontEnum | Function); + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "imul"), 1, mathProtoFuncIMul, IMulIntrinsic, DontEnum | Function); } // ------------------------------ Functions -------------------------------- @@ -166,14 +160,6 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState* exec) return JSValue::encode(jsNumber(ceil(exec->argument(0).toNumber(exec)))); } -EncodedJSValue JSC_HOST_CALL mathProtoFuncClz32(ExecState* exec) -{ - uint32_t value = exec->argument(0).toUInt32(exec); - if (exec->hadException()) - return JSValue::encode(jsNull()); - return JSValue::encode(JSValue(clz32(value))); -} - EncodedJSValue JSC_HOST_CALL mathProtoFuncCos(ExecState* exec) { return JSValue::encode(jsDoubleNumber(cos(exec->argument(0).toNumber(exec)))); @@ -189,35 +175,6 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState* exec) return JSValue::encode(jsNumber(floor(exec->argument(0).toNumber(exec)))); } -EncodedJSValue JSC_HOST_CALL mathProtoFuncHypot(ExecState* exec) -{ - unsigned argsCount = exec->argumentCount(); - double max = 0; - Vector<double, 8> args; - args.reserveInitialCapacity(argsCount); - for (unsigned i = 0; i < argsCount; ++i) { - args.uncheckedAppend(exec->uncheckedArgument(i).toNumber(exec)); - if (exec->hadException()) - return JSValue::encode(jsNull()); - if (std::isinf(args[i])) - return JSValue::encode(jsDoubleNumber(+std::numeric_limits<double>::infinity())); - max = std::max(fabs(args[i]), max); - } - if (!max) - max = 1; - // Kahan summation algorithm significantly reduces the numerical error in the total obtained. - double sum = 0; - double compensation = 0; - for (double argument : args) { - double scaledArgument = argument / max; - double summand = scaledArgument * scaledArgument - compensation; - double preliminary = sum + summand; - compensation = (preliminary - sum) - summand; - sum = preliminary; - } - return JSValue::encode(jsDoubleNumber(sqrt(sum) * max)); -} - EncodedJSValue JSC_HOST_CALL mathProtoFuncLog(ExecState* exec) { return JSValue::encode(jsDoubleNumber(log(exec->argument(0).toNumber(exec)))); @@ -230,8 +187,10 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncMax(ExecState* exec) for (unsigned k = 0; k < argsCount; ++k) { double val = exec->uncheckedArgument(k).toNumber(exec); if (std::isnan(val)) { - result = PNaN; - } else if (val > result || (!val && !result && !std::signbit(val))) + result = QNaN; + break; + } + if (val > result || (!val && !result && !std::signbit(val))) result = val; } return JSValue::encode(jsNumber(result)); @@ -244,13 +203,52 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncMin(ExecState* exec) for (unsigned k = 0; k < argsCount; ++k) { double val = exec->uncheckedArgument(k).toNumber(exec); if (std::isnan(val)) { - result = PNaN; - } else if (val < result || (!val && !result && std::signbit(val))) + result = QNaN; + break; + } + if (val < result || (!val && !result && std::signbit(val))) result = val; } return JSValue::encode(jsNumber(result)); } +#if PLATFORM(IOS) && CPU(ARM_THUMB2) + +static double fdlibmPow(double x, double y); + +static ALWAYS_INLINE bool isDenormal(double x) +{ + static const uint64_t signbit = 0x8000000000000000ULL; + static const uint64_t minNormal = 0x0001000000000000ULL; + return (bitwise_cast<uint64_t>(x) & ~signbit) - 1 < minNormal - 1; +} + +static ALWAYS_INLINE bool isEdgeCase(double x) +{ + static const uint64_t signbit = 0x8000000000000000ULL; + static const uint64_t infinity = 0x7fffffffffffffffULL; + return (bitwise_cast<uint64_t>(x) & ~signbit) - 1 >= infinity - 1; +} + +static ALWAYS_INLINE double mathPow(double x, double y) +{ + if (!isDenormal(x) && !isDenormal(y)) { + double libmResult = pow(x,y); + if (libmResult || isEdgeCase(x) || isEdgeCase(y)) + return libmResult; + } + return fdlibmPow(x,y); +} + +#else + +ALWAYS_INLINE double mathPow(double x, double y) +{ + return pow(x, y); +} + +#endif + EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState* exec) { // ECMA 15.8.2.1.13 @@ -258,7 +256,11 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState* exec) double arg = exec->argument(0).toNumber(exec); double arg2 = exec->argument(1).toNumber(exec); - return JSValue::encode(JSValue(operationMathPow(arg, arg2))); + if (std::isnan(arg2)) + return JSValue::encode(jsNaN()); + if (std::isinf(arg2) && fabs(arg) == 1) + return JSValue::encode(jsNaN()); + return JSValue::encode(jsNumber(mathPow(arg, arg2))); } EncodedJSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState* exec) @@ -268,17 +270,9 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState* exec) EncodedJSValue JSC_HOST_CALL mathProtoFuncRound(ExecState* exec) { - return JSValue::encode(jsNumber(jsRound(exec->argument(0).toNumber(exec)))); -} - -EncodedJSValue JSC_HOST_CALL mathProtoFuncSign(ExecState* exec) -{ double arg = exec->argument(0).toNumber(exec); - if (std::isnan(arg)) - return JSValue::encode(jsNaN()); - if (!arg) - return JSValue::encode(std::signbit(arg) ? jsNumber(-0.0) : jsNumber(0)); - return JSValue::encode(jsNumber(std::signbit(arg) ? -1 : 1)); + double integer = ceil(arg); + return JSValue::encode(jsNumber(integer - (integer - arg > 0.5))); } EncodedJSValue JSC_HOST_CALL mathProtoFuncSin(ExecState* exec) @@ -373,4 +367,354 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncTrunc(ExecState*exec) return JSValue::encode(jsNumber(exec->argument(0).toIntegerPreserveNaN(exec))); } + +#if PLATFORM(IOS) && CPU(ARM_THUMB2) + +// The following code is taken from netlib.org: +// http://www.netlib.org/fdlibm/fdlibm.h +// http://www.netlib.org/fdlibm/e_pow.c +// http://www.netlib.org/fdlibm/s_scalbn.c +// +// And was originally distributed under the following license: + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* __ieee754_pow(x,y) return x**y + * + * n + * Method: Let x = 2 * (1+f) + * 1. Compute and return log2(x) in two pieces: + * log2(x) = w1 + w2, + * where w1 has 53-24 = 29 bit trailing zeros. + * 2. Perform y*log2(x) = n+y' by simulating muti-precision + * arithmetic, where |y'|<=0.5. + * 3. Return x**y = 2**n*exp(y'*log2) + * + * Special cases: + * 1. (anything) ** 0 is 1 + * 2. (anything) ** 1 is itself + * 3. (anything) ** NAN is NAN + * 4. NAN ** (anything except 0) is NAN + * 5. +-(|x| > 1) ** +INF is +INF + * 6. +-(|x| > 1) ** -INF is +0 + * 7. +-(|x| < 1) ** +INF is +0 + * 8. +-(|x| < 1) ** -INF is +INF + * 9. +-1 ** +-INF is NAN + * 10. +0 ** (+anything except 0, NAN) is +0 + * 11. -0 ** (+anything except 0, NAN, odd integer) is +0 + * 12. +0 ** (-anything except 0, NAN) is +INF + * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF + * 14. -0 ** (odd integer) = -( +0 ** (odd integer) ) + * 15. +INF ** (+anything except 0,NAN) is +INF + * 16. +INF ** (-anything except 0,NAN) is +0 + * 17. -INF ** (anything) = -0 ** (-anything) + * 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) + * 19. (-anything except 0 and inf) ** (non-integer) is NAN + * + * Accuracy: + * pow(x,y) returns x**y nearly rounded. In particular + * pow(integer,integer) + * always returns the correct integer provided it is + * representable. + * + * Constants : + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#define __HI(x) *(1+(int*)&x) +#define __LO(x) *(int*)&x + +static const double +bp[] = {1.0, 1.5,}, +dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */ +dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */ +zero = 0.0, +one = 1.0, +two = 2.0, +two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */ +huge = 1.0e300, +tiny = 1.0e-300, + /* for scalbn */ +two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */ +twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */ + /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ +L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */ +L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */ +L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */ +L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */ +L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */ +L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */ +P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ +P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ +P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ +P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ +P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */ +lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ +lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */ +lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */ +ovt = 8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */ +cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */ +cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */ +cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/ +ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */ +ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/ +ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/ + +inline double fdlibmScalbn (double x, int n) +{ + int k,hx,lx; + hx = __HI(x); + lx = __LO(x); + k = (hx&0x7ff00000)>>20; /* extract exponent */ + if (k==0) { /* 0 or subnormal x */ + if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */ + x *= two54; + hx = __HI(x); + k = ((hx&0x7ff00000)>>20) - 54; + if (n< -50000) return tiny*x; /*underflow*/ + } + if (k==0x7ff) return x+x; /* NaN or Inf */ + k = k+n; + if (k > 0x7fe) return huge*copysign(huge,x); /* overflow */ + if (k > 0) /* normal result */ + {__HI(x) = (hx&0x800fffff)|(k<<20); return x;} + if (k <= -54) { + if (n > 50000) /* in case integer overflow in n+k */ + return huge*copysign(huge,x); /*overflow*/ + else return tiny*copysign(tiny,x); /*underflow*/ + } + k += 54; /* subnormal result */ + __HI(x) = (hx&0x800fffff)|(k<<20); + return x*twom54; +} + +double fdlibmPow(double x, double y) +{ + double z,ax,z_h,z_l,p_h,p_l; + double y1,t1,t2,r,s,t,u,v,w; + int i0,i1,i,j,k,yisint,n; + int hx,hy,ix,iy; + unsigned lx,ly; + + i0 = ((*(int*)&one)>>29)^1; i1=1-i0; + hx = __HI(x); lx = __LO(x); + hy = __HI(y); ly = __LO(y); + ix = hx&0x7fffffff; iy = hy&0x7fffffff; + + /* y==zero: x**0 = 1 */ + if((iy|ly)==0) return one; + + /* +-NaN return x+y */ + if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) || + iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0))) + return x+y; + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if(hx<0) { + if(iy>=0x43400000) yisint = 2; /* even integer y */ + else if(iy>=0x3ff00000) { + k = (iy>>20)-0x3ff; /* exponent */ + if(k>20) { + j = ly>>(52-k); + if(static_cast<unsigned>(j<<(52-k))==ly) yisint = 2-(j&1); + } else if(ly==0) { + j = iy>>(20-k); + if((j<<(20-k))==iy) yisint = 2-(j&1); + } + } + } + + /* special value of y */ + if(ly==0) { + if (iy==0x7ff00000) { /* y is +-inf */ + if(((ix-0x3ff00000)|lx)==0) + return y - y; /* inf**+-1 is NaN */ + else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */ + return (hy>=0)? y: zero; + else /* (|x|<1)**-,+inf = inf,0 */ + return (hy<0)?-y: zero; + } + if(iy==0x3ff00000) { /* y is +-1 */ + if(hy<0) return one/x; else return x; + } + if(hy==0x40000000) return x*x; /* y is 2 */ + if(hy==0x3fe00000) { /* y is 0.5 */ + if(hx>=0) /* x >= +0 */ + return sqrt(x); + } + } + + ax = fabs(x); + /* special value of x */ + if(lx==0) { + if(ix==0x7ff00000||ix==0||ix==0x3ff00000){ + z = ax; /*x is +-0,+-inf,+-1*/ + if(hy<0) z = one/z; /* z = (1/|x|) */ + if(hx<0) { + if(((ix-0x3ff00000)|yisint)==0) { + z = (z-z)/(z-z); /* (-1)**non-int is NaN */ + } else if(yisint==1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + } + + n = (hx>>31)+1; + + /* (x<0)**(non-int) is NaN */ + if((n|yisint)==0) return (x-x)/(x-x); + + s = one; /* s (sign of result -ve**odd) = -1 else = 1 */ + if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */ + + /* |y| is huge */ + if(iy>0x41e00000) { /* if |y| > 2**31 */ + if(iy>0x43f00000){ /* if |y| > 2**64, must o/uflow */ + if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny; + if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny; + } + /* over/underflow if x is not close to one */ + if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny; + if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny; + /* now |1-x| is tiny <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax-one; /* t has 20 trailing zeros */ + w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25)); + u = ivln2_h*t; /* ivln2_h has 21 sig. bits */ + v = t*ivln2_l-w*ivln2; + t1 = u+v; + __LO(t1) = 0; + t2 = v-(t1-u); + } else { + double ss,s2,s_h,s_l,t_h,t_l; + n = 0; + /* take care subnormal number */ + if(ix<0x00100000) + {ax *= two53; n -= 53; ix = __HI(ax); } + n += ((ix)>>20)-0x3ff; + j = ix&0x000fffff; + /* determine interval */ + ix = j|0x3ff00000; /* normalize ix */ + if(j<=0x3988E) k=0; /* |x|<sqrt(3/2) */ + else if(j<0xBB67A) k=1; /* |x|<sqrt(3) */ + else {k=0;n+=1;ix -= 0x00100000;} + __HI(ax) = ix; + + /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */ + u = ax-bp[k]; /* bp[0]=1.0, bp[1]=1.5 */ + v = one/(ax+bp[k]); + ss = u*v; + s_h = ss; + __LO(s_h) = 0; + /* t_h=ax+bp[k] High */ + t_h = zero; + __HI(t_h)=((ix>>1)|0x20000000)+0x00080000+(k<<18); + t_l = ax - (t_h-bp[k]); + s_l = v*((u-s_h*t_h)-s_h*t_l); + /* compute log(ax) */ + s2 = ss*ss; + r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); + r += s_l*(s_h+ss); + s2 = s_h*s_h; + t_h = 3.0+s2+r; + __LO(t_h) = 0; + t_l = r-((t_h-3.0)-s2); + /* u+v = ss*(1+...) */ + u = s_h*t_h; + v = s_l*t_h+t_l*ss; + /* 2/(3log2)*(ss+...) */ + p_h = u+v; + __LO(p_h) = 0; + p_l = v-(p_h-u); + z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = cp_l*p_h+p_l*cp+dp_l[k]; + /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = (double)n; + t1 = (((z_h+z_l)+dp_h[k])+t); + __LO(t1) = 0; + t2 = z_l-(((t1-t)-dp_h[k])-z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + y1 = y; + __LO(y1) = 0; + p_l = (y-y1)*t1+y*t2; + p_h = y1*t1; + z = p_l+p_h; + j = __HI(z); + i = __LO(z); + if (j>=0x40900000) { /* z >= 1024 */ + if(((j-0x40900000)|i)!=0) /* if z > 1024 */ + return s*huge*huge; /* overflow */ + else { + if(p_l+ovt>z-p_h) return s*huge*huge; /* overflow */ + } + } else if((j&0x7fffffff)>=0x4090cc00 ) { /* z <= -1075 */ + if(((j-0xc090cc00)|i)!=0) /* z < -1075 */ + return s*tiny*tiny; /* underflow */ + else { + if(p_l<=z-p_h) return s*tiny*tiny; /* underflow */ + } + } + /* + * compute 2**(p_h+p_l) + */ + i = j&0x7fffffff; + k = (i>>20)-0x3ff; + n = 0; + if(i>0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */ + n = j+(0x00100000>>(k+1)); + k = ((n&0x7fffffff)>>20)-0x3ff; /* new k for n */ + t = zero; + __HI(t) = (n&~(0x000fffff>>k)); + n = ((n&0x000fffff)|0x00100000)>>(20-k); + if(j<0) n = -n; + p_h -= t; + } + t = p_l+p_h; + __LO(t) = 0; + u = t*lg2_h; + v = (p_l-(t-p_h))*lg2+t*lg2_l; + z = u+v; + w = v-(z-u); + t = z*z; + t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + r = (z*t1)/(t1-two)-(w+z*w); + z = one-(r-z); + j = __HI(z); + j += (n<<20); + if((j>>20)<=0) z = fdlibmScalbn(z,n); /* subnormal output */ + else __HI(z) += (n<<20); + return s*z; +} + +#endif + } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/MathObject.h b/Source/JavaScriptCore/runtime/MathObject.h index 9d1c181c0..4b2a5bbec 100644 --- a/Source/JavaScriptCore/runtime/MathObject.h +++ b/Source/JavaScriptCore/runtime/MathObject.h @@ -25,34 +25,31 @@ namespace JSC { -class MathObject : public JSNonFinalObject { -private: - MathObject(VM&, Structure*); - -public: - typedef JSNonFinalObject Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; - - static MathObject* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) - { - MathObject* object = new (NotNull, allocateCell<MathObject>(vm.heap)) MathObject(vm, structure); - object->finishCreation(vm, globalObject); - return object; - } - - DECLARE_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } - -protected: - void finishCreation(VM&, JSGlobalObject*); -}; - -EncodedJSValue JSC_HOST_CALL mathProtoFuncAbs(ExecState*); -EncodedJSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState*); + class MathObject : public JSNonFinalObject { + private: + MathObject(VM&, Structure*); + + public: + typedef JSNonFinalObject Base; + + static MathObject* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) + { + MathObject* object = new (NotNull, allocateCell<MathObject>(vm.heap)) MathObject(vm, structure); + object->finishCreation(vm, globalObject); + return object; + } + + DECLARE_INFO; + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } + + protected: + void finishCreation(VM&, JSGlobalObject*); + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSObject::StructureFlags; + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/SymbolObject.cpp b/Source/JavaScriptCore/runtime/NameConstructor.cpp index 9ab7a7ecb..77d7c920e 100644 --- a/Source/JavaScriptCore/runtime/SymbolObject.cpp +++ b/Source/JavaScriptCore/runtime/NameConstructor.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2012 Apple Inc. All rights reserved. - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,32 +24,46 @@ */ #include "config.h" -#include "SymbolObject.h" +#include "NameConstructor.h" -#include "JSCInlines.h" +#include "JSGlobalObject.h" +#include "NamePrototype.h" +#include "Operations.h" namespace JSC { -STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(SymbolObject); +STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(NameConstructor); -const ClassInfo SymbolObject::s_info = { "Symbol", &JSWrapperObject::s_info, nullptr, CREATE_METHOD_TABLE(SymbolObject) }; +const ClassInfo NameConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(NameConstructor) }; -SymbolObject::SymbolObject(VM& vm, Structure* structure) - : JSWrapperObject(vm, structure) +NameConstructor::NameConstructor(VM& vm, Structure* structure) + : InternalFunction(vm, structure) { } -void SymbolObject::finishCreation(VM& vm, Symbol* symbol) +void NameConstructor::finishCreation(VM& vm, NamePrototype* prototype) { - Base::finishCreation(vm); - ASSERT(inherits(info())); - setInternalValue(vm, symbol); + Base::finishCreation(vm, prototype->classInfo()->className); + putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, DontEnum | DontDelete | ReadOnly); + putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), DontDelete | ReadOnly | DontEnum); } -JSValue SymbolObject::defaultValue(const JSObject* object, ExecState*, PreferredPrimitiveType) +static EncodedJSValue JSC_HOST_CALL constructPrivateName(ExecState* exec) { - const SymbolObject* symbolObject = jsCast<const SymbolObject*>(object); - return symbolObject->internalValue(); + JSValue publicName = exec->argument(0); + return JSValue::encode(NameInstance::create(exec->vm(), exec->lexicalGlobalObject()->privateNameStructure(), publicName.toString(exec))); +} + +ConstructType NameConstructor::getConstructData(JSCell*, ConstructData& constructData) +{ + constructData.native.function = constructPrivateName; + return ConstructTypeHost; +} + +CallType NameConstructor::getCallData(JSCell*, CallData& callData) +{ + callData.native.function = constructPrivateName; + return CallTypeHost; } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/SymbolConstructor.h b/Source/JavaScriptCore/runtime/NameConstructor.h index 344a978ab..8e20f28fc 100644 --- a/Source/JavaScriptCore/runtime/SymbolConstructor.h +++ b/Source/JavaScriptCore/runtime/NameConstructor.h @@ -1,6 +1,5 @@ /* * Copyright (C) 2012 Apple Inc. All rights reserved. - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,45 +23,43 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SymbolConstructor_h -#define SymbolConstructor_h +#ifndef NameConstructor_h +#define NameConstructor_h #include "InternalFunction.h" -#include "Symbol.h" +#include "NameInstance.h" namespace JSC { -class SymbolPrototype; +class NamePrototype; -class SymbolConstructor : public InternalFunction { +class NameConstructor : public InternalFunction { public: typedef InternalFunction Base; - static const unsigned StructureFlags = OverridesGetOwnPropertySlot | Base::StructureFlags; - static SymbolConstructor* create(VM& vm, Structure* structure, SymbolPrototype* prototype) + static NameConstructor* create(VM& vm, Structure* structure, NamePrototype* prototype) { - SymbolConstructor* constructor = new (NotNull, allocateCell<SymbolConstructor>(vm.heap)) SymbolConstructor(vm, structure); + NameConstructor* constructor = new (NotNull, allocateCell<NameConstructor>(vm.heap)) NameConstructor(vm, structure); constructor->finishCreation(vm, prototype); return constructor; } DECLARE_INFO; - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } protected: - void finishCreation(VM&, SymbolPrototype*); - + void finishCreation(VM&, NamePrototype*); + private: - SymbolConstructor(VM&, Structure*); + NameConstructor(VM&, Structure*); static ConstructType getConstructData(JSCell*, ConstructData&); static CallType getCallData(JSCell*, CallData&); - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); }; } // namespace JSC -#endif // SymbolConstructor_h +#endif // NameConstructor_h diff --git a/Source/JavaScriptCore/runtime/MemoryStatistics.cpp b/Source/JavaScriptCore/runtime/NameInstance.cpp index a2eaf349c..dbbf0e2f6 100644 --- a/Source/JavaScriptCore/runtime/MemoryStatistics.cpp +++ b/Source/JavaScriptCore/runtime/NameInstance.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. + * 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 @@ -24,27 +24,24 @@ */ #include "config.h" -#include "MemoryStatistics.h" +#include "NameInstance.h" -#include "ExecutableAllocator.h" -#include "VM.h" -#include "JSStack.h" +#include "JSScope.h" +#include "Operations.h" namespace JSC { -GlobalMemoryStatistics globalMemoryStatistics() -{ - GlobalMemoryStatistics stats; +const ClassInfo NameInstance::s_info = { "Name", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(NameInstance) }; - stats.stackBytes = JSStack::committedByteCount(); -#if ENABLE(EXECUTABLE_ALLOCATOR_FIXED) || (PLATFORM(EFL) && ENABLE(JIT)) - stats.JITBytes = ExecutableAllocator::committedByteCount(); -#else - stats.JITBytes = 0; -#endif - return stats; +NameInstance::NameInstance(VM& vm, Structure* structure, JSString* nameString) + : Base(vm, structure) +{ + m_nameString.set(vm, this, nameString); } +void NameInstance::destroy(JSCell* cell) +{ + static_cast<NameInstance*>(cell)->NameInstance::~NameInstance(); } - +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSTemplateRegistryKey.h b/Source/JavaScriptCore/runtime/NameInstance.h index fc6e39286..c3be29a2d 100644 --- a/Source/JavaScriptCore/runtime/JSTemplateRegistryKey.h +++ b/Source/JavaScriptCore/runtime/NameInstance.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. + * 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 @@ -23,39 +23,55 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSTemplateRegistryKey_h -#define JSTemplateRegistryKey_h +#ifndef NameInstance_h +#define NameInstance_h #include "JSDestructibleObject.h" -#include "Structure.h" -#include "TemplateRegistryKey.h" +#include "PrivateName.h" namespace JSC { -class JSTemplateRegistryKey final : public JSDestructibleObject { +class NameInstance : public JSDestructibleObject { public: typedef JSDestructibleObject Base; - static JSTemplateRegistryKey* create(VM&, const TemplateRegistryKey&); + DECLARE_INFO; static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + return Structure::create(vm, globalObject, prototype, TypeInfo(NameInstanceType, StructureFlags), info()); } - DECLARE_INFO; + static NameInstance* create(VM& vm, Structure* structure, JSString* nameString) + { + NameInstance* name = new (NotNull, allocateCell<NameInstance>(vm.heap)) NameInstance(vm, structure, nameString); + name->finishCreation(vm); + return name; + } - const TemplateRegistryKey& templateRegistryKey() const { return m_templateRegistryKey; } + const PrivateName& privateName() { return m_privateName; } + JSString* nameString() { return m_nameString.get(); } protected: static void destroy(JSCell*); -private: - JSTemplateRegistryKey(VM&, const TemplateRegistryKey&); + NameInstance(VM&, Structure*, JSString*); - TemplateRegistryKey m_templateRegistryKey; + void finishCreation(VM& vm) + { + Base::finishCreation(vm); + ASSERT(inherits(info())); + } + + PrivateName m_privateName; + WriteBarrier<JSString> m_nameString; }; +inline bool isName(JSValue v) +{ + return v.isCell() && v.asCell()->structure()->typeInfo().isName(); +} + } // namespace JSC -#endif // JSTemplateRegistryKey_h +#endif // NameInstance_h diff --git a/Source/JavaScriptCore/runtime/NamePrototype.cpp b/Source/JavaScriptCore/runtime/NamePrototype.cpp new file mode 100644 index 000000000..ccbb41bc5 --- /dev/null +++ b/Source/JavaScriptCore/runtime/NamePrototype.cpp @@ -0,0 +1,81 @@ +/* + * 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. 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 "NamePrototype.h" + +#include "Error.h" +#include "Operations.h" + +namespace JSC { + +static EncodedJSValue JSC_HOST_CALL privateNameProtoFuncToString(ExecState*); + +} + +#include "NamePrototype.lut.h" + +namespace JSC { + +const ClassInfo NamePrototype::s_info = { "Name", &Base::s_info, 0, ExecState::privateNamePrototypeTable, CREATE_METHOD_TABLE(NamePrototype) }; + +/* Source for NamePrototype.lut.h +@begin privateNamePrototypeTable + toString privateNameProtoFuncToString DontEnum|Function 0 +@end +*/ + +NamePrototype::NamePrototype(ExecState* exec, Structure* structure) + : Base(exec->vm(), structure, jsEmptyString(exec)) +{ +} + +void NamePrototype::finishCreation(VM& vm) +{ + Base::finishCreation(vm); + ASSERT(inherits(info())); +} + +bool NamePrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot) +{ + return getStaticFunctionSlot<Base>(exec, ExecState::privateNamePrototypeTable(exec->vm()), jsCast<NamePrototype*>(object), propertyName, slot); +} + +// ------------------------------ Functions --------------------------- + +EncodedJSValue JSC_HOST_CALL privateNameProtoFuncToString(ExecState* exec) +{ + JSValue thisValue = exec->hostThisValue(); + if (!thisValue.isObject()) + return throwVMTypeError(exec); + + JSObject* thisObject = asObject(thisValue); + if (!thisObject->inherits(NameInstance::info())) + return throwVMTypeError(exec); + + return JSValue::encode(jsCast<NameInstance*>(thisObject)->nameString()); +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/SymbolPrototype.h b/Source/JavaScriptCore/runtime/NamePrototype.h index 8b221e519..d4b947f72 100644 --- a/Source/JavaScriptCore/runtime/SymbolPrototype.h +++ b/Source/JavaScriptCore/runtime/NamePrototype.h @@ -1,6 +1,5 @@ /* * Copyright (C) 2012 Apple Inc. All rights reserved. - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,42 +23,42 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SymbolPrototype_h -#define SymbolPrototype_h +#ifndef NamePrototype_h +#define NamePrototype_h -#include "Symbol.h" -#include "SymbolObject.h" +#include "NameInstance.h" namespace JSC { -// In the ES6 spec, Symbol.prototype object is an ordinary JS object, not one of the symbol wrapper object instance. -class SymbolPrototype : public JSDestructibleObject { +class NamePrototype : public NameInstance { public: - typedef JSDestructibleObject Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; + typedef NameInstance Base; - static SymbolPrototype* create(VM& vm, JSGlobalObject*, Structure* structure) + static NamePrototype* create(ExecState* exec, Structure* structure) { - SymbolPrototype* prototype = new (NotNull, allocateCell<SymbolPrototype>(vm.heap)) SymbolPrototype(vm, structure); + VM& vm = exec->vm(); + NamePrototype* prototype = new (NotNull, allocateCell<NamePrototype>(vm.heap)) NamePrototype(exec, structure); prototype->finishCreation(vm); return prototype; } - + DECLARE_INFO; static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + return Structure::create(vm, globalObject, prototype, TypeInfo(NameInstanceType, StructureFlags), info()); } protected: - SymbolPrototype(VM&, Structure*); + NamePrototype(ExecState*, Structure*); void finishCreation(VM&); + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | NameInstance::StructureFlags; + private: static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); }; } // namespace JSC -#endif // SymbolPrototype_h +#endif // NamePrototype_h diff --git a/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp b/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp index 3fb58a328..d5e728c2c 100644 --- a/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp +++ b/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp @@ -25,38 +25,27 @@ #include "JSFunction.h" #include "JSString.h" #include "NativeErrorPrototype.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(NativeErrorConstructor); -const ClassInfo NativeErrorConstructor::s_info = { "Function", &InternalFunction::s_info, 0, CREATE_METHOD_TABLE(NativeErrorConstructor) }; +const ClassInfo NativeErrorConstructor::s_info = { "Function", &InternalFunction::s_info, 0, 0, CREATE_METHOD_TABLE(NativeErrorConstructor) }; NativeErrorConstructor::NativeErrorConstructor(VM& vm, Structure* structure) : InternalFunction(vm, structure) { } -void NativeErrorConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, Structure* prototypeStructure, const String& name) -{ - Base::finishCreation(vm, name); - ASSERT(inherits(info())); - - NativeErrorPrototype* prototype = NativeErrorPrototype::create(vm, globalObject, prototypeStructure, name, this); - - putDirect(vm, vm.propertyNames->length, jsNumber(1), DontDelete | ReadOnly | DontEnum); // ECMA 15.11.7.5 - putDirect(vm, vm.propertyNames->prototype, prototype, DontDelete | ReadOnly | DontEnum); - m_errorStructure.set(vm, this, ErrorInstance::createStructure(vm, globalObject, prototype)); - ASSERT(m_errorStructure); - ASSERT(m_errorStructure->isObject()); -} - void NativeErrorConstructor::visitChildren(JSCell* cell, SlotVisitor& visitor) { NativeErrorConstructor* thisObject = jsCast<NativeErrorConstructor*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - Base::visitChildren(thisObject, visitor); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + + InternalFunction::visitChildren(thisObject, visitor); visitor.append(&thisObject->m_errorStructure); } @@ -65,7 +54,10 @@ EncodedJSValue JSC_HOST_CALL Interpreter::constructWithNativeErrorConstructor(Ex JSValue message = exec->argument(0); Structure* errorStructure = static_cast<NativeErrorConstructor*>(exec->callee())->errorStructure(); ASSERT(errorStructure); - return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, nullptr, TypeNothing, false)); + Vector<StackFrame> stackTrace; + exec->vm().interpreter->getStackTrace(stackTrace, std::numeric_limits<size_t>::max()); + stackTrace.remove(0); + return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, stackTrace)); } ConstructType NativeErrorConstructor::getConstructData(JSCell*, ConstructData& constructData) @@ -78,7 +70,10 @@ EncodedJSValue JSC_HOST_CALL Interpreter::callNativeErrorConstructor(ExecState* { JSValue message = exec->argument(0); Structure* errorStructure = static_cast<NativeErrorConstructor*>(exec->callee())->errorStructure(); - return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, nullptr, TypeNothing, false)); + Vector<StackFrame> stackTrace; + exec->vm().interpreter->getStackTrace(stackTrace, std::numeric_limits<size_t>::max()); + stackTrace.remove(0); + return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, stackTrace)); } CallType NativeErrorConstructor::getCallData(JSCell*, CallData& callData) diff --git a/Source/JavaScriptCore/runtime/NativeErrorConstructor.h b/Source/JavaScriptCore/runtime/NativeErrorConstructor.h index b582ef392..740d3f933 100644 --- a/Source/JavaScriptCore/runtime/NativeErrorConstructor.h +++ b/Source/JavaScriptCore/runtime/NativeErrorConstructor.h @@ -26,41 +26,54 @@ namespace JSC { -class ErrorInstance; -class FunctionPrototype; -class NativeErrorPrototype; + class ErrorInstance; + class FunctionPrototype; + class NativeErrorPrototype; -class NativeErrorConstructor : public InternalFunction { -public: - typedef InternalFunction Base; + class NativeErrorConstructor : public InternalFunction { + public: + typedef InternalFunction Base; - static NativeErrorConstructor* create(VM& vm, JSGlobalObject* globalObject, Structure* structure, Structure* prototypeStructure, const String& name) - { - NativeErrorConstructor* constructor = new (NotNull, allocateCell<NativeErrorConstructor>(vm.heap)) NativeErrorConstructor(vm, structure); - constructor->finishCreation(vm, globalObject, prototypeStructure, name); - return constructor; - } + static NativeErrorConstructor* create(VM& vm, JSGlobalObject* globalObject, Structure* structure, Structure* prototypeStructure, const String& name) + { + NativeErrorConstructor* constructor = new (NotNull, allocateCell<NativeErrorConstructor>(vm.heap)) NativeErrorConstructor(vm, structure); + constructor->finishCreation(vm, globalObject, prototypeStructure, name); + return constructor; + } + + DECLARE_INFO; - DECLARE_INFO; + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } + Structure* errorStructure() { return m_errorStructure.get(); } - Structure* errorStructure() { return m_errorStructure.get(); } + protected: + void finishCreation(VM& vm, JSGlobalObject* globalObject, Structure* prototypeStructure, const String& name) + { + Base::finishCreation(vm, name); + ASSERT(inherits(info())); -protected: - void finishCreation(VM&, JSGlobalObject*, Structure* prototypeStructure, const String& name); + NativeErrorPrototype* prototype = NativeErrorPrototype::create(vm, globalObject, prototypeStructure, name, this); -private: - NativeErrorConstructor(VM&, Structure*); - static ConstructType getConstructData(JSCell*, ConstructData&); - static CallType getCallData(JSCell*, CallData&); - static void visitChildren(JSCell*, SlotVisitor&); + putDirect(vm, vm.propertyNames->length, jsNumber(1), DontDelete | ReadOnly | DontEnum); // ECMA 15.11.7.5 + putDirect(vm, vm.propertyNames->prototype, prototype, DontDelete | ReadOnly | DontEnum); + m_errorStructure.set(vm, this, ErrorInstance::createStructure(vm, globalObject, prototype)); + ASSERT(m_errorStructure); + ASSERT(m_errorStructure->isObject()); + } - WriteBarrier<Structure> m_errorStructure; -}; + private: + NativeErrorConstructor(VM&, Structure*); + static const unsigned StructureFlags = OverridesVisitChildren | InternalFunction::StructureFlags; + static ConstructType getConstructData(JSCell*, ConstructData&); + static CallType getCallData(JSCell*, CallData&); + static void visitChildren(JSCell*, SlotVisitor&); + + WriteBarrier<Structure> m_errorStructure; + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp b/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp index 967ac5f8f..3dea2093d 100644 --- a/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp +++ b/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp @@ -24,7 +24,7 @@ #include "JSGlobalObject.h" #include "JSString.h" #include "NativeErrorConstructor.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { diff --git a/Source/JavaScriptCore/runtime/NativeErrorPrototype.h b/Source/JavaScriptCore/runtime/NativeErrorPrototype.h index 5812e6363..9326c5ccb 100644 --- a/Source/JavaScriptCore/runtime/NativeErrorPrototype.h +++ b/Source/JavaScriptCore/runtime/NativeErrorPrototype.h @@ -24,26 +24,25 @@ #include "ErrorPrototype.h" namespace JSC { - -class NativeErrorConstructor; - -class NativeErrorPrototype : public ErrorPrototype { -private: - NativeErrorPrototype(VM&, Structure*); - -public: - typedef ErrorPrototype Base; - - static NativeErrorPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure, const String& name, NativeErrorConstructor* constructor) - { - NativeErrorPrototype* prototype = new (NotNull, allocateCell<NativeErrorPrototype>(vm.heap)) NativeErrorPrototype(vm, structure); - prototype->finishCreation(vm, globalObject, name, constructor); - return prototype; - } - -protected: - void finishCreation(VM&, JSGlobalObject*, const String& nameAndMessage, NativeErrorConstructor*); -}; + class NativeErrorConstructor; + + class NativeErrorPrototype : public ErrorPrototype { + private: + NativeErrorPrototype(VM&, Structure*); + + public: + typedef ErrorPrototype Base; + + static NativeErrorPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure, const String& name, NativeErrorConstructor* constructor) + { + NativeErrorPrototype* prototype = new (NotNull, allocateCell<NativeErrorPrototype>(vm.heap)) NativeErrorPrototype(vm, structure); + prototype->finishCreation(vm, globalObject, name, constructor); + return prototype; + } + + protected: + void finishCreation(VM&, JSGlobalObject*, const String& nameAndMessage, NativeErrorConstructor*); + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/NullGetterFunction.h b/Source/JavaScriptCore/runtime/NullGetterFunction.h deleted file mode 100644 index d95feb731..000000000 --- a/Source/JavaScriptCore/runtime/NullGetterFunction.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2014 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 NullGetterFunction_h -#define NullGetterFunction_h - -#include "InternalFunction.h" - -namespace JSC { - -class NullGetterFunction : public InternalFunction { -public: - typedef InternalFunction Base; - - static NullGetterFunction* create(VM& vm, Structure* structure) - { - NullGetterFunction* function = new (NotNull, allocateCell< NullGetterFunction>(vm.heap)) NullGetterFunction(vm, structure); - function->finishCreation(vm, String()); - return function; - } - - DECLARE_EXPORT_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } - -private: - NullGetterFunction(VM& vm, Structure* structure) - : Base(vm, structure) - { - } - static ConstructType getConstructData(JSCell*, ConstructData&); - static CallType getCallData(JSCell*, CallData&); -}; - -} - -#endif // NullGetterFunction_h diff --git a/Source/JavaScriptCore/runtime/NullSetterFunction.cpp b/Source/JavaScriptCore/runtime/NullSetterFunction.cpp deleted file mode 100644 index 118fb1520..000000000 --- a/Source/JavaScriptCore/runtime/NullSetterFunction.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2015 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 "NullSetterFunction.h" - -#include "Error.h" -#include "JSCInlines.h" -#include "JSCJSValueInlines.h" -#include "StackVisitor.h" - -namespace JSC { - -const ClassInfo NullSetterFunction::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(NullSetterFunction) }; - - -class GetCallerStrictnessFunctor { -public: - GetCallerStrictnessFunctor() - : m_iterations(0) - , m_callerIsStrict(false) - { - } - - StackVisitor::Status operator()(StackVisitor& visitor) - { - ++m_iterations; - if (m_iterations < 2) - return StackVisitor::Continue; - - CodeBlock* codeBlock = visitor->codeBlock(); - m_callerIsStrict = codeBlock && codeBlock->isStrictMode(); - return StackVisitor::Done; - } - - bool callerIsStrict() const { return m_callerIsStrict; } - -private: - int m_iterations; - bool m_callerIsStrict; -}; - -static bool callerIsStrict(ExecState* exec) -{ - GetCallerStrictnessFunctor iter; - exec->iterate(iter); - return iter.callerIsStrict(); -} - -static EncodedJSValue JSC_HOST_CALL callReturnUndefined(ExecState* exec) -{ - if (callerIsStrict(exec)) - return JSValue::encode(throwTypeError(exec, ASCIILiteral("Setting a property that has only a getter"))); - return JSValue::encode(jsUndefined()); -} - -CallType NullSetterFunction::getCallData(JSCell*, CallData& callData) -{ - callData.native.function = callReturnUndefined; - return CallTypeHost; -} - -ConstructType NullSetterFunction::getConstructData(JSCell*, ConstructData&) -{ - return ConstructTypeNone; -} - -} diff --git a/Source/JavaScriptCore/runtime/NullSetterFunction.h b/Source/JavaScriptCore/runtime/NullSetterFunction.h deleted file mode 100644 index ccdc6f1dd..000000000 --- a/Source/JavaScriptCore/runtime/NullSetterFunction.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2015 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 NullSetterFunction_h -#define NullSetterFunction_h - -#include "InternalFunction.h" - -namespace JSC { - -class NullSetterFunction : public InternalFunction { -public: - typedef InternalFunction Base; - - static NullSetterFunction* create(VM& vm, Structure* structure) - { - NullSetterFunction* function = new (NotNull, allocateCell< NullSetterFunction>(vm.heap)) NullSetterFunction(vm, structure); - function->finishCreation(vm, String()); - return function; - } - - DECLARE_EXPORT_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } - -private: - NullSetterFunction(VM& vm, Structure* structure) - : Base(vm, structure) - { - } - static ConstructType getConstructData(JSCell*, ConstructData&); - static CallType getCallData(JSCell*, CallData&); -}; - -} - -#endif // NullSetterFunction_h diff --git a/Source/JavaScriptCore/runtime/NumberConstructor.cpp b/Source/JavaScriptCore/runtime/NumberConstructor.cpp index 0a21512d3..8e858a24f 100644 --- a/Source/JavaScriptCore/runtime/NumberConstructor.cpp +++ b/Source/JavaScriptCore/runtime/NumberConstructor.cpp @@ -25,23 +25,35 @@ #include "Lookup.h" #include "NumberObject.h" #include "NumberPrototype.h" -#include "JSCInlines.h" -#include "JSGlobalObjectFunctions.h" +#include "Operations.h" namespace JSC { -static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsFinite(ExecState*); -static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsInteger(ExecState*); -static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsNaN(ExecState*); -static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsSafeInteger(ExecState*); +static EncodedJSValue numberConstructorNaNValue(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); +static EncodedJSValue numberConstructorNegInfinity(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); +static EncodedJSValue numberConstructorPosInfinity(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); +static EncodedJSValue numberConstructorMaxValue(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); +static EncodedJSValue numberConstructorMinValue(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); } // namespace JSC +#include "NumberConstructor.lut.h" + namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(NumberConstructor); -const ClassInfo NumberConstructor::s_info = { "Function", &InternalFunction::s_info, 0, CREATE_METHOD_TABLE(NumberConstructor) }; +const ClassInfo NumberConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::numberConstructorTable, CREATE_METHOD_TABLE(NumberConstructor) }; + +/* Source for NumberConstructor.lut.h +@begin numberConstructorTable + NaN numberConstructorNaNValue DontEnum|DontDelete|ReadOnly + NEGATIVE_INFINITY numberConstructorNegInfinity DontEnum|DontDelete|ReadOnly + POSITIVE_INFINITY numberConstructorPosInfinity DontEnum|DontDelete|ReadOnly + MAX_VALUE numberConstructorMaxValue DontEnum|DontDelete|ReadOnly + MIN_VALUE numberConstructorMinValue DontEnum|DontDelete|ReadOnly +@end +*/ NumberConstructor::NumberConstructor(VM& vm, Structure* structure) : InternalFunction(vm, structure) @@ -58,22 +70,36 @@ void NumberConstructor::finishCreation(VM& vm, NumberPrototype* numberPrototype) // no. of arguments for constructor putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontEnum | DontDelete); +} + +bool NumberConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) +{ + return getStaticValueSlot<NumberConstructor, InternalFunction>(exec, ExecState::numberConstructorTable(exec->vm()), jsCast<NumberConstructor*>(object), propertyName, slot); +} + +static EncodedJSValue numberConstructorNaNValue(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName) +{ + return JSValue::encode(jsNaN()); +} + +static EncodedJSValue numberConstructorNegInfinity(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName) +{ + return JSValue::encode(jsNumber(-std::numeric_limits<double>::infinity())); +} - putDirectWithoutTransition(vm, Identifier::fromString(&vm, "EPSILON"), jsDoubleNumber(std::numeric_limits<double>::epsilon()), DontDelete | DontEnum | ReadOnly); - putDirectWithoutTransition(vm, Identifier::fromString(&vm, "MAX_VALUE"), jsDoubleNumber(1.7976931348623157E+308), DontDelete | DontEnum | ReadOnly); - putDirectWithoutTransition(vm, Identifier::fromString(&vm, "MIN_VALUE"), jsDoubleNumber(5E-324), DontDelete | DontEnum | ReadOnly); - putDirectWithoutTransition(vm, Identifier::fromString(&vm, "MAX_SAFE_INTEGER"), jsDoubleNumber(9007199254740991.0), DontDelete | DontEnum | ReadOnly); - putDirectWithoutTransition(vm, Identifier::fromString(&vm, "MIN_SAFE_INTEGER"), jsDoubleNumber(-9007199254740991.0), DontDelete | DontEnum | ReadOnly); - putDirectWithoutTransition(vm, Identifier::fromString(&vm, "NEGATIVE_INFINITY"), jsDoubleNumber(-std::numeric_limits<double>::infinity()), DontDelete | DontEnum | ReadOnly); - putDirectWithoutTransition(vm, Identifier::fromString(&vm, "POSITIVE_INFINITY"), jsDoubleNumber(std::numeric_limits<double>::infinity()), DontDelete | DontEnum | ReadOnly); - putDirectWithoutTransition(vm, Identifier::fromString(&vm, "NaN"), jsNaN(), DontDelete | DontEnum | ReadOnly); - - putDirectNativeFunctionWithoutTransition(vm, numberPrototype->globalObject(), Identifier::fromString(&vm, "isFinite"), 1, numberConstructorFuncIsFinite, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, numberPrototype->globalObject(), Identifier::fromString(&vm, "isInteger"), 1, numberConstructorFuncIsInteger, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, numberPrototype->globalObject(), Identifier::fromString(&vm, "isNaN"), 1, numberConstructorFuncIsNaN, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, numberPrototype->globalObject(), Identifier::fromString(&vm, "isSafeInteger"), 1, numberConstructorFuncIsSafeInteger, NoIntrinsic, DontEnum | Function); - putDirectNativeFunctionWithoutTransition(vm, numberPrototype->globalObject(), Identifier::fromString(&vm, "parseFloat"), 1, globalFuncParseFloat, NoIntrinsic, DontEnum | Function); - putDirectWithoutTransition(vm, Identifier::fromString(&vm, "parseInt"), numberPrototype->globalObject()->parseIntFunction(), DontEnum | Function); +static EncodedJSValue numberConstructorPosInfinity(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName) +{ + return JSValue::encode(jsNumber(std::numeric_limits<double>::infinity())); +} + +static EncodedJSValue numberConstructorMaxValue(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName) +{ + return JSValue::encode(jsNumber(1.7976931348623157E+308)); +} + +static EncodedJSValue numberConstructorMinValue(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName) +{ + return JSValue::encode(jsNumber(5E-324)); } // ECMA 15.7.1 @@ -103,50 +129,4 @@ CallType NumberConstructor::getCallData(JSCell*, CallData& callData) return CallTypeHost; } -// ECMA-262 20.1.2.2 -static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsFinite(ExecState* exec) -{ - JSValue argument = exec->argument(0); - return JSValue::encode(jsBoolean(argument.isNumber() && (argument.isInt32() || std::isfinite(argument.asDouble())))); -} - -// ECMA-262 20.1.2.3 -static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsInteger(ExecState* exec) -{ - JSValue argument = exec->argument(0); - bool isInteger; - if (argument.isInt32()) - isInteger = true; - else if (!argument.isDouble()) - isInteger = false; - else { - double number = argument.asDouble(); - isInteger = std::isfinite(number) && trunc(number) == number; - } - return JSValue::encode(jsBoolean(isInteger)); -} - -// ECMA-262 20.1.2.4 -static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsNaN(ExecState* exec) -{ - JSValue argument = exec->argument(0); - return JSValue::encode(jsBoolean(argument.isDouble() && std::isnan(argument.asDouble()))); -} - -// ECMA-262 20.1.2.5 -static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsSafeInteger(ExecState* exec) -{ - JSValue argument = exec->argument(0); - bool isInteger; - if (argument.isInt32()) - isInteger = true; - else if (!argument.isDouble()) - isInteger = false; - else { - double number = argument.asDouble(); - isInteger = trunc(number) == number && std::abs(number) <= 9007199254740991.0; - } - return JSValue::encode(jsBoolean(isInteger)); -} - } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/NumberConstructor.h b/Source/JavaScriptCore/runtime/NumberConstructor.h index f8b1f7f44..6c8ed89fe 100644 --- a/Source/JavaScriptCore/runtime/NumberConstructor.h +++ b/Source/JavaScriptCore/runtime/NumberConstructor.h @@ -25,35 +25,40 @@ namespace JSC { -class NumberPrototype; - -class NumberConstructor : public InternalFunction { -public: - typedef InternalFunction Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | ImplementsHasInstance; - - static NumberConstructor* create(VM& vm, Structure* structure, NumberPrototype* numberPrototype) - { - NumberConstructor* constructor = new (NotNull, allocateCell<NumberConstructor>(vm.heap)) NumberConstructor(vm, structure); - constructor->finishCreation(vm, numberPrototype); - return constructor; - } - - DECLARE_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) - { - return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info()); - } - -protected: - void finishCreation(VM&, NumberPrototype*); - -private: - NumberConstructor(VM&, Structure*); - static ConstructType getConstructData(JSCell*, ConstructData&); - static CallType getCallData(JSCell*, CallData&); -}; + class NumberPrototype; + + class NumberConstructor : public InternalFunction { + public: + typedef InternalFunction Base; + + static NumberConstructor* create(VM& vm, Structure* structure, NumberPrototype* numberPrototype) + { + NumberConstructor* constructor = new (NotNull, allocateCell<NumberConstructor>(vm.heap)) NumberConstructor(vm, structure); + constructor->finishCreation(vm, numberPrototype); + return constructor; + } + + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + JSValue getValueProperty(ExecState*, int token) const; + + DECLARE_INFO; + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) + { + return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info()); + } + + enum { NaNValue, NegInfinity, PosInfinity, MaxValue, MinValue }; + + protected: + void finishCreation(VM&, NumberPrototype*); + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | InternalFunction::StructureFlags; + + private: + NumberConstructor(VM&, Structure*); + static ConstructType getConstructData(JSCell*, ConstructData&); + static CallType getCallData(JSCell*, CallData&); + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/NumberObject.cpp b/Source/JavaScriptCore/runtime/NumberObject.cpp index 31350ccbd..a77d45f4f 100644 --- a/Source/JavaScriptCore/runtime/NumberObject.cpp +++ b/Source/JavaScriptCore/runtime/NumberObject.cpp @@ -24,13 +24,13 @@ #include "JSGlobalObject.h" #include "NumberPrototype.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(NumberObject); -const ClassInfo NumberObject::s_info = { "Number", &JSWrapperObject::s_info, 0, CREATE_METHOD_TABLE(NumberObject) }; +const ClassInfo NumberObject::s_info = { "Number", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(NumberObject) }; NumberObject::NumberObject(VM& vm, Structure* structure) : JSWrapperObject(vm, structure) diff --git a/Source/JavaScriptCore/runtime/NumberObject.h b/Source/JavaScriptCore/runtime/NumberObject.h index d979dd48a..4bdf2819f 100644 --- a/Source/JavaScriptCore/runtime/NumberObject.h +++ b/Source/JavaScriptCore/runtime/NumberObject.h @@ -25,30 +25,30 @@ namespace JSC { -class NumberObject : public JSWrapperObject { -protected: - NumberObject(VM&, Structure*); - void finishCreation(VM&); - -public: - typedef JSWrapperObject Base; - - static NumberObject* create(VM& vm, Structure* structure) - { - NumberObject* number = new (NotNull, allocateCell<NumberObject>(vm.heap)) NumberObject(vm, structure); - number->finishCreation(vm); - return number; - } - - DECLARE_EXPORT_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(NumberObjectType, StructureFlags), info()); - } -}; - -JS_EXPORT_PRIVATE NumberObject* constructNumber(ExecState*, JSGlobalObject*, JSValue); + class NumberObject : public JSWrapperObject { + protected: + NumberObject(VM&, Structure*); + void finishCreation(VM&); + + public: + typedef JSWrapperObject Base; + + static NumberObject* create(VM& vm, Structure* structure) + { + NumberObject* number = new (NotNull, allocateCell<NumberObject>(vm.heap)) NumberObject(vm, structure); + number->finishCreation(vm); + return number; + } + + DECLARE_EXPORT_INFO; + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(NumberObjectType, StructureFlags), info()); + } + }; + + JS_EXPORT_PRIVATE NumberObject* constructNumber(ExecState*, JSGlobalObject*, JSValue); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/NumberPrototype.cpp b/Source/JavaScriptCore/runtime/NumberPrototype.cpp index ea711c0f7..141024ac3 100644 --- a/Source/JavaScriptCore/runtime/NumberPrototype.cpp +++ b/Source/JavaScriptCore/runtime/NumberPrototype.cpp @@ -27,7 +27,7 @@ #include "JSFunction.h" #include "JSGlobalObject.h" #include "JSString.h" -#include "JSCInlines.h" +#include "Operations.h" #include "Uint16WithFraction.h" #include <wtf/dtoa.h> #include <wtf/Assertions.h> @@ -55,7 +55,7 @@ static EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState*); namespace JSC { -const ClassInfo NumberPrototype::s_info = { "Number", &NumberObject::s_info, &numberPrototypeTable, CREATE_METHOD_TABLE(NumberPrototype) }; +const ClassInfo NumberPrototype::s_info = { "Number", &NumberObject::s_info, 0, ExecState::numberPrototypeTable, CREATE_METHOD_TABLE(NumberPrototype) }; /* Source for NumberPrototype.lut.h @begin numberPrototypeTable @@ -85,7 +85,7 @@ void NumberPrototype::finishCreation(VM& vm, JSGlobalObject*) bool NumberPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot) { - return getStaticFunctionSlot<NumberObject>(exec, numberPrototypeTable, jsCast<NumberPrototype*>(object), propertyName, slot); + return getStaticFunctionSlot<NumberObject>(exec, ExecState::numberPrototypeTable(exec->vm()), jsCast<NumberPrototype*>(object), propertyName, slot); } // ------------------------------ Functions --------------------------- @@ -102,7 +102,7 @@ static ALWAYS_INLINE bool toThisNumber(JSValue thisValue, double& x) return true; } - if (thisValue.isCell() && thisValue.asCell()->type() == NumberObjectType) { + if (thisValue.isCell() && thisValue.asCell()->structure()->typeInfo().isNumberObject()) { x = static_cast<const NumberObject*>(thisValue.asCell())->internalValue().asNumber(); return true; } @@ -365,7 +365,7 @@ static String toStringWithRadix(int32_t number, unsigned radix) EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState* exec) { double x; - if (!toThisNumber(exec->thisValue(), x)) + if (!toThisNumber(exec->hostThisValue(), x)) return throwVMTypeError(exec); // Get the argument. @@ -376,7 +376,7 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState* exec) // Handle NaN and Infinity. if (!std::isfinite(x)) - return JSValue::encode(jsNontrivialString(exec, String::numberToStringECMAScript(x))); + return JSValue::encode(jsString(exec, String::numberToStringECMAScript(x))); // Round if the argument is not undefined, always format as exponential. char buffer[WTF::NumberToStringBufferLength]; @@ -396,7 +396,7 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState* exec) EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec) { double x; - if (!toThisNumber(exec->thisValue(), x)) + if (!toThisNumber(exec->hostThisValue(), x)) return throwVMTypeError(exec); // Get the argument. @@ -429,7 +429,7 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec) EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec) { double x; - if (!toThisNumber(exec->thisValue(), x)) + if (!toThisNumber(exec->hostThisValue(), x)) return throwVMTypeError(exec); // Get the argument. @@ -444,7 +444,7 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec) // Handle NaN and Infinity. if (!std::isfinite(x)) - return JSValue::encode(jsNontrivialString(exec, String::numberToStringECMAScript(x))); + return JSValue::encode(jsString(exec, String::numberToStringECMAScript(x))); NumberToStringBuffer buffer; return JSValue::encode(jsString(exec, String(numberToFixedPrecisionString(x, significantFigures, buffer)))); @@ -486,7 +486,7 @@ static inline EncodedJSValue integerValueToString(ExecState* exec, int32_t radix EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec) { double doubleValue; - if (!toThisNumber(exec->thisValue(), doubleValue)) + if (!toThisNumber(exec->hostThisValue(), doubleValue)) return throwVMTypeError(exec); int32_t radix = extractRadixFromArgs(exec); @@ -503,7 +503,7 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec) } if (!std::isfinite(doubleValue)) - return JSValue::encode(jsNontrivialString(exec, String::numberToStringECMAScript(doubleValue))); + return JSValue::encode(jsString(exec, String::numberToStringECMAScript(doubleValue))); RadixBuffer s; return JSValue::encode(jsString(exec, toStringWithRadix(s, doubleValue, radix))); @@ -512,7 +512,7 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec) EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState* exec) { double x; - if (!toThisNumber(exec->thisValue(), x)) + if (!toThisNumber(exec->hostThisValue(), x)) return throwVMTypeError(exec); return JSValue::encode(jsNumber(x).toString(exec)); @@ -521,7 +521,7 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState* exec) EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState* exec) { double x; - if (!toThisNumber(exec->thisValue(), x)) + if (!toThisNumber(exec->hostThisValue(), x)) return throwVMTypeError(exec); return JSValue::encode(jsNumber(x)); } diff --git a/Source/JavaScriptCore/runtime/NumberPrototype.h b/Source/JavaScriptCore/runtime/NumberPrototype.h index 45acd8fb1..723544faa 100644 --- a/Source/JavaScriptCore/runtime/NumberPrototype.h +++ b/Source/JavaScriptCore/runtime/NumberPrototype.h @@ -25,32 +25,32 @@ namespace JSC { -class NumberPrototype : public NumberObject { -public: - typedef NumberObject Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; - - static NumberPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) - { - NumberPrototype* prototype = new (NotNull, allocateCell<NumberPrototype>(vm.heap)) NumberPrototype(vm, structure); - prototype->finishCreation(vm, globalObject); - return prototype; - } - - DECLARE_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(NumberObjectType, StructureFlags), info()); - } - -protected: - void finishCreation(VM&, JSGlobalObject*); - -private: - NumberPrototype(VM&, Structure*); - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); -}; + class NumberPrototype : public NumberObject { + public: + typedef NumberObject Base; + + static NumberPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) + { + NumberPrototype* prototype = new (NotNull, allocateCell<NumberPrototype>(vm.heap)) NumberPrototype(vm, structure); + prototype->finishCreation(vm, globalObject); + return prototype; + } + + DECLARE_INFO; + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(NumberObjectType, StructureFlags), info()); + } + + protected: + void finishCreation(VM&, JSGlobalObject*); + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | NumberObject::StructureFlags; + + private: + NumberPrototype(VM&, Structure*); + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/NumericStrings.h b/Source/JavaScriptCore/runtime/NumericStrings.h index ac8d41603..3bb5b91c8 100644 --- a/Source/JavaScriptCore/runtime/NumericStrings.h +++ b/Source/JavaScriptCore/runtime/NumericStrings.h @@ -32,66 +32,66 @@ namespace JSC { -class NumericStrings { -public: - ALWAYS_INLINE String add(double d) - { - CacheEntry<double>& entry = lookup(d); - if (d == entry.key && !entry.value.isNull()) + class NumericStrings { + public: + ALWAYS_INLINE String add(double d) + { + CacheEntry<double>& entry = lookup(d); + if (d == entry.key && !entry.value.isNull()) + return entry.value; + entry.key = d; + entry.value = String::numberToStringECMAScript(d); return entry.value; - entry.key = d; - entry.value = String::numberToStringECMAScript(d); - return entry.value; - } + } - ALWAYS_INLINE String add(int i) - { - if (static_cast<unsigned>(i) < cacheSize) - return lookupSmallString(static_cast<unsigned>(i)); - CacheEntry<int>& entry = lookup(i); - if (i == entry.key && !entry.value.isNull()) + ALWAYS_INLINE String add(int i) + { + if (static_cast<unsigned>(i) < cacheSize) + return lookupSmallString(static_cast<unsigned>(i)); + CacheEntry<int>& entry = lookup(i); + if (i == entry.key && !entry.value.isNull()) + return entry.value; + entry.key = i; + entry.value = String::number(i); return entry.value; - entry.key = i; - entry.value = String::number(i); - return entry.value; - } + } - ALWAYS_INLINE String add(unsigned i) - { - if (i < cacheSize) - return lookupSmallString(static_cast<unsigned>(i)); - CacheEntry<unsigned>& entry = lookup(i); - if (i == entry.key && !entry.value.isNull()) + ALWAYS_INLINE String add(unsigned i) + { + if (i < cacheSize) + return lookupSmallString(static_cast<unsigned>(i)); + CacheEntry<unsigned>& entry = lookup(i); + if (i == entry.key && !entry.value.isNull()) + return entry.value; + entry.key = i; + entry.value = String::number(i); return entry.value; - entry.key = i; - entry.value = String::number(i); - return entry.value; - } -private: - static const size_t cacheSize = 64; + } + private: + static const size_t cacheSize = 64; - template<typename T> - struct CacheEntry { - T key; - String value; - }; + template<typename T> + struct CacheEntry { + T key; + String value; + }; - CacheEntry<double>& lookup(double d) { return doubleCache[WTF::FloatHash<double>::hash(d) & (cacheSize - 1)]; } - CacheEntry<int>& lookup(int i) { return intCache[WTF::IntHash<int>::hash(i) & (cacheSize - 1)]; } - CacheEntry<unsigned>& lookup(unsigned i) { return unsignedCache[WTF::IntHash<unsigned>::hash(i) & (cacheSize - 1)]; } - ALWAYS_INLINE const String& lookupSmallString(unsigned i) - { - ASSERT(i < cacheSize); - if (smallIntCache[i].isNull()) - smallIntCache[i] = String::number(i); - return smallIntCache[i]; - } + CacheEntry<double>& lookup(double d) { return doubleCache[WTF::FloatHash<double>::hash(d) & (cacheSize - 1)]; } + CacheEntry<int>& lookup(int i) { return intCache[WTF::IntHash<int>::hash(i) & (cacheSize - 1)]; } + CacheEntry<unsigned>& lookup(unsigned i) { return unsignedCache[WTF::IntHash<unsigned>::hash(i) & (cacheSize - 1)]; } + ALWAYS_INLINE const String& lookupSmallString(unsigned i) + { + ASSERT(i < cacheSize); + if (smallIntCache[i].isNull()) + smallIntCache[i] = String::number(i); + return smallIntCache[i]; + } - std::array<CacheEntry<double>, cacheSize> doubleCache; - std::array<CacheEntry<int>, cacheSize> intCache; - std::array<CacheEntry<unsigned>, cacheSize> unsignedCache; - std::array<String, cacheSize> smallIntCache; -}; + std::array<CacheEntry<double>, cacheSize> doubleCache; + std::array<CacheEntry<int>, cacheSize> intCache; + std::array<CacheEntry<unsigned>, cacheSize> unsignedCache; + std::array<String, cacheSize> smallIntCache; + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp index 65acb4817..72169e7d2 100644 --- a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp @@ -22,36 +22,35 @@ #include "ObjectConstructor.h" #include "ButterflyInlines.h" +#include "CallFrameInlines.h" #include "CopiedSpaceInlines.h" #include "Error.h" #include "ExceptionHelpers.h" -#include "JSArray.h" -#include "JSCInlines.h" #include "JSFunction.h" +#include "JSArray.h" #include "JSGlobalObject.h" -#include "JSGlobalObjectFunctions.h" #include "Lookup.h" #include "ObjectPrototype.h" +#include "Operations.h" #include "PropertyDescriptor.h" #include "PropertyNameArray.h" #include "StackVisitor.h" -#include "Symbol.h" namespace JSC { -EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState*); -EncodedJSValue JSC_HOST_CALL objectConstructorSetPrototypeOf(ExecState*); -EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState*); -EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState*); -EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState*); -EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState*); -EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState*); -EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState*); -EncodedJSValue JSC_HOST_CALL objectConstructorPreventExtensions(ExecState*); -EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState*); -EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState*); -EncodedJSValue JSC_HOST_CALL objectConstructorIsExtensible(ExecState*); -EncodedJSValue JSC_HOST_CALL objectConstructorIs(ExecState*); +static EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState*); +static EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState*); +static EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState*); +static EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState*); +static EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState*); +static EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState*); +static EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState*); +static EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState*); +static EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState*); +static EncodedJSValue JSC_HOST_CALL objectConstructorPreventExtensions(ExecState*); +static EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState*); +static EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState*); +static EncodedJSValue JSC_HOST_CALL objectConstructorIsExtensible(ExecState*); } @@ -61,12 +60,11 @@ namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ObjectConstructor); -const ClassInfo ObjectConstructor::s_info = { "Function", &InternalFunction::s_info, &objectConstructorTable, CREATE_METHOD_TABLE(ObjectConstructor) }; +const ClassInfo ObjectConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::objectConstructorTable, CREATE_METHOD_TABLE(ObjectConstructor) }; /* Source for ObjectConstructor.lut.h @begin objectConstructorTable getPrototypeOf objectConstructorGetPrototypeOf DontEnum|Function 1 - setPrototypeOf objectConstructorSetPrototypeOf DontEnum|Function 2 getOwnPropertyDescriptor objectConstructorGetOwnPropertyDescriptor DontEnum|Function 2 getOwnPropertyNames objectConstructorGetOwnPropertyNames DontEnum|Function 1 keys objectConstructorKeys DontEnum|Function 1 @@ -79,8 +77,6 @@ const ClassInfo ObjectConstructor::s_info = { "Function", &InternalFunction::s_i isSealed objectConstructorIsSealed DontEnum|Function 1 isFrozen objectConstructorIsFrozen DontEnum|Function 1 isExtensible objectConstructorIsExtensible DontEnum|Function 1 - is objectConstructorIs DontEnum|Function 2 - assign objectConstructorAssign DontEnum|Function 2 @end */ @@ -89,30 +85,18 @@ ObjectConstructor::ObjectConstructor(VM& vm, Structure* structure) { } -void ObjectConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, ObjectPrototype* objectPrototype) +void ObjectConstructor::finishCreation(VM& vm, ObjectPrototype* objectPrototype) { - Base::finishCreation(vm, objectPrototype->classInfo()->className); + Base::finishCreation(vm, Identifier(&vm, "Object").string()); // ECMA 15.2.3.1 putDirectWithoutTransition(vm, vm.propertyNames->prototype, objectPrototype, DontEnum | DontDelete | ReadOnly); // no. of arguments for constructor putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontEnum | DontDelete); - - JSC_NATIVE_FUNCTION("getOwnPropertySymbols", objectConstructorGetOwnPropertySymbols, DontEnum, 1); - JSC_NATIVE_FUNCTION(vm.propertyNames->getPrototypeOfPrivateName, objectConstructorGetPrototypeOf, DontEnum, 1); - JSC_NATIVE_FUNCTION(vm.propertyNames->getOwnPropertyNamesPrivateName, objectConstructorGetOwnPropertyNames, DontEnum, 1); -} - -JSFunction* ObjectConstructor::addDefineProperty(ExecState* exec, JSGlobalObject* globalObject) -{ - VM& vm = exec->vm(); - JSFunction* definePropertyFunction = JSFunction::create(vm, globalObject, 3, vm.propertyNames->defineProperty.string(), objectConstructorDefineProperty); - putDirectWithoutTransition(vm, vm.propertyNames->defineProperty, definePropertyFunction, DontEnum); - return definePropertyFunction; } bool ObjectConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot) { - return getStaticFunctionSlot<JSObject>(exec, objectConstructorTable, jsCast<ObjectConstructor*>(object), propertyName, slot); + return getStaticFunctionSlot<JSObject>(exec, ExecState::objectConstructorTable(exec->vm()), jsCast<ObjectConstructor*>(object), propertyName, slot); } static ALWAYS_INLINE JSObject* constructObject(ExecState* exec) @@ -152,11 +136,11 @@ public: ObjectConstructorGetPrototypeOfFunctor(JSObject* object) : m_hasSkippedFirstFrame(false) , m_object(object) - , m_result(jsUndefined()) + , m_result(JSValue::encode(jsUndefined())) { } - JSValue result() const { return m_result; } + EncodedJSValue result() const { return m_result; } StackVisitor::Status operator()(StackVisitor& visitor) { @@ -165,73 +149,37 @@ public: return StackVisitor::Continue; } - if (m_object->allowsAccessFrom(visitor->callFrame())) - m_result = m_object->prototype(); - return StackVisitor::Done; - } + if (m_object->allowsAccessFrom(visitor->callFrame())) + m_result = JSValue::encode(m_object->prototype()); + return StackVisitor::Done; +} private: bool m_hasSkippedFirstFrame; JSObject* m_object; - JSValue m_result; + EncodedJSValue m_result; }; -JSValue objectConstructorGetPrototypeOf(ExecState* exec, JSObject* object) +EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState* exec) { + if (!exec->argument(0).isObject()) + return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested prototype of a value that is not an object."))); + JSObject* object = asObject(exec->argument(0)); ObjectConstructorGetPrototypeOfFunctor functor(object); exec->iterate(functor); return functor.result(); } -EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState* exec) -{ - JSObject* object = exec->argument(0).toObject(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - return JSValue::encode(objectConstructorGetPrototypeOf(exec, object)); -} - -EncodedJSValue JSC_HOST_CALL objectConstructorSetPrototypeOf(ExecState* exec) -{ - JSValue objectValue = exec->argument(0); - if (objectValue.isUndefinedOrNull()) - return throwVMTypeError(exec); - - JSValue protoValue = exec->argument(1); - if (!protoValue.isObject() && !protoValue.isNull()) - return throwVMTypeError(exec); - - JSObject* object = objectValue.toObject(exec); - if (exec->hadException()) - return JSValue::encode(objectValue); - - if (!checkProtoSetterAccessAllowed(exec, object)) - return JSValue::encode(objectValue); - - if (object->prototype() == protoValue) - return JSValue::encode(objectValue); - - if (!object->isExtensible()) - return throwVMError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError)); - - if (!object->setPrototypeWithCycleCheck(exec, protoValue)) { - exec->vm().throwException(exec, createError(exec, ASCIILiteral("cyclic __proto__ value"))); - return JSValue::encode(jsUndefined()); - } - - return JSValue::encode(objectValue); -} - EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState* exec) { - JSObject* object = exec->argument(0).toObject(exec); - if (exec->hadException()) - return JSValue::encode(jsNull()); - auto propertyName = exec->argument(1).toPropertyKey(exec); + if (!exec->argument(0).isObject()) + return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested property descriptor of a value that is not an object."))); + String propertyName = exec->argument(1).toString(exec)->value(exec); if (exec->hadException()) return JSValue::encode(jsNull()); + JSObject* object = asObject(exec->argument(0)); PropertyDescriptor descriptor; - if (!object->getOwnPropertyDescriptor(exec, propertyName, descriptor)) + if (!object->getOwnPropertyDescriptor(exec, Identifier(exec, propertyName), descriptor)) return JSValue::encode(jsUndefined()); if (exec->hadException()) return JSValue::encode(jsUndefined()); @@ -256,40 +204,33 @@ EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState // FIXME: Use the enumeration cache. EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState* exec) { - JSObject* object = exec->argument(0).toObject(exec); - if (exec->hadException()) - return JSValue::encode(jsNull()); - return JSValue::encode(ownPropertyKeys(exec, object, PropertyNameMode::Strings, DontEnumPropertiesMode::Include)); -} - -// FIXME: Use the enumeration cache. -EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertySymbols(ExecState* exec) -{ - JSObject* object = exec->argument(0).toObject(exec); - if (exec->hadException()) - return JSValue::encode(jsNull()); - return JSValue::encode(ownPropertyKeys(exec, object, PropertyNameMode::Symbols, DontEnumPropertiesMode::Include)); + if (!exec->argument(0).isObject()) + return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested property names of a value that is not an object."))); + PropertyNameArray properties(exec); + asObject(exec->argument(0))->methodTable()->getOwnPropertyNames(asObject(exec->argument(0)), exec, properties, IncludeDontEnumProperties); + JSArray* names = constructEmptyArray(exec, 0); + size_t numProperties = properties.size(); + for (size_t i = 0; i < numProperties; i++) + names->push(exec, jsOwnedString(exec, properties[i].string())); + return JSValue::encode(names); } // FIXME: Use the enumeration cache. EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec) { - JSObject* object = exec->argument(0).toObject(exec); - if (exec->hadException()) - return JSValue::encode(jsNull()); - return JSValue::encode(ownPropertyKeys(exec, object, PropertyNameMode::Strings, DontEnumPropertiesMode::Exclude)); -} - -EncodedJSValue JSC_HOST_CALL ownEnumerablePropertyKeys(ExecState* exec) -{ - JSObject* object = exec->argument(0).toObject(exec); - if (exec->hadException()) - return JSValue::encode(jsNull()); - return JSValue::encode(ownPropertyKeys(exec, object, PropertyNameMode::StringsAndSymbols, DontEnumPropertiesMode::Exclude)); + if (!exec->argument(0).isObject()) + return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested keys of a value that is not an object."))); + PropertyNameArray properties(exec); + asObject(exec->argument(0))->methodTable()->getOwnPropertyNames(asObject(exec->argument(0)), exec, properties, ExcludeDontEnumProperties); + JSArray* keys = constructEmptyArray(exec, 0); + size_t numProperties = properties.size(); + for (size_t i = 0; i < numProperties; i++) + keys->push(exec, jsOwnedString(exec, properties[i].string())); + return JSValue::encode(keys); } // ES5 8.10.5 ToPropertyDescriptor -bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor& desc) +static bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor& desc) { if (!in.isObject()) { exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Property description must be an object."))); @@ -376,7 +317,7 @@ EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState* exec) if (!exec->argument(0).isObject()) return throwVMError(exec, createTypeError(exec, ASCIILiteral("Properties can only be defined on Objects."))); JSObject* O = asObject(exec->argument(0)); - auto propertyName = exec->argument(1).toPropertyKey(exec); + String propertyName = exec->argument(1).toString(exec)->value(exec); if (exec->hadException()) return JSValue::encode(jsNull()); PropertyDescriptor descriptor; @@ -384,14 +325,14 @@ EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState* exec) return JSValue::encode(jsNull()); ASSERT((descriptor.attributes() & Accessor) || (!descriptor.isAccessorDescriptor())); ASSERT(!exec->hadException()); - O->methodTable(exec->vm())->defineOwnProperty(O, exec, propertyName, descriptor, true); + O->methodTable()->defineOwnProperty(O, exec, Identifier(exec, propertyName), descriptor, true); return JSValue::encode(O); } static JSValue defineProperties(ExecState* exec, JSObject* object, JSObject* properties) { - PropertyNameArray propertyNames(exec, PropertyNameMode::StringsAndSymbols); - asObject(properties)->methodTable(exec->vm())->getOwnPropertyNames(asObject(properties), exec, propertyNames, EnumerationMode(DontEnumPropertiesMode::Exclude)); + PropertyNameArray propertyNames(exec); + asObject(properties)->methodTable()->getOwnPropertyNames(asObject(properties), exec, propertyNames, ExcludeDontEnumProperties); size_t numProperties = propertyNames.size(); Vector<PropertyDescriptor> descriptors; MarkedArgumentBuffer markBuffer; @@ -414,10 +355,7 @@ static JSValue defineProperties(ExecState* exec, JSObject* object, JSObject* pro } } for (size_t i = 0; i < numProperties; i++) { - Identifier propertyName = propertyNames[i]; - if (exec->propertyNames().isPrivateName(propertyName)) - continue; - object->methodTable(exec->vm())->defineOwnProperty(object, exec, propertyName, descriptors[i], true); + object->methodTable()->defineOwnProperty(object, exec, propertyNames[i], descriptors[i], true); if (exec->hadException()) return jsNull(); } @@ -448,10 +386,10 @@ EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState* exec) EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState* exec) { - // 1. If Type(O) is not Object, return O. + // 1. If Type(O) is not Object throw a TypeError exception. JSValue obj = exec->argument(0); if (!obj.isObject()) - return JSValue::encode(obj); + return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.seal can only be called on Objects."))); JSObject* object = asObject(obj); if (isJSFinalObject(object)) { @@ -460,21 +398,18 @@ EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState* exec) } // 2. For each named own property name P of O, - PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols); - object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include)); + PropertyNameArray properties(exec); + object->methodTable()->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties); PropertyNameArray::const_iterator end = properties.end(); for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) { - Identifier propertyName = *iter; - if (exec->propertyNames().isPrivateName(propertyName)) - continue; // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P. PropertyDescriptor desc; - if (!object->getOwnPropertyDescriptor(exec, propertyName, desc)) + if (!object->getOwnPropertyDescriptor(exec, *iter, desc)) continue; // b. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false. desc.setConfigurable(false); // c. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments. - object->methodTable(exec->vm())->defineOwnProperty(object, exec, propertyName, desc, true); + object->methodTable()->defineOwnProperty(object, exec, *iter, desc, true); if (exec->hadException()) return JSValue::encode(obj); } @@ -486,24 +421,27 @@ EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState* exec) return JSValue::encode(obj); } -JSObject* objectConstructorFreeze(ExecState* exec, JSObject* object) +EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState* exec) { - if (isJSFinalObject(object) && !hasIndexedProperties(object->indexingType())) { + // 1. If Type(O) is not Object throw a TypeError exception. + JSValue obj = exec->argument(0); + if (!obj.isObject()) + return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.freeze can only be called on Objects."))); + JSObject* object = asObject(obj); + + if (isJSFinalObject(object) && !hasIndexedProperties(object->structure()->indexingType())) { object->freeze(exec->vm()); - return object; + return JSValue::encode(obj); } // 2. For each named own property name P of O, - PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols); - object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include)); + PropertyNameArray properties(exec); + object->methodTable()->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties); PropertyNameArray::const_iterator end = properties.end(); for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) { - Identifier propertyName = *iter; - if (exec->propertyNames().isPrivateName(propertyName)) - continue; // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P. PropertyDescriptor desc; - if (!object->getOwnPropertyDescriptor(exec, propertyName, desc)) + if (!object->getOwnPropertyDescriptor(exec, *iter, desc)) continue; // b. If IsDataDescriptor(desc) is true, then // i. If desc.[[Writable]] is true, set desc.[[Writable]] to false. @@ -512,58 +450,46 @@ JSObject* objectConstructorFreeze(ExecState* exec, JSObject* object) // c. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false. desc.setConfigurable(false); // d. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments. - object->methodTable(exec->vm())->defineOwnProperty(object, exec, propertyName, desc, true); + object->methodTable()->defineOwnProperty(object, exec, *iter, desc, true); if (exec->hadException()) - return object; + return JSValue::encode(obj); } // 3. Set the [[Extensible]] internal property of O to false. object->preventExtensions(exec->vm()); // 4. Return O. - return object; -} - -EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState* exec) -{ - // 1. If Type(O) is not Object, return O. - JSValue obj = exec->argument(0); - if (!obj.isObject()) - return JSValue::encode(obj); - return JSValue::encode(objectConstructorFreeze(exec, asObject(obj))); + return JSValue::encode(obj); } EncodedJSValue JSC_HOST_CALL objectConstructorPreventExtensions(ExecState* exec) { JSValue obj = exec->argument(0); if (!obj.isObject()) - return JSValue::encode(obj); + return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.preventExtensions can only be called on Objects."))); asObject(obj)->preventExtensions(exec->vm()); return JSValue::encode(obj); } EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState* exec) { - // 1. If Type(O) is not Object, return true. + // 1. If Type(O) is not Object throw a TypeError exception. JSValue obj = exec->argument(0); if (!obj.isObject()) - return JSValue::encode(jsBoolean(true)); + return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.isSealed can only be called on Objects."))); JSObject* object = asObject(obj); if (isJSFinalObject(object)) return JSValue::encode(jsBoolean(object->isSealed(exec->vm()))); // 2. For each named own property name P of O, - PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols); - object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include)); + PropertyNameArray properties(exec); + object->methodTable()->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties); PropertyNameArray::const_iterator end = properties.end(); for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) { - Identifier propertyName = *iter; - if (exec->propertyNames().isPrivateName(propertyName)) - continue; // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P. PropertyDescriptor desc; - if (!object->getOwnPropertyDescriptor(exec, propertyName, desc)) + if (!object->getOwnPropertyDescriptor(exec, *iter, desc)) continue; // b. If desc.[[Configurable]] is true, then return false. if (desc.configurable()) @@ -577,26 +503,23 @@ EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState* exec) EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState* exec) { - // 1. If Type(O) is not Object, return true. + // 1. If Type(O) is not Object throw a TypeError exception. JSValue obj = exec->argument(0); if (!obj.isObject()) - return JSValue::encode(jsBoolean(true)); + return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.isFrozen can only be called on Objects."))); JSObject* object = asObject(obj); if (isJSFinalObject(object)) return JSValue::encode(jsBoolean(object->isFrozen(exec->vm()))); // 2. For each named own property name P of O, - PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols); - object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include)); + PropertyNameArray properties(exec); + object->methodTable()->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties); PropertyNameArray::const_iterator end = properties.end(); for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) { - Identifier propertyName = *iter; - if (exec->propertyNames().isPrivateName(propertyName)) - continue; // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P. PropertyDescriptor desc; - if (!object->getOwnPropertyDescriptor(exec, propertyName, desc)) + if (!object->getOwnPropertyDescriptor(exec, *iter, desc)) continue; // b. If IsDataDescriptor(desc) is true then // i. If desc.[[Writable]] is true, return false. c. If desc.[[Configurable]] is true, then return false. @@ -613,66 +536,8 @@ EncodedJSValue JSC_HOST_CALL objectConstructorIsExtensible(ExecState* exec) { JSValue obj = exec->argument(0); if (!obj.isObject()) - return JSValue::encode(jsBoolean(false)); + return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.isExtensible can only be called on Objects."))); return JSValue::encode(jsBoolean(asObject(obj)->isExtensible())); } -EncodedJSValue JSC_HOST_CALL objectConstructorIs(ExecState* exec) -{ - return JSValue::encode(jsBoolean(sameValue(exec, exec->argument(0), exec->argument(1)))); -} - -// FIXME: Use the enumeration cache. -JSArray* ownPropertyKeys(ExecState* exec, JSObject* object, PropertyNameMode propertyNameMode, DontEnumPropertiesMode dontEnumPropertiesMode) -{ - PropertyNameArray properties(exec, propertyNameMode); - object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(dontEnumPropertiesMode)); - - JSArray* keys = constructEmptyArray(exec, 0); - - switch (propertyNameMode) { - case PropertyNameMode::Strings: { - size_t numProperties = properties.size(); - for (size_t i = 0; i < numProperties; i++) { - const auto& identifier = properties[i]; - ASSERT(!identifier.isSymbol()); - keys->push(exec, jsOwnedString(exec, identifier.string())); - } - break; - } - - case PropertyNameMode::Symbols: { - size_t numProperties = properties.size(); - for (size_t i = 0; i < numProperties; i++) { - const auto& identifier = properties[i]; - ASSERT(identifier.isSymbol()); - if (!exec->propertyNames().isPrivateName(identifier)) - keys->push(exec, Symbol::create(exec->vm(), static_cast<SymbolImpl&>(*identifier.impl()))); - } - break; - } - - case PropertyNameMode::StringsAndSymbols: { - Vector<Identifier, 16> propertySymbols; - size_t numProperties = properties.size(); - for (size_t i = 0; i < numProperties; i++) { - const auto& identifier = properties[i]; - if (identifier.isSymbol()) { - if (!exec->propertyNames().isPrivateName(identifier)) - propertySymbols.append(identifier); - } else - keys->push(exec, jsOwnedString(exec, identifier.string())); - } - - // To ensure the order defined in the spec (9.1.12), we append symbols at the last elements of keys. - for (const auto& identifier : propertySymbols) - keys->push(exec, Symbol::create(exec->vm(), static_cast<SymbolImpl&>(*identifier.impl()))); - - break; - } - } - - return keys; -} - } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.h b/Source/JavaScriptCore/runtime/ObjectConstructor.h index 15b0d4dae..4a6b4711b 100644 --- a/Source/JavaScriptCore/runtime/ObjectConstructor.h +++ b/Source/JavaScriptCore/runtime/ObjectConstructor.h @@ -27,73 +27,61 @@ namespace JSC { -EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState*); -EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertySymbols(ExecState*); -EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState*); -EncodedJSValue JSC_HOST_CALL ownEnumerablePropertyKeys(ExecState*); + class ObjectPrototype; -class ObjectPrototype; + class ObjectConstructor : public InternalFunction { + public: + typedef InternalFunction Base; -class ObjectConstructor : public InternalFunction { -public: - typedef InternalFunction Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; + static ObjectConstructor* create(VM& vm, Structure* structure, ObjectPrototype* objectPrototype) + { + ObjectConstructor* constructor = new (NotNull, allocateCell<ObjectConstructor>(vm.heap)) ObjectConstructor(vm, structure); + constructor->finishCreation(vm, objectPrototype); + return constructor; + } - static ObjectConstructor* create(VM& vm, JSGlobalObject* globalObject, Structure* structure, ObjectPrototype* objectPrototype) + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + + DECLARE_INFO; + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } + + protected: + void finishCreation(VM& vm, ObjectPrototype*); + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags; + + private: + ObjectConstructor(VM&, Structure*); + static ConstructType getConstructData(JSCell*, ConstructData&); + static CallType getCallData(JSCell*, CallData&); + }; + + inline JSObject* constructEmptyObject(ExecState* exec, Structure* structure) { - ObjectConstructor* constructor = new (NotNull, allocateCell<ObjectConstructor>(vm.heap)) ObjectConstructor(vm, structure); - constructor->finishCreation(vm, globalObject, objectPrototype); - return constructor; + return JSFinalObject::create(exec, structure); } - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); - - DECLARE_INFO; + 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); + } - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + inline JSObject* constructEmptyObject(ExecState* exec, JSObject* prototype) { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + return constructEmptyObject(exec, prototype, JSFinalObject::defaultInlineCapacity()); } - JSFunction* addDefineProperty(ExecState*, JSGlobalObject*); - -protected: - void finishCreation(VM&, JSGlobalObject*, ObjectPrototype*); - -private: - ObjectConstructor(VM&, Structure*); - static ConstructType getConstructData(JSCell*, ConstructData&); - 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()); -} - -JSObject* objectConstructorFreeze(ExecState*, JSObject*); -JSValue objectConstructorGetPrototypeOf(ExecState*, JSObject*); -JSArray* ownPropertyKeys(ExecState*, JSObject*, PropertyNameMode, DontEnumPropertiesMode); -bool toPropertyDescriptor(ExecState*, JSValue, PropertyDescriptor&); + inline JSObject* constructEmptyObject(ExecState* exec) + { + return constructEmptyObject(exec, exec->lexicalGlobalObject()->objectPrototype()); + } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp index 905d0d256..9bfbe9741 100644 --- a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp @@ -25,7 +25,8 @@ #include "GetterSetter.h" #include "JSFunction.h" #include "JSString.h" -#include "JSCInlines.h" +#include "JSStringBuilder.h" +#include "Operations.h" #include "StructureRareDataInlines.h" namespace JSC { @@ -42,7 +43,7 @@ static EncodedJSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState*); STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ObjectPrototype); -const ClassInfo ObjectPrototype::s_info = { "Object", &JSNonFinalObject::s_info, 0, CREATE_METHOD_TABLE(ObjectPrototype) }; +const ClassInfo ObjectPrototype::s_info = { "Object", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(ObjectPrototype) }; ObjectPrototype::ObjectPrototype(VM& vm, Structure* stucture) : JSNonFinalObject(vm, stucture) @@ -78,22 +79,19 @@ ObjectPrototype* ObjectPrototype::create(VM& vm, JSGlobalObject* globalObject, S EncodedJSValue JSC_HOST_CALL objectProtoFuncValueOf(ExecState* exec) { - JSValue thisValue = exec->thisValue().toThis(exec, StrictMode); + JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode); return JSValue::encode(thisValue.toObject(exec)); } EncodedJSValue JSC_HOST_CALL objectProtoFuncHasOwnProperty(ExecState* exec) { - JSValue thisValue = exec->thisValue().toThis(exec, StrictMode); - auto propertyName = exec->argument(0).toPropertyKey(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - return JSValue::encode(jsBoolean(thisValue.toObject(exec)->hasOwnProperty(exec, propertyName))); + JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode); + return JSValue::encode(jsBoolean(thisValue.toObject(exec)->hasOwnProperty(exec, Identifier(exec, exec->argument(0).toString(exec)->value(exec))))); } EncodedJSValue JSC_HOST_CALL objectProtoFuncIsPrototypeOf(ExecState* exec) { - JSValue thisValue = exec->thisValue().toThis(exec, StrictMode); + JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode); JSObject* thisObj = thisValue.toObject(exec); if (!exec->argument(0).isObject()) @@ -112,7 +110,7 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncIsPrototypeOf(ExecState* exec) EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineGetter(ExecState* exec) { - JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec); + JSObject* thisObject = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); @@ -121,24 +119,18 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineGetter(ExecState* exec) if (getCallData(get, callData) == CallTypeNone) return throwVMError(exec, createTypeError(exec, ASCIILiteral("invalid getter usage"))); - auto propertyName = exec->argument(0).toPropertyKey(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - PropertyDescriptor descriptor; descriptor.setGetter(get); descriptor.setEnumerable(true); descriptor.setConfigurable(true); - - bool shouldThrow = false; - thisObject->methodTable(exec->vm())->defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow); + thisObject->methodTable()->defineOwnProperty(thisObject, exec, Identifier(exec, exec->argument(0).toString(exec)->value(exec)), descriptor, false); return JSValue::encode(jsUndefined()); } EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineSetter(ExecState* exec) { - JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec); + JSObject* thisObject = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); @@ -147,68 +139,48 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineSetter(ExecState* exec) if (getCallData(set, callData) == CallTypeNone) return throwVMError(exec, createTypeError(exec, ASCIILiteral("invalid setter usage"))); - auto propertyName = exec->argument(0).toPropertyKey(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - PropertyDescriptor descriptor; descriptor.setSetter(set); descriptor.setEnumerable(true); descriptor.setConfigurable(true); - - bool shouldThrow = false; - thisObject->methodTable(exec->vm())->defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow); + thisObject->methodTable()->defineOwnProperty(thisObject, exec, Identifier(exec, exec->argument(0).toString(exec)->value(exec)), descriptor, false); return JSValue::encode(jsUndefined()); } EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupGetter(ExecState* exec) { - JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - auto propertyName = exec->argument(0).toPropertyKey(exec); + JSObject* thisObject = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); PropertySlot slot(thisObject); - if (thisObject->getPropertySlot(exec, propertyName, slot) && slot.isAccessor()) { - GetterSetter* getterSetter = slot.getterSetter(); - return getterSetter->isGetterNull() ? JSValue::encode(jsUndefined()) : JSValue::encode(getterSetter->getter()); - } + if (thisObject->getPropertySlot(exec, Identifier(exec, exec->argument(0).toString(exec)->value(exec)), slot) + && slot.isAccessor()) + return JSValue::encode(slot.getterSetter()->getter()); return JSValue::encode(jsUndefined()); } EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState* exec) { - JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - auto propertyName = exec->argument(0).toPropertyKey(exec); + JSObject* thisObject = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); PropertySlot slot(thisObject); - if (thisObject->getPropertySlot(exec, propertyName, slot) && slot.isAccessor()) { - GetterSetter* getterSetter = slot.getterSetter(); - return getterSetter->isSetterNull() ? JSValue::encode(jsUndefined()) : JSValue::encode(getterSetter->setter()); - } + if (thisObject->getPropertySlot(exec, Identifier(exec, exec->argument(0).toString(exec)->value(exec)), slot) + && slot.isAccessor()) + return JSValue::encode(slot.getterSetter()->setter()); return JSValue::encode(jsUndefined()); } EncodedJSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState* exec) { - auto propertyName = exec->argument(0).toPropertyKey(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + JSObject* thisObject = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); + Identifier propertyName(exec, exec->argument(0).toString(exec)->value(exec)); - JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); PropertyDescriptor descriptor; bool enumerable = thisObject->getOwnPropertyDescriptor(exec, propertyName, descriptor) && descriptor.enumerable(); return JSValue::encode(jsBoolean(enumerable)); @@ -218,7 +190,7 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState* exec EncodedJSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState* exec) { // 1. Let O be the result of calling ToObject passing the this value as the argument. - JSObject* object = exec->thisValue().toThis(exec, StrictMode).toObject(exec); + JSObject* object = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); @@ -237,20 +209,19 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState* exec) EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState* exec) { - VM& vm = exec->vm(); - JSValue thisValue = exec->thisValue().toThis(exec, StrictMode); + JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode); if (thisValue.isUndefinedOrNull()) - return JSValue::encode(thisValue.isUndefined() ? vm.smallStrings.undefinedObjectString() : vm.smallStrings.nullObjectString()); + return JSValue::encode(jsNontrivialString(exec, String(thisValue.isUndefined() ? ASCIILiteral("[object Undefined]") : ASCIILiteral("[object Null]")))); JSObject* thisObject = thisValue.toObject(exec); - JSString* result = thisObject->structure(vm)->objectToStringValue(); + JSString* result = thisObject->structure()->objectToStringValue(); if (!result) { - RefPtr<StringImpl> newString = WTF::tryMakeString("[object ", thisObject->methodTable(exec->vm())->className(thisObject), "]"); + RefPtr<StringImpl> newString = WTF::tryMakeString("[object ", thisObject->methodTable()->className(thisObject), "]"); if (!newString) return JSValue::encode(throwOutOfMemoryError(exec)); - result = jsNontrivialString(&vm, newString.release()); - thisObject->structure(vm)->setObjectToStringValue(vm, result); + result = jsNontrivialString(exec, newString.release()); + 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 34238a9f4..75a2a95a1 100644 --- a/Source/JavaScriptCore/runtime/ObjectPrototype.h +++ b/Source/JavaScriptCore/runtime/ObjectPrototype.h @@ -25,27 +25,27 @@ namespace JSC { -class ObjectPrototype : public JSNonFinalObject { -public: - typedef JSNonFinalObject Base; + class ObjectPrototype : public JSNonFinalObject { + public: + typedef JSNonFinalObject Base; - static ObjectPrototype* create(VM&, JSGlobalObject*, Structure*); + static ObjectPrototype* create(VM&, JSGlobalObject*, Structure*); - DECLARE_INFO; + DECLARE_INFO; - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } -protected: - void finishCreation(VM&, JSGlobalObject*); + protected: + void finishCreation(VM&, JSGlobalObject*); -private: - ObjectPrototype(VM&, Structure*); -}; + private: + ObjectPrototype(VM&, Structure*); + }; -JS_EXPORT_PRIVATE EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState*); + JS_EXPORT_PRIVATE EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState*); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Operations.cpp b/Source/JavaScriptCore/runtime/Operations.cpp index 5732cfd0c..f0ffd5668 100644 --- a/Source/JavaScriptCore/runtime/Operations.cpp +++ b/Source/JavaScriptCore/runtime/Operations.cpp @@ -23,7 +23,6 @@ #include "Operations.h" #include "Error.h" -#include "JSCInlines.h" #include "JSObject.h" #include "JSString.h" #include <wtf/MathExtras.h> @@ -65,22 +64,15 @@ JSValue jsTypeStringForValue(VM& vm, JSGlobalObject* globalObject, JSValue v) return vm.smallStrings.numberString(); if (v.isString()) return vm.smallStrings.stringString(); - if (v.isSymbol()) - return vm.smallStrings.symbolString(); if (v.isObject()) { - JSObject* object = asObject(v); // Return "undefined" for objects that should be treated // as null when doing comparisons. - if (object->structure(vm)->masqueradesAsUndefined(globalObject)) + if (asObject(v)->structure()->masqueradesAsUndefined(globalObject)) return vm.smallStrings.undefinedString(); - if (object->type() == JSFunctionType) + CallData callData; + JSObject* object = asObject(v); + if (object->methodTable()->getCallData(object, callData) != CallTypeNone) return vm.smallStrings.functionString(); - if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) { - CallData callData; - JSObject* object = asObject(v); - if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone) - return vm.smallStrings.functionString(); - } } return vm.smallStrings.objectString(); } @@ -90,20 +82,20 @@ JSValue jsTypeStringForValue(CallFrame* callFrame, JSValue v) return jsTypeStringForValue(callFrame->vm(), callFrame->lexicalGlobalObject(), v); } -bool jsIsObjectTypeOrNull(CallFrame* callFrame, JSValue v) +bool jsIsObjectType(CallFrame* callFrame, JSValue v) { if (!v.isCell()) return v.isNull(); - JSType type = v.asCell()->type(); - if (type == StringType || type == SymbolType) + JSType type = v.asCell()->structure()->typeInfo().type(); + if (type == StringType) return false; if (type >= ObjectType) { - if (asObject(v)->structure(callFrame->vm())->masqueradesAsUndefined(callFrame->lexicalGlobalObject())) + if (asObject(v)->structure()->masqueradesAsUndefined(callFrame->lexicalGlobalObject())) return false; CallData callData; JSObject* object = asObject(v); - if (object->methodTable(callFrame->vm())->getCallData(object, callData) != CallTypeNone) + if (object->methodTable()->getCallData(object, callData) != CallTypeNone) return false; } return true; diff --git a/Source/JavaScriptCore/runtime/Operations.h b/Source/JavaScriptCore/runtime/Operations.h index 057f59471..cee00ebf4 100644 --- a/Source/JavaScriptCore/runtime/Operations.h +++ b/Source/JavaScriptCore/runtime/Operations.h @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2002, 2005, 2006, 2007, 2008, 2009, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2002, 2005, 2006, 2007, 2008, 2009, 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 Library General Public @@ -22,16 +22,23 @@ #ifndef Operations_h #define Operations_h -#include "CallFrame.h" #include "ExceptionHelpers.h" -#include "JSCJSValue.h" +#include "GCIncomingRefCountedInlines.h" +#include "Interpreter.h" +#include "JSArrayBufferViewInlines.h" +#include "JSCJSValueInlines.h" +#include "JSFunctionInlines.h" +#include "JSProxy.h" +#include "JSString.h" +#include "SlotVisitorInlines.h" +#include "StructureInlines.h" namespace JSC { NEVER_INLINE JSValue jsAddSlowCase(CallFrame*, JSValue, JSValue); JSValue jsTypeStringForValue(CallFrame*, JSValue); JSValue jsTypeStringForValue(VM&, JSGlobalObject*, JSValue); -bool jsIsObjectTypeOrNull(CallFrame*, JSValue); +bool jsIsObjectType(CallFrame*, JSValue); bool jsIsFunctionType(JSValue); ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2) @@ -194,28 +201,85 @@ ALWAYS_INLINE JSValue jsAdd(CallFrame* callFrame, JSValue v1, JSValue v2) #define InvalidPrototypeChain (std::numeric_limits<size_t>::max()) -inline size_t normalizePrototypeChain(CallFrame* callFrame, Structure* structure) +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 || slotBase != cell) { + if (cell->isProxy()) + return InvalidPrototypeChain; + + const TypeInfo& typeInfo = cell->structure()->typeInfo(); + if (typeInfo.hasImpureGetOwnPropertySlot() && !typeInfo.newImpurePropertyFiresWatchpoints()) + return InvalidPrototypeChain; + + 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 (v.isNull()) { + if (!slotBase) + return count; + return InvalidPrototypeChain; + } + + 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->vm()); + if (slotBase == cell) + slotOffset = cell->structure()->get(callFrame->vm(), propertyName); + } + + ++count; + } + + return count; +} + +inline size_t normalizePrototypeChain(CallFrame* callFrame, JSCell* base) { - VM& vm = callFrame->vm(); size_t count = 0; while (1) { - if (structure->isProxy()) + if (base->isProxy()) return InvalidPrototypeChain; - JSValue v = structure->prototypeForLookup(callFrame); + + JSValue v = base->structure()->prototypeForLookup(callFrame); if (v.isNull()) return count; - JSCell* base = v.asCell(); - structure = base->structure(vm); + 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 (structure->isDictionary()) - structure->flattenDictionaryStructure(vm, asObject(base)); + if (base->structure()->isDictionary()) + asObject(base)->flattenDictionaryObject(callFrame->vm()); ++count; } } +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; + + structure = v.asCell()->structure(); + + if (structure->isDictionary()) + return false; + } +} + } // namespace JSC #endif // Operations_h diff --git a/Source/JavaScriptCore/runtime/Options.cpp b/Source/JavaScriptCore/runtime/Options.cpp index fe830b47b..aa8ccc751 100644 --- a/Source/JavaScriptCore/runtime/Options.cpp +++ b/Source/JavaScriptCore/runtime/Options.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012, 2014-2015 Apple Inc. All rights reserved. + * 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 @@ -29,25 +29,17 @@ #include "HeapStatistics.h" #include <algorithm> #include <limits> -#include <math.h> -#include <mutex> #include <stdlib.h> #include <string.h> -#include <wtf/DataLog.h> #include <wtf/NumberOfCores.h> #include <wtf/PageBlock.h> #include <wtf/StdLibExtras.h> #include <wtf/StringExtras.h> -#include <wtf/text/StringBuilder.h> #if OS(DARWIN) && ENABLE(PARALLEL_GC) #include <sys/sysctl.h> #endif -#if OS(WINDOWS) -#include "MacroAssemblerX86.h" -#endif - namespace JSC { static bool parse(const char* string, bool& value) @@ -83,63 +75,31 @@ static bool parse(const char* string, OptionRange& value) return value.init(string); } -static bool parse(const char* string, const char*& value) -{ - if (!strlen(string)) - string = nullptr; - value = string; - return true; -} - -static bool parse(const char* string, GCLogging::Level& value) -{ - if (!strcasecmp(string, "none") || !strcasecmp(string, "no") || !strcasecmp(string, "false") || !strcmp(string, "0")) { - value = GCLogging::None; - return true; - } - - if (!strcasecmp(string, "basic") || !strcasecmp(string, "yes") || !strcasecmp(string, "true") || !strcmp(string, "1")) { - value = GCLogging::Basic; - return true; - } - - if (!strcasecmp(string, "verbose") || !strcmp(string, "2")) { - value = GCLogging::Verbose; - return true; - } - - return false; -} - template<typename T> -bool overrideOptionWithHeuristic(T& variable, const char* name) +void overrideOptionWithHeuristic(T& variable, const char* name) { +#if !OS(WINCE) const char* stringValue = getenv(name); if (!stringValue) - return false; + return; if (parse(stringValue, variable)) - return true; + return; fprintf(stderr, "WARNING: failed to parse %s=%s\n", name, stringValue); - return false; +#endif } -static unsigned computeNumberOfWorkerThreads(int maxNumberOfWorkerThreads, int minimum = 1) +static unsigned computeNumberOfWorkerThreads(int maxNumberOfWorkerThreads) { int cpusToUse = std::min(WTF::numberOfProcessorCores(), maxNumberOfWorkerThreads); // Be paranoid, it is the OS we're dealing with, after all. ASSERT(cpusToUse >= 1); - return std::max(cpusToUse, minimum); -} - -static int32_t computePriorityDeltaOfWorkerThreads(int32_t twoCorePriorityDelta, int32_t multiCorePriorityDelta) -{ - if (WTF::numberOfProcessorCores() <= 2) - return twoCorePriorityDelta; - - return multiCorePriorityDelta; + if (cpusToUse < 1) + cpusToUse = 1; + + return cpusToUse; } static unsigned computeNumberOfGCMarkers(unsigned maxNumberOfGCMarkers) @@ -152,8 +112,6 @@ static unsigned computeNumberOfGCMarkers(unsigned maxNumberOfGCMarkers) #endif } -const char* const OptionRange::s_nullRangeStr = "<null>"; - bool OptionRange::init(const char* rangeString) { // rangeString should be in the form of [!]<low>[:<high>] @@ -161,16 +119,14 @@ bool OptionRange::init(const char* rangeString) bool invert = false; + if (m_state > Uninitialized) + return true; + if (!rangeString) { m_state = InitError; return false; } - if (!strcmp(rangeString, s_nullRangeStr)) { - m_state = Uninitialized; - return true; - } - m_rangeString = rangeString; if (*rangeString == '!') { @@ -209,258 +165,69 @@ bool OptionRange::isInRange(unsigned count) return m_state == Normal ? false : true; } -void OptionRange::dump(PrintStream& out) const -{ - out.print(m_rangeString); -} - Options::Entry Options::s_options[Options::numberOfOptions]; -Options::Entry Options::s_defaultOptions[Options::numberOfOptions]; // Realize the names for each of the options: const Options::EntryInfo Options::s_optionsInfo[Options::numberOfOptions] = { -#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_) \ - { #name_, description_, Options::Type::type_##Type }, +#define FOR_EACH_OPTION(type_, name_, defaultValue_) \ + { #name_, Options::type_##Type }, JSC_OPTIONS(FOR_EACH_OPTION) #undef FOR_EACH_OPTION }; -static void scaleJITPolicy() +void Options::initialize() { - auto& scaleFactor = Options::jitPolicyScale(); - if (scaleFactor > 1.0) - scaleFactor = 1.0; - else if (scaleFactor < 0.0) - scaleFactor = 0.0; - - struct OptionToScale { - Options::OptionID id; - int32_t minVal; - }; - - static const OptionToScale optionsToScale[] = { - { Options::thresholdForJITAfterWarmUpID, 0 }, - { Options::thresholdForJITSoonID, 0 }, - { Options::thresholdForOptimizeAfterWarmUpID, 1 }, - { Options::thresholdForOptimizeAfterLongWarmUpID, 1 }, - { Options::thresholdForOptimizeSoonID, 1 }, - { Options::thresholdForFTLOptimizeSoonID, 2 }, - { Options::thresholdForFTLOptimizeAfterWarmUpID, 2 } - }; - - const int numberOfOptionsToScale = sizeof(optionsToScale) / sizeof(OptionToScale); - for (int i = 0; i < numberOfOptionsToScale; i++) { - Option option(optionsToScale[i].id); - ASSERT(option.type() == Options::Type::int32Type); - option.int32Val() *= scaleFactor; - option.int32Val() = std::max(option.int32Val(), optionsToScale[i].minVal); - } -} + // Initialize each of the options with their default values: +#define FOR_EACH_OPTION(type_, name_, defaultValue_) \ + name_() = defaultValue_; + JSC_OPTIONS(FOR_EACH_OPTION) +#undef FOR_EACH_OPTION + +#if USE(CF) || OS(UNIX) + objectsAreImmortal() = !!getenv("JSImmortalZombieEnabled"); + useZombieMode() = !!getenv("JSImmortalZombieEnabled") || !!getenv("JSZombieEnabled"); -static void recomputeDependentOptions() -{ -#if !ENABLE(JIT) - Options::useLLInt() = true; - Options::useJIT() = false; - Options::useDFGJIT() = false; - Options::useFTLJIT() = false; -#endif -#if !ENABLE(YARR_JIT) - Options::useRegExpJIT() = false; -#endif -#if !ENABLE(CONCURRENT_JIT) - Options::enableConcurrentJIT() = false; + gcMaxHeapSize() = getenv("GCMaxHeapSize") ? HeapStatistics::parseMemoryAmount(getenv("GCMaxHeapSize")) : 0; + recordGCPauseTimes() = !!getenv("JSRecordGCPauseTimes"); + logHeapStatisticsAtExit() = gcMaxHeapSize() || recordGCPauseTimes(); #endif -#if !ENABLE(DFG_JIT) - Options::useDFGJIT() = false; - Options::useFTLJIT() = false; + + // Allow environment vars to override options if applicable. + // The evn var should be the name of the option prefixed with + // "JSC_". +#define FOR_EACH_OPTION(type_, name_, defaultValue_) \ + overrideOptionWithHeuristic(name_(), "JSC_" #name_); + JSC_OPTIONS(FOR_EACH_OPTION) +#undef FOR_EACH_OPTION + +#if 0 + ; // Deconfuse editors that do auto indentation #endif -#if !ENABLE(FTL_JIT) - Options::useFTLJIT() = false; + +#if !ENABLE(JIT) + useJIT() = false; + useDFGJIT() = false; #endif -#if OS(WINDOWS) && CPU(X86) - // Disable JIT on Windows if SSE2 is not present - if (!MacroAssemblerX86::supportsFloatingPoint()) - Options::useJIT() = false; +#if !ENABLE(YARR_JIT) + useRegExpJIT() = false; #endif - if (Options::showDisassembly() - || Options::showDFGDisassembly() - || Options::showFTLDisassembly() - || Options::dumpBytecodeAtDFGTime() - || Options::dumpGraphAtEachPhase() - || Options::verboseCompilation() - || Options::verboseFTLCompilation() - || Options::logCompilationChanges() - || Options::validateGraph() - || Options::validateGraphAtEachPhase() - || Options::verboseOSR() - || Options::verboseCompilationQueue() - || Options::reportCompileTimes() - || Options::reportFTLCompileTimes() - || Options::verboseCFA() - || Options::verboseFTLFailure()) - Options::alwaysComputeHash() = true; - - if (Option(Options::jitPolicyScaleID).isOverridden()) - scaleJITPolicy(); - - if (Options::forceEagerCompilation()) { - Options::thresholdForJITAfterWarmUp() = 10; - Options::thresholdForJITSoon() = 10; - Options::thresholdForOptimizeAfterWarmUp() = 20; - Options::thresholdForOptimizeAfterLongWarmUp() = 20; - Options::thresholdForOptimizeSoon() = 20; - Options::thresholdForFTLOptimizeAfterWarmUp() = 20; - Options::thresholdForFTLOptimizeSoon() = 20; - Options::maximumEvalCacheableSourceLength() = 150000; - Options::enableConcurrentJIT() = false; - } + + // Do range checks where needed and make corrections to the options: + ASSERT(thresholdForOptimizeAfterLongWarmUp() >= thresholdForOptimizeAfterWarmUp()); + ASSERT(thresholdForOptimizeAfterWarmUp() >= thresholdForOptimizeSoon()); + ASSERT(thresholdForOptimizeAfterWarmUp() >= 0); // Compute the maximum value of the reoptimization retry counter. This is simply // the largest value at which we don't overflow the execute counter, when using it // to left-shift the execution counter by this amount. Currently the value ends // up being 18, so this loop is not so terrible; it probably takes up ~100 cycles // total on a 32-bit processor. - Options::reoptimizationRetryCounterMax() = 0; - while ((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << (Options::reoptimizationRetryCounterMax() + 1)) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max())) - Options::reoptimizationRetryCounterMax()++; + reoptimizationRetryCounterMax() = 0; + while ((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp()) << (reoptimizationRetryCounterMax() + 1)) <= static_cast<int64_t>(std::numeric_limits<int32>::max())) + reoptimizationRetryCounterMax()++; - ASSERT((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << Options::reoptimizationRetryCounterMax()) > 0); - ASSERT((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << Options::reoptimizationRetryCounterMax()) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max())); -} - -void Options::initialize() -{ - static std::once_flag initializeOptionsOnceFlag; - - std::call_once( - initializeOptionsOnceFlag, - [] { - // Initialize each of the options with their default values: -#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_) \ - name_() = defaultValue_; \ - name_##Default() = defaultValue_; - JSC_OPTIONS(FOR_EACH_OPTION) -#undef FOR_EACH_OPTION - - // It *probably* makes sense for other platforms to enable this. -#if PLATFORM(IOS) && CPU(ARM64) - enableLLVMFastISel() = true; -#endif - - // Allow environment vars to override options if applicable. - // The evn var should be the name of the option prefixed with - // "JSC_". -#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_) \ - overrideOptionWithHeuristic(name_(), "JSC_" #name_); - JSC_OPTIONS(FOR_EACH_OPTION) -#undef FOR_EACH_OPTION - -#if 0 - ; // Deconfuse editors that do auto indentation -#endif - - recomputeDependentOptions(); - - // Do range checks where needed and make corrections to the options: - ASSERT(Options::thresholdForOptimizeAfterLongWarmUp() >= Options::thresholdForOptimizeAfterWarmUp()); - ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= Options::thresholdForOptimizeSoon()); - ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= 0); - - dumpOptionsIfNeeded(); - ensureOptionsAreCoherent(); - }); -} - -void Options::dumpOptionsIfNeeded() -{ - if (Options::showOptions()) { - DumpLevel level = static_cast<DumpLevel>(Options::showOptions()); - if (level > DumpLevel::Verbose) - level = DumpLevel::Verbose; - - const char* title = nullptr; - switch (level) { - case DumpLevel::None: - break; - case DumpLevel::Overridden: - title = "Overridden JSC options:"; - break; - case DumpLevel::All: - title = "All JSC options:"; - break; - case DumpLevel::Verbose: - title = "All JSC options with descriptions:"; - break; - } - - StringBuilder builder; - dumpAllOptions(builder, level, title, nullptr, " ", "\n", ShowDefaults); - dataLog(builder.toString()); - } -} - -bool Options::setOptions(const char* optionsStr) -{ - Vector<char*> options; - - size_t length = strlen(optionsStr); - char* optionsStrCopy = WTF::fastStrDup(optionsStr); - char* end = optionsStrCopy + length; - char* p = optionsStrCopy; - - while (p < end) { - char* optionStart = p; - p = strstr(p, "="); - if (!p) { - dataLogF("'=' not found in option string: %p\n", optionStart); - return false; - } - p++; - - char* valueBegin = p; - bool hasStringValue = false; - const int minStringLength = 2; // The min is an empty string i.e. 2 double quotes. - if ((p + minStringLength < end) && (*p == '"')) { - p = strstr(p + 1, "\""); - if (!p) { - dataLogF("Missing trailing '\"' in option string: %p\n", optionStart); - return false; // End of string not found. - } - hasStringValue = true; - } - - p = strstr(p, " "); - if (!p) - p = end; // No more " " separator. Hence, this is the last arg. - - // If we have a well-formed string value, strip the quotes. - if (hasStringValue) { - char* valueEnd = p; - ASSERT((*valueBegin == '"') && ((valueEnd - valueBegin) >= minStringLength) && (valueEnd[-1] == '"')); - memmove(valueBegin, valueBegin + 1, valueEnd - valueBegin - minStringLength); - valueEnd[-minStringLength] = '\0'; - } - - // Strip leading -- if present. - if ((p - optionStart > 2) && optionStart[0] == '-' && optionStart[1] == '-') - optionStart += 2; - - *p++ = '\0'; - options.append(optionStart); - } - - bool success = true; - for (auto& option : options) { - bool optionSuccess = setOption(option); - if (!optionSuccess) { - dataLogF("Failed to set option : %s\n", option); - success = false; - } - } - - dumpOptionsIfNeeded(); - return success; + ASSERT((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp()) << reoptimizationRetryCounterMax()) > 0); + ASSERT((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp()) << reoptimizationRetryCounterMax()) <= static_cast<int64_t>(std::numeric_limits<int32>::max())); } // Parses a single command line option in the format "<optionName>=<value>" @@ -477,151 +244,55 @@ bool Options::setOption(const char* arg) // For each option, check if the specify arg is a match. If so, set the arg // if the value makes sense. Otherwise, move on to checking the next option. -#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_) \ - if (strlen(#name_) == static_cast<size_t>(equalStr - arg) \ - && !strncmp(arg, #name_, equalStr - arg)) { \ - type_ value; \ - value = (defaultValue_); \ - bool success = parse(valueStr, value); \ - if (success) { \ - name_() = value; \ - recomputeDependentOptions(); \ - return true; \ - } \ - return false; \ +#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; \ + return true; \ + } \ + return false; \ } JSC_OPTIONS(FOR_EACH_OPTION) #undef FOR_EACH_OPTION - return false; // No option matched. -} - -void Options::dumpAllOptions(StringBuilder& builder, DumpLevel level, const char* title, - const char* separator, const char* optionHeader, const char* optionFooter, ShowDefaultsOption showDefaultsOption) -{ - if (title) { - builder.append(title); - builder.append('\n'); - } - - for (int id = 0; id < numberOfOptions; id++) { - if (separator && id) - builder.append(separator); - dumpOption(builder, level, static_cast<OptionID>(id), optionHeader, optionFooter, showDefaultsOption); - } -} - -void Options::dumpAllOptionsInALine(StringBuilder& builder) -{ - dumpAllOptions(builder, DumpLevel::All, nullptr, " ", nullptr, nullptr, DontShowDefaults); + return false; // No option matched. } -void Options::dumpAllOptions(FILE* stream, DumpLevel level, const char* title) +void Options::dumpAllOptions(FILE* stream) { - StringBuilder builder; - dumpAllOptions(builder, level, title, nullptr, " ", "\n", ShowDefaults); - fprintf(stream, "%s", builder.toString().ascii().data()); + fprintf(stream, "JSC runtime options:\n"); + for (int id = 0; id < numberOfOptions; id++) + dumpOption(static_cast<OptionID>(id), stream, " ", "\n"); } -void Options::dumpOption(StringBuilder& builder, DumpLevel level, OptionID id, - const char* header, const char* footer, ShowDefaultsOption showDefaultsOption) +void Options::dumpOption(OptionID id, FILE* stream, const char* header, const char* footer) { if (id >= numberOfOptions) return; // Illegal option. - Option option(id); - bool wasOverridden = option.isOverridden(); - bool needsDescription = (level == DumpLevel::Verbose && option.description()); - - if (level == DumpLevel::Overridden && !wasOverridden) - return; - - if (header) - builder.append(header); - builder.append(option.name()); - builder.append('='); - option.dump(builder); - - if (wasOverridden && (showDefaultsOption == ShowDefaults)) { - builder.append(" (default: "); - option.defaultOption().dump(builder); - builder.append(")"); - } - - if (needsDescription) { - builder.append(" ... "); - builder.append(option.description()); - } - - builder.append(footer); -} - -void Options::ensureOptionsAreCoherent() -{ - bool coherent = true; - if (!(useLLInt() || useJIT())) { - coherent = false; - dataLog("INCOHERENT OPTIONS: at least one of useLLInt or useJIT must be true\n"); - } - if (!coherent) - CRASH(); -} - -void Option::dump(StringBuilder& builder) const -{ - switch (type()) { - case Options::Type::boolType: - builder.append(m_entry.boolVal ? "true" : "false"); + fprintf(stream, "%s%s: ", header, s_optionsInfo[id].name); + switch (s_optionsInfo[id].type) { + case boolType: + fprintf(stream, "%s", s_options[id].u.boolVal?"true":"false"); break; - case Options::Type::unsignedType: - builder.appendNumber(m_entry.unsignedVal); + case unsignedType: + fprintf(stream, "%u", s_options[id].u.unsignedVal); break; - case Options::Type::doubleType: - builder.appendNumber(m_entry.doubleVal); + case doubleType: + fprintf(stream, "%lf", s_options[id].u.doubleVal); break; - case Options::Type::int32Type: - builder.appendNumber(m_entry.int32Val); + case int32Type: + fprintf(stream, "%d", s_options[id].u.int32Val); break; - case Options::Type::optionRangeType: - builder.append(m_entry.optionRangeVal.rangeString()); - break; - case Options::Type::optionStringType: { - const char* option = m_entry.optionStringVal; - if (!option) - option = ""; - builder.append('"'); - builder.append(option); - builder.append('"'); + case optionRangeType: + fprintf(stream, "%s", s_options[id].u.optionRangeVal.rangeString()); break; } - case Options::Type::gcLogLevelType: { - builder.append(GCLogging::levelAsString(m_entry.gcLogLevelVal)); - break; - } - } -} - -bool Option::operator==(const Option& other) const -{ - switch (type()) { - case Options::Type::boolType: - return m_entry.boolVal == other.m_entry.boolVal; - case Options::Type::unsignedType: - return m_entry.unsignedVal == other.m_entry.unsignedVal; - case Options::Type::doubleType: - return (m_entry.doubleVal == other.m_entry.doubleVal) || (isnan(m_entry.doubleVal) && isnan(other.m_entry.doubleVal)); - case Options::Type::int32Type: - return m_entry.int32Val == other.m_entry.int32Val; - case Options::Type::optionRangeType: - return m_entry.optionRangeVal.rangeString() == other.m_entry.optionRangeVal.rangeString(); - case Options::Type::optionStringType: - return (m_entry.optionStringVal == other.m_entry.optionStringVal) - || (m_entry.optionStringVal && other.m_entry.optionStringVal && !strcmp(m_entry.optionStringVal, other.m_entry.optionStringVal)); - case Options::Type::gcLogLevelType: - return m_entry.gcLogLevelVal == other.m_entry.gcLogLevelVal; - } - return false; + fprintf(stream, "%s", footer); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Options.h b/Source/JavaScriptCore/runtime/Options.h index 1a6555ed6..c88b3ac6c 100644 --- a/Source/JavaScriptCore/runtime/Options.h +++ b/Source/JavaScriptCore/runtime/Options.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2015 Apple Inc. All rights reserved. + * Copyright (C) 2011, 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,17 +26,9 @@ #ifndef Options_h #define Options_h -#include "GCLogging.h" #include "JSExportMacros.h" #include <stdint.h> #include <stdio.h> -#include <wtf/PrintStream.h> -#include <wtf/StdLibExtras.h> - -namespace WTF { -class StringBuilder; -} -using WTF::StringBuilder; namespace JSC { @@ -85,13 +77,9 @@ public: bool init(const char*); bool isInRange(unsigned); - const char* rangeString() const { return (m_state > InitError) ? m_rangeString : s_nullRangeStr; } - - void dump(PrintStream& out) const; + const char* rangeString() { return (m_state > InitError) ? m_rangeString : "<null>"; } private: - static const char* const s_nullRangeStr; - RangeState m_state; const char* m_rangeString; unsigned m_lowLimit; @@ -99,432 +87,203 @@ private: }; typedef OptionRange optionRange; -typedef const char* optionString; #define JSC_OPTIONS(v) \ - v(unsigned, showOptions, 0, "shows JSC options (0 = None, 1 = Overridden only, 2 = All, 3 = Verbose)") \ - \ - v(bool, useLLInt, true, "allows the LLINT to be used if true") \ - v(bool, useJIT, true, "allows the baseline JIT to be used if true") \ - v(bool, useDFGJIT, true, "allows the DFG JIT to be used if true") \ - v(bool, useRegExpJIT, true, "allows the RegExp JIT to be used if true") \ - \ - v(bool, reportMustSucceedExecutableAllocations, false, nullptr) \ - \ - v(unsigned, maxPerThreadStackUsage, 4 * MB, nullptr) \ - v(unsigned, reservedZoneSize, 128 * KB, nullptr) \ - v(unsigned, errorModeReservedZoneSize, 64 * KB, nullptr) \ + v(bool, useLLInt, true) \ + v(bool, useJIT, true) \ + v(bool, useDFGJIT, true) \ + v(bool, useRegExpJIT, true) \ \ - v(bool, crashIfCantAllocateJITMemory, false, nullptr) \ - v(unsigned, jitMemoryReservationSize, 0, nullptr) \ + v(bool, crashIfCantAllocateJITMemory, false) \ \ - v(bool, forceDFGCodeBlockLiveness, false, nullptr) \ - v(bool, forceICFailure, false, nullptr) \ + v(bool, forceDFGCodeBlockLiveness, false) \ \ - v(bool, dumpGeneratedBytecodes, false, nullptr) \ - v(bool, dumpBytecodeLivenessResults, false, nullptr) \ - v(bool, validateBytecode, false, nullptr) \ - v(bool, forceDebuggerBytecodeGeneration, false, nullptr) \ - v(bool, forceProfilerBytecodeGeneration, false, nullptr) \ - \ - v(bool, enableFunctionDotArguments, true, nullptr) \ + v(bool, dumpGeneratedBytecodes, false) \ + v(bool, dumpBytecodeLivenessResults, false) \ + v(bool, validateBytecode, false) \ \ /* showDisassembly implies showDFGDisassembly. */ \ - v(bool, showDisassembly, false, "dumps disassembly of all JIT compiled code upon compilation") \ - v(bool, asyncDisassembly, false, nullptr) \ - v(bool, showDFGDisassembly, false, "dumps disassembly of DFG function upon compilation") \ - v(bool, showFTLDisassembly, false, "dumps disassembly of FTL function upon compilation") \ - v(bool, showAllDFGNodes, false, nullptr) \ - v(optionRange, bytecodeRangeToDFGCompile, 0, "bytecode size range to allow DFG compilation on, e.g. 1:100") \ - v(optionString, dfgWhitelist, nullptr, "file with list of function signatures to allow DFG compilation on") \ - v(bool, dumpSourceAtDFGTime, false, "dumps source code of JS function being DFG compiled") \ - v(bool, dumpBytecodeAtDFGTime, false, "dumps bytecode of JS function being DFG compiled") \ - v(bool, dumpGraphAfterParsing, false, nullptr) \ - v(bool, dumpGraphAtEachPhase, false, nullptr) \ - v(bool, verboseDFGByteCodeParsing, false, nullptr) \ - v(bool, verboseCompilation, false, nullptr) \ - v(bool, verboseFTLCompilation, false, nullptr) \ - v(bool, logCompilationChanges, false, nullptr) \ - v(bool, printEachOSRExit, false, nullptr) \ - v(bool, validateGraph, false, nullptr) \ - v(bool, validateGraphAtEachPhase, false, nullptr) \ - v(bool, verboseValidationFailure, false, nullptr) \ - v(bool, verboseOSR, false, nullptr) \ - v(bool, verboseFTLOSRExit, false, nullptr) \ - v(bool, verboseCallLink, false, nullptr) \ - v(bool, verboseCompilationQueue, false, nullptr) \ - v(bool, reportCompileTimes, false, "dumps JS function signature and the time it took to compile") \ - v(bool, reportFTLCompileTimes, false, "dumps JS function signature and the time it took to FTL compile") \ - v(bool, reportTotalCompileTimes, false, nullptr) \ - v(bool, verboseCFA, false, nullptr) \ - v(bool, verboseFTLToJSThunk, false, nullptr) \ - v(bool, verboseFTLFailure, false, nullptr) \ - v(bool, alwaysComputeHash, false, nullptr) \ - v(bool, testTheFTL, false, nullptr) \ - v(bool, verboseSanitizeStack, false, nullptr) \ - v(bool, alwaysDoFullCollection, false, nullptr) \ - v(bool, eagerlyUpdateTopCallFrame, false, nullptr) \ - \ - v(bool, enableOSREntryToDFG, true, nullptr) \ - v(bool, enableOSREntryToFTL, true, nullptr) \ - \ - v(bool, useFTLJIT, true, "allows the FTL JIT to be used if true") \ - v(bool, useFTLTBAA, true, nullptr) \ - v(bool, enableLLVMFastISel, false, nullptr) \ - v(bool, useLLVMSmallCodeModel, false, nullptr) \ - v(bool, dumpLLVMIR, false, nullptr) \ - v(bool, validateFTLOSRExitLiveness, false, nullptr) \ - v(bool, llvmAlwaysFailsBeforeCompile, false, nullptr) \ - v(bool, llvmAlwaysFailsBeforeLink, false, nullptr) \ - v(bool, llvmSimpleOpt, true, nullptr) \ - v(unsigned, llvmBackendOptimizationLevel, 2, nullptr) \ - v(unsigned, llvmOptimizationLevel, 2, nullptr) \ - v(unsigned, llvmSizeLevel, 0, nullptr) \ - v(unsigned, llvmMaxStackSize, 128 * KB, nullptr) \ - v(bool, llvmDisallowAVX, true, nullptr) \ - v(bool, ftlCrashes, false, nullptr) /* fool-proof way of checking that you ended up in the FTL. ;-) */\ - v(bool, ftlCrashesIfCantInitializeLLVM, false, nullptr) \ - v(bool, clobberAllRegsInFTLICSlowPath, !ASSERT_DISABLED, nullptr) \ - v(bool, assumeAllRegsInFTLICAreLive, false, nullptr) \ - v(bool, enableAccessInlining, true, nullptr) \ - v(bool, enablePolyvariantDevirtualization, true, nullptr) \ - v(bool, enablePolymorphicAccessInlining, true, nullptr) \ - v(bool, enablePolymorphicCallInlining, true, nullptr) \ - v(unsigned, maxPolymorphicCallVariantListSize, 15, nullptr) \ - v(unsigned, maxPolymorphicCallVariantListSizeForTopTier, 5, nullptr) \ - v(unsigned, maxPolymorphicCallVariantsForInlining, 5, nullptr) \ - v(unsigned, frequentCallThreshold, 2, nullptr) \ - v(double, minimumCallToKnownRate, 0.51, nullptr) \ - v(bool, enableMovHintRemoval, true, nullptr) \ - v(bool, enableObjectAllocationSinking, true, nullptr) \ - \ - v(bool, enableConcurrentJIT, true, "allows the DFG / FTL compilation in threads other than the executing JS thread") \ - v(unsigned, numberOfDFGCompilerThreads, computeNumberOfWorkerThreads(2, 2) - 1, nullptr) \ - v(unsigned, numberOfFTLCompilerThreads, computeNumberOfWorkerThreads(8, 2) - 1, nullptr) \ - v(int32, priorityDeltaOfDFGCompilerThreads, computePriorityDeltaOfWorkerThreads(-1, 0), nullptr) \ - v(int32, priorityDeltaOfFTLCompilerThreads, computePriorityDeltaOfWorkerThreads(-2, 0), nullptr) \ - \ - v(bool, enableProfiler, false, nullptr) \ - \ - v(bool, forceUDis86Disassembler, false, nullptr) \ - v(bool, forceLLVMDisassembler, false, nullptr) \ - \ - v(bool, enableArchitectureSpecificOptimizations, true, nullptr) \ - \ - v(bool, breakOnThrow, false, nullptr) \ - \ - v(unsigned, maximumOptimizationCandidateInstructionCount, 100000, nullptr) \ - \ - v(unsigned, maximumFunctionForCallInlineCandidateInstructionCount, 180, nullptr) \ - v(unsigned, maximumFunctionForClosureCallInlineCandidateInstructionCount, 100, nullptr) \ - v(unsigned, maximumFunctionForConstructInlineCandidateInstructionCount, 100, nullptr) \ - \ - v(unsigned, maximumFTLCandidateInstructionCount, 20000, nullptr) \ + 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, verboseOSR, false) \ + v(bool, verboseCallLink, false) \ + v(bool, verboseCompilationQueue, false) \ + v(bool, reportCompileTimes, false) \ + v(bool, verboseCFA, false) \ + \ + v(bool, enableOSREntryInLoops, true) \ + \ + v(bool, useExperimentalFTL, false) \ + v(bool, useFTLTBAA, true) \ + v(bool, enableLLVMFastISel, false) \ + v(bool, useLLVMSmallCodeModel, false) \ + v(bool, dumpLLVMIR, false) \ + v(bool, validateFTLOSRExitLiveness, false) \ + v(bool, llvmAlwaysFailsBeforeCompile, false) \ + v(bool, llvmAlwaysFailsBeforeLink, false) \ + v(bool, llvmSimpleOpt, true) \ + v(unsigned, llvmBackendOptimizationLevel, 2) \ + v(unsigned, llvmOptimizationLevel, 2) \ + v(unsigned, llvmSizeLevel, 0) \ + v(bool, ftlCrashes, false) /* fool-proof way of checking that you ended up in the FTL. ;-) */\ + \ + v(bool, enableConcurrentJIT, true) \ + v(unsigned, numberOfCompilerThreads, computeNumberOfWorkerThreads(2) - 1) \ + \ + v(bool, enableProfiler, false) \ + \ + v(bool, forceUDis86Disassembler, false) \ + v(bool, forceLLVMDisassembler, false) \ + \ + v(bool, enableArchitectureSpecificOptimizations, true) \ + \ + 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. */ \ - v(unsigned, maximumInliningDepth, 5, "maximum allowed inlining depth. Depth of 1 means no inlining") \ - v(unsigned, maximumInliningRecursion, 2, nullptr) \ - \ - v(unsigned, maximumLLVMInstructionCountForNativeInlining, 80, nullptr) \ + v(unsigned, maximumInliningDepth, 5) \ \ - /* Maximum size of a caller for enabling inlining. This is purely to protect us */\ - /* from super long compiles that take a lot of memory. */\ - v(unsigned, maximumInliningCallerSize, 10000, nullptr) \ + v(unsigned, maximumBinaryStringSwitchCaseLength, 50) \ + v(unsigned, maximumBinaryStringSwitchTotalLength, 2000) \ \ - v(unsigned, maximumVarargsForInlining, 100, nullptr) \ + v(int32, thresholdForJITAfterWarmUp, 100) \ + v(int32, thresholdForJITSoon, 100) \ \ - v(bool, enablePolyvariantCallInlining, true, nullptr) \ - v(bool, enablePolyvariantByIdInlining, true, nullptr) \ + v(int32, thresholdForOptimizeAfterWarmUp, 1000) \ + v(int32, thresholdForOptimizeAfterLongWarmUp, 1000) \ + v(int32, thresholdForOptimizeSoon, 1000) \ + v(int32, executionCounterIncrementForLoop, 1) \ + v(int32, executionCounterIncrementForEntry, 15) \ \ - v(unsigned, maximumBinaryStringSwitchCaseLength, 50, nullptr) \ - v(unsigned, maximumBinaryStringSwitchTotalLength, 2000, nullptr) \ + v(int32, thresholdForFTLOptimizeAfterWarmUp, 25000) \ + v(int32, thresholdForFTLOptimizeSoon, 1000) \ + v(int32, ftlTierUpCounterIncrementForLoop, 1) \ + v(int32, ftlTierUpCounterIncrementForReturn, 15) \ + v(unsigned, ftlOSREntryFailureCountForReoptimization, 15) \ \ - v(double, jitPolicyScale, 1.0, "scale JIT thresholds to this specified ratio between 0.0 (compile ASAP) and 1.0 (compile like normal).") \ - v(bool, forceEagerCompilation, false, nullptr) \ - v(int32, thresholdForJITAfterWarmUp, 500, nullptr) \ - v(int32, thresholdForJITSoon, 100, nullptr) \ + v(int32, evalThresholdMultiplier, 10) \ \ - v(int32, thresholdForOptimizeAfterWarmUp, 1000, nullptr) \ - v(int32, thresholdForOptimizeAfterLongWarmUp, 1000, nullptr) \ - v(int32, thresholdForOptimizeSoon, 1000, nullptr) \ - v(int32, executionCounterIncrementForLoop, 1, nullptr) \ - v(int32, executionCounterIncrementForEntry, 15, nullptr) \ + v(bool, randomizeExecutionCountsBetweenCheckpoints, false) \ + v(int32, maximumExecutionCountsBetweenCheckpoints, 1000) \ \ - v(int32, thresholdForFTLOptimizeAfterWarmUp, 100000, nullptr) \ - v(int32, thresholdForFTLOptimizeSoon, 1000, nullptr) \ - v(int32, ftlTierUpCounterIncrementForLoop, 1, nullptr) \ - v(int32, ftlTierUpCounterIncrementForReturn, 15, nullptr) \ - v(unsigned, ftlOSREntryFailureCountForReoptimization, 15, nullptr) \ - v(unsigned, ftlOSREntryRetryThreshold, 100, nullptr) \ + v(unsigned, likelyToTakeSlowCaseMinimumCount, 100) \ + v(unsigned, couldTakeSlowCaseMinimumCount, 10) \ \ - v(int32, evalThresholdMultiplier, 10, nullptr) \ - v(unsigned, maximumEvalCacheableSourceLength, 256, nullptr) \ + v(unsigned, osrExitCountForReoptimization, 100) \ + v(unsigned, osrExitCountForReoptimizationFromLoop, 5) \ \ - v(bool, randomizeExecutionCountsBetweenCheckpoints, false, nullptr) \ - v(int32, maximumExecutionCountsBetweenCheckpointsForBaseline, 1000, nullptr) \ - v(int32, maximumExecutionCountsBetweenCheckpointsForUpperTiers, 50000, nullptr) \ + v(unsigned, reoptimizationRetryCounterMax, 0) \ + v(unsigned, reoptimizationRetryCounterStep, 1) \ \ - v(unsigned, likelyToTakeSlowCaseMinimumCount, 20, nullptr) \ - v(unsigned, couldTakeSlowCaseMinimumCount, 10, nullptr) \ + v(unsigned, minimumOptimizationDelay, 1) \ + v(unsigned, maximumOptimizationDelay, 5) \ + v(double, desiredProfileLivenessRate, 0.75) \ + v(double, desiredProfileFullnessRate, 0.35) \ \ - v(unsigned, osrExitCountForReoptimization, 100, nullptr) \ - v(unsigned, osrExitCountForReoptimizationFromLoop, 5, nullptr) \ + v(double, doubleVoteRatioForDoubleFormat, 2) \ + v(double, structureCheckVoteRatioForHoisting, 1) \ + v(double, checkArrayVoteRatioForHoisting, 1) \ \ - v(unsigned, reoptimizationRetryCounterMax, 0, nullptr) \ + v(unsigned, minimumNumberOfScansBetweenRebalance, 100) \ + v(unsigned, numberOfGCMarkers, computeNumberOfGCMarkers(7)) \ + v(unsigned, opaqueRootMergeThreshold, 1000) \ + v(double, minHeapUtilization, 0.8) \ + v(double, minCopiedBlockUtilization, 0.9) \ \ - v(unsigned, minimumOptimizationDelay, 1, nullptr) \ - v(unsigned, maximumOptimizationDelay, 5, nullptr) \ - v(double, desiredProfileLivenessRate, 0.75, nullptr) \ - v(double, desiredProfileFullnessRate, 0.35, nullptr) \ + v(bool, forceWeakRandomSeed, false) \ + v(unsigned, forcedWeakRandomSeed, 0) \ \ - v(double, doubleVoteRatioForDoubleFormat, 2, nullptr) \ - v(double, structureCheckVoteRatioForHoisting, 1, nullptr) \ - v(double, checkArrayVoteRatioForHoisting, 1, nullptr) \ + v(bool, useZombieMode, false) \ + v(bool, objectsAreImmortal, false) \ + v(bool, showObjectStatistics, false) \ \ - v(unsigned, minimumNumberOfScansBetweenRebalance, 100, nullptr) \ - v(unsigned, numberOfGCMarkers, computeNumberOfGCMarkers(7), nullptr) \ - v(unsigned, opaqueRootMergeThreshold, 1000, nullptr) \ - v(double, minHeapUtilization, 0.8, nullptr) \ - v(double, minCopiedBlockUtilization, 0.9, nullptr) \ - v(double, minMarkedBlockUtilization, 0.9, nullptr) \ - v(unsigned, slowPathAllocsBetweenGCs, 0, "force a GC on every Nth slow path alloc, where N is specified by this option") \ - \ - v(double, percentCPUPerMBForFullTimer, 0.0003125, nullptr) \ - v(double, percentCPUPerMBForEdenTimer, 0.0025, nullptr) \ - v(double, collectionTimerMaxPercentCPU, 0.05, nullptr) \ - \ - v(bool, forceWeakRandomSeed, false, nullptr) \ - v(unsigned, forcedWeakRandomSeed, 0, nullptr) \ - \ - v(bool, useZombieMode, false, "debugging option to scribble over dead objects with 0xdeadbeef") \ - v(bool, objectsAreImmortal, false, "debugging option to keep all objects alive forever") \ - v(bool, showObjectStatistics, false, nullptr) \ - \ - v(gcLogLevel, logGC, GCLogging::None, "debugging option to log GC activity (0 = None, 1 = Basic, 2 = Verbose)") \ - v(bool, disableGC, false, nullptr) \ - v(unsigned, gcMaxHeapSize, 0, nullptr) \ - v(unsigned, forceRAMSize, 0, nullptr) \ - v(bool, recordGCPauseTimes, false, nullptr) \ - v(bool, logHeapStatisticsAtExit, false, nullptr) \ - v(bool, enableTypeProfiler, false, nullptr) \ - v(bool, enableControlFlowProfiler, false, nullptr) \ - \ - v(bool, verifyHeap, false, nullptr) \ - v(unsigned, numberOfGCCyclesToRecordForVerification, 3, nullptr) \ - \ - v(bool, enableExceptionFuzz, false, nullptr) \ - v(unsigned, fireExceptionFuzzAt, 0, nullptr) \ - \ - v(bool, enableExecutableAllocationFuzz, false, nullptr) \ - v(unsigned, fireExecutableAllocationFuzzAt, 0, nullptr) \ - v(unsigned, fireExecutableAllocationFuzzAtOrAfter, 0, nullptr) \ - v(bool, verboseExecutableAllocationFuzz, false, nullptr) \ - \ - v(bool, enableOSRExitFuzz, false, nullptr) \ - v(unsigned, fireOSRExitFuzzAtStatic, 0, nullptr) \ - v(unsigned, fireOSRExitFuzzAt, 0, nullptr) \ - v(unsigned, fireOSRExitFuzzAtOrAfter, 0, nullptr) \ - \ - v(bool, enableDollarVM, false, "installs the $vm debugging tool in global objects") \ - v(optionString, functionOverrides, nullptr, "file with debugging overrides for function bodies") \ - \ - v(unsigned, watchdog, 0, "watchdog timeout (0 = Disabled, N = a timeout period of N milliseconds)") \ - \ - v(bool, dumpModuleRecord, false, nullptr) \ + v(bool, logGC, false) \ + v(unsigned, gcMaxHeapSize, 0) \ + v(bool, recordGCPauseTimes, false) \ + v(bool, logHeapStatisticsAtExit, false) class Options { public: - enum class DumpLevel { - None = 0, - Overridden, - All, - Verbose - }; - // This typedef is to allow us to eliminate the '_' in the field name in // union inside Entry. This is needed to keep the style checker happy. typedef int32_t int32; // Declare the option IDs: enum OptionID { -#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_) \ - name_##ID, +#define FOR_EACH_OPTION(type_, name_, defaultValue_) \ + OPT_##name_, JSC_OPTIONS(FOR_EACH_OPTION) #undef FOR_EACH_OPTION numberOfOptions }; - enum class Type { - boolType, - unsignedType, - doubleType, - int32Type, - optionRangeType, - optionStringType, - gcLogLevelType, - }; - - JS_EXPORT_PRIVATE static void initialize(); - // Parses a string of options where each option is of the format "--<optionName>=<value>" - // and are separated by a space. The leading "--" is optional and will be ignored. - JS_EXPORT_PRIVATE static bool setOptions(const char* optionsList); + static void initialize(); // Parses a single command line option in the format "<optionName>=<value>" // (no spaces allowed) and set the specified option if appropriate. JS_EXPORT_PRIVATE static bool setOption(const char* arg); - - JS_EXPORT_PRIVATE static void dumpAllOptions(FILE*, DumpLevel, const char* title = nullptr); - JS_EXPORT_PRIVATE static void dumpAllOptionsInALine(StringBuilder&); - - JS_EXPORT_PRIVATE static void ensureOptionsAreCoherent(); + JS_EXPORT_PRIVATE static void dumpAllOptions(FILE* stream = stdout); + static void dumpOption(OptionID id, FILE* stream = stdout, const char* header = "", const char* footer = ""); // Declare accessors for each option: -#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_) \ - ALWAYS_INLINE static type_& name_() { return s_options[name_##ID].type_##Val; } \ - ALWAYS_INLINE static type_& name_##Default() { return s_defaultOptions[name_##ID].type_##Val; } +#define FOR_EACH_OPTION(type_, name_, defaultValue_) \ + ALWAYS_INLINE static type_& name_() { return s_options[OPT_##name_].u.type_##Val; } JSC_OPTIONS(FOR_EACH_OPTION) #undef FOR_EACH_OPTION private: + enum EntryType { + boolType, + unsignedType, + doubleType, + int32Type, + optionRangeType, + }; + // For storing for an option value: - union Entry { - bool boolVal; - unsigned unsignedVal; - double doubleVal; - int32 int32Val; - OptionRange optionRangeVal; - const char* optionStringVal; - GCLogging::Level gcLogLevelVal; + struct Entry { + union { + bool boolVal; + unsigned unsignedVal; + double doubleVal; + int32 int32Val; + OptionRange optionRangeVal; + } u; }; // For storing constant meta data about each option: struct EntryInfo { const char* name; - const char* description; - Type type; + EntryType type; }; Options(); - enum ShowDefaultsOption { - DontShowDefaults, - ShowDefaults - }; - static void dumpOptionsIfNeeded(); - static void dumpAllOptions(StringBuilder&, DumpLevel, const char* title, - const char* separator, const char* optionHeader, const char* optionFooter, ShowDefaultsOption); - static void dumpOption(StringBuilder&, DumpLevel, OptionID, - const char* optionHeader, const char* optionFooter, ShowDefaultsOption); + // Declare the options: +#define FOR_EACH_OPTION(type_, name_, defaultValue_) \ + type_ m_##name_; + JSC_OPTIONS(FOR_EACH_OPTION) +#undef FOR_EACH_OPTION // Declare the singleton instance of the options store: JS_EXPORTDATA static Entry s_options[numberOfOptions]; - static Entry s_defaultOptions[numberOfOptions]; static const EntryInfo s_optionsInfo[numberOfOptions]; - - friend class Option; -}; - -class Option { -public: - Option(Options::OptionID id) - : m_id(id) - , m_entry(Options::s_options[m_id]) - { - } - - void dump(StringBuilder&) const; - - bool operator==(const Option& other) const; - bool operator!=(const Option& other) const { return !(*this == other); } - - const char* name() const; - const char* description() const; - Options::Type type() const; - bool isOverridden() const; - const Option defaultOption() const; - - bool& boolVal(); - unsigned& unsignedVal(); - double& doubleVal(); - int32_t& int32Val(); - OptionRange optionRangeVal(); - const char* optionStringVal(); - GCLogging::Level& gcLogLevelVal(); - -private: - // Only used for constructing default Options. - Option(Options::OptionID id, Options::Entry& entry) - : m_id(id) - , m_entry(entry) - { - } - - Options::OptionID m_id; - Options::Entry& m_entry; }; -inline const char* Option::name() const -{ - return Options::s_optionsInfo[m_id].name; -} - -inline const char* Option::description() const -{ - return Options::s_optionsInfo[m_id].description; -} - -inline Options::Type Option::type() const -{ - return Options::s_optionsInfo[m_id].type; -} - -inline bool Option::isOverridden() const -{ - return *this != defaultOption(); -} - -inline const Option Option::defaultOption() const -{ - return Option(m_id, Options::s_defaultOptions[m_id]); -} - -inline bool& Option::boolVal() -{ - return m_entry.boolVal; -} - -inline unsigned& Option::unsignedVal() -{ - return m_entry.unsignedVal; -} - -inline double& Option::doubleVal() -{ - return m_entry.doubleVal; -} - -inline int32_t& Option::int32Val() -{ - return m_entry.int32Val; -} - -inline OptionRange Option::optionRangeVal() -{ - return m_entry.optionRangeVal; -} - -inline const char* Option::optionStringVal() -{ - return m_entry.optionStringVal; -} - -inline GCLogging::Level& Option::gcLogLevelVal() -{ - return m_entry.gcLogLevelVal; -} - } // namespace JSC #endif // Options_h diff --git a/Source/JavaScriptCore/runtime/PrivateName.h b/Source/JavaScriptCore/runtime/PrivateName.h index 2b6ba017d..5d2774a20 100644 --- a/Source/JavaScriptCore/runtime/PrivateName.h +++ b/Source/JavaScriptCore/runtime/PrivateName.h @@ -26,35 +26,26 @@ #ifndef PrivateName_h #define PrivateName_h -#include <wtf/text/SymbolImpl.h> +#include <wtf/text/StringImpl.h> namespace JSC { class PrivateName { public: PrivateName() - : m_uid(StringImpl::createSymbolEmpty()) + : m_impl(StringImpl::createEmptyUnique()) { } - - explicit PrivateName(SymbolImpl& uid) - : m_uid(&uid) + explicit PrivateName(StringImpl* uid) + : m_impl(uid) { + ASSERT(m_impl->isEmptyUnique()); } - enum DescriptionTag { Description }; - explicit PrivateName(DescriptionTag, const String& description) - : m_uid(StringImpl::createSymbol(description.impl())) - { - } - - SymbolImpl* uid() const { return m_uid.get(); } - - bool operator==(const PrivateName& other) const { return uid() == other.uid(); } - bool operator!=(const PrivateName& other) const { return uid() != other.uid(); } + StringImpl* uid() const { return m_impl.get(); } private: - RefPtr<SymbolImpl> m_uid; + RefPtr<StringImpl> m_impl; }; } diff --git a/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp b/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp index 5722e88da..1dd35605c 100644 --- a/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp +++ b/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp @@ -30,7 +30,7 @@ #include "GetterSetter.h" #include "JSObject.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { unsigned PropertyDescriptor::defaultAttributes = DontDelete | DontEnum | ReadOnly; @@ -106,8 +106,8 @@ void PropertyDescriptor::setDescriptor(JSValue value, unsigned attributes) m_attributes &= ~ReadOnly; // FIXME: we should be able to ASSERT this! GetterSetter* accessor = asGetterSetter(value); - m_getter = !accessor->isGetterNull() ? accessor->getter() : jsUndefined(); - m_setter = !accessor->isSetterNull() ? accessor->setter() : jsUndefined(); + m_getter = accessor->getter() ? accessor->getter() : jsUndefined(); + m_setter = accessor->setter() ? accessor->setter() : jsUndefined(); m_seenAttributes = EnumerablePresent | ConfigurablePresent; } else { m_value = value; @@ -115,24 +115,14 @@ void PropertyDescriptor::setDescriptor(JSValue value, unsigned attributes) } } -void PropertyDescriptor::setCustomDescriptor(unsigned attributes) -{ - m_attributes = attributes | Accessor | CustomAccessor; - m_attributes &= ~ReadOnly; - m_seenAttributes = EnumerablePresent | ConfigurablePresent; - setGetter(jsUndefined()); - setSetter(jsUndefined()); - m_value = JSValue(); -} - void PropertyDescriptor::setAccessorDescriptor(GetterSetter* accessor, unsigned attributes) { ASSERT(attributes & Accessor); attributes &= ~ReadOnly; // FIXME: we should be able to ASSERT this! m_attributes = attributes; - m_getter = !accessor->isGetterNull() ? accessor->getter() : jsUndefined(); - m_setter = !accessor->isSetterNull() ? accessor->setter() : jsUndefined(); + m_getter = accessor->getter() ? accessor->getter() : jsUndefined(); + m_setter = accessor->setter() ? accessor->setter() : jsUndefined(); m_seenAttributes = EnumerablePresent | ConfigurablePresent; } @@ -186,10 +176,8 @@ bool sameValue(ExecState* exec, JSValue a, JSValue b) return false; double x = a.asNumber(); double y = b.asNumber(); - bool xIsNaN = std::isnan(x); - bool yIsNaN = std::isnan(y); - if (xIsNaN || yIsNaN) - return xIsNaN && yIsNaN; + 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 0345b4e4a..2cc95fb21 100644 --- a/Source/JavaScriptCore/runtime/PropertyDescriptor.h +++ b/Source/JavaScriptCore/runtime/PropertyDescriptor.h @@ -29,72 +29,68 @@ #include "JSCJSValue.h" namespace JSC { + class GetterSetter; -class GetterSetter; + // See ES5.1 9.12 + bool sameValue(ExecState*, JSValue, JSValue); -// See ES5.1 9.12 -bool sameValue(ExecState*, JSValue, JSValue); - -class PropertyDescriptor { -public: - PropertyDescriptor() - : m_attributes(defaultAttributes) - , m_seenAttributes(0) - { - } - PropertyDescriptor(JSValue value, unsigned attributes) - : m_value(value) - , m_attributes(attributes) - , m_seenAttributes(EnumerablePresent | ConfigurablePresent | WritablePresent) - { - ASSERT(m_value); - ASSERT(!m_value.isGetterSetter()); - ASSERT(!m_value.isCustomGetterSetter()); - } - JS_EXPORT_PRIVATE bool writable() const; - JS_EXPORT_PRIVATE bool enumerable() const; - JS_EXPORT_PRIVATE bool configurable() const; - JS_EXPORT_PRIVATE bool isDataDescriptor() const; - bool isGenericDescriptor() const; - JS_EXPORT_PRIVATE bool isAccessorDescriptor() const; - unsigned attributes() const { return m_attributes; } - JSValue value() const { return m_value; } - JS_EXPORT_PRIVATE JSValue getter() const; - JS_EXPORT_PRIVATE JSValue setter() const; - JSObject* getterObject() const; - JSObject* setterObject() const; - JS_EXPORT_PRIVATE void setUndefined(); - JS_EXPORT_PRIVATE void setDescriptor(JSValue, unsigned attributes); - JS_EXPORT_PRIVATE void setCustomDescriptor(unsigned attributes); - JS_EXPORT_PRIVATE void setAccessorDescriptor(GetterSetter* accessor, unsigned attributes); - JS_EXPORT_PRIVATE void setWritable(bool); - JS_EXPORT_PRIVATE void setEnumerable(bool); - JS_EXPORT_PRIVATE void setConfigurable(bool); - void setValue(JSValue value) { m_value = value; } - JS_EXPORT_PRIVATE void setSetter(JSValue); - JS_EXPORT_PRIVATE void setGetter(JSValue); - bool isEmpty() const { return !(m_value || m_getter || m_setter || m_seenAttributes); } - bool writablePresent() const { return m_seenAttributes & WritablePresent; } - bool enumerablePresent() const { return m_seenAttributes & EnumerablePresent; } - bool configurablePresent() const { return m_seenAttributes & ConfigurablePresent; } - bool setterPresent() const { return !!m_setter; } - bool getterPresent() const { return !!m_getter; } - bool equalTo(ExecState*, const PropertyDescriptor& other) const; - bool attributesEqual(const PropertyDescriptor& other) const; - unsigned attributesOverridingCurrent(const PropertyDescriptor& current) const; - -private: - JS_EXPORTDATA static unsigned defaultAttributes; - bool operator==(const PropertyDescriptor&) { return false; } - enum { WritablePresent = 1, EnumerablePresent = 2, ConfigurablePresent = 4}; - // May be a getter/setter - JSValue m_value; - JSValue m_getter; - JSValue m_setter; - unsigned m_attributes; - unsigned m_seenAttributes; -}; + class PropertyDescriptor { + public: + PropertyDescriptor() + : m_attributes(defaultAttributes) + , m_seenAttributes(0) + { + } + PropertyDescriptor(JSValue value, unsigned attributes) + : m_value(value) + , m_attributes(attributes) + , m_seenAttributes(EnumerablePresent | ConfigurablePresent | WritablePresent) + { + ASSERT(m_value); + ASSERT(!m_value.isGetterSetter()); + } + JS_EXPORT_PRIVATE bool writable() const; + JS_EXPORT_PRIVATE bool enumerable() const; + JS_EXPORT_PRIVATE bool configurable() const; + JS_EXPORT_PRIVATE bool isDataDescriptor() const; + bool isGenericDescriptor() const; + JS_EXPORT_PRIVATE bool isAccessorDescriptor() const; + unsigned attributes() const { return m_attributes; } + JSValue value() const { return m_value; } + JS_EXPORT_PRIVATE JSValue getter() const; + JS_EXPORT_PRIVATE JSValue setter() const; + JSObject* getterObject() const; + JSObject* setterObject() const; + JS_EXPORT_PRIVATE void setUndefined(); + JS_EXPORT_PRIVATE void setDescriptor(JSValue value, unsigned attributes); + JS_EXPORT_PRIVATE void setAccessorDescriptor(GetterSetter* accessor, unsigned attributes); + JS_EXPORT_PRIVATE void setWritable(bool); + JS_EXPORT_PRIVATE void setEnumerable(bool); + JS_EXPORT_PRIVATE void setConfigurable(bool); + void setValue(JSValue value) { m_value = value; } + JS_EXPORT_PRIVATE void setSetter(JSValue); + JS_EXPORT_PRIVATE void setGetter(JSValue); + bool isEmpty() const { return !(m_value || m_getter || m_setter || m_seenAttributes); } + bool writablePresent() const { return m_seenAttributes & WritablePresent; } + bool enumerablePresent() const { return m_seenAttributes & EnumerablePresent; } + bool configurablePresent() const { return m_seenAttributes & ConfigurablePresent; } + bool setterPresent() const { return m_setter; } + bool getterPresent() const { return m_getter; } + bool equalTo(ExecState* exec, const PropertyDescriptor& other) const; + bool attributesEqual(const PropertyDescriptor& other) const; + unsigned attributesOverridingCurrent(const PropertyDescriptor& current) const; + private: + JS_EXPORTDATA static unsigned defaultAttributes; + bool operator==(const PropertyDescriptor&){ return false; } + enum { WritablePresent = 1, EnumerablePresent = 2, ConfigurablePresent = 4}; + // May be a getter/setter + JSValue m_value; + JSValue m_getter; + JSValue m_setter; + unsigned m_attributes; + unsigned m_seenAttributes; + }; } #endif diff --git a/Source/JavaScriptCore/runtime/PropertyMapHashTable.h b/Source/JavaScriptCore/runtime/PropertyMapHashTable.h index b068b991d..fad60fba5 100644 --- a/Source/JavaScriptCore/runtime/PropertyMapHashTable.h +++ b/Source/JavaScriptCore/runtime/PropertyMapHashTable.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -21,41 +21,36 @@ #ifndef PropertyMapHashTable_h #define PropertyMapHashTable_h -#include "JSExportMacros.h" #include "PropertyOffset.h" #include "Structure.h" #include "WriteBarrier.h" #include <wtf/CryptographicallyRandomNumber.h> #include <wtf/HashTable.h> #include <wtf/MathExtras.h> +#include <wtf/PassOwnPtr.h> #include <wtf/Vector.h> -#include <wtf/text/AtomicStringImpl.h> +#include <wtf/text/StringImpl.h> +#ifndef NDEBUG #define DUMP_PROPERTYMAP_STATS 0 -#define DUMP_PROPERTYMAP_COLLISIONS 0 - -#define PROPERTY_MAP_DELETED_ENTRY_KEY ((UniquedStringImpl*)1) - -namespace JSC { +#else +#define DUMP_PROPERTYMAP_STATS 0 +#endif #if DUMP_PROPERTYMAP_STATS -struct PropertyMapHashTableStats { - std::atomic<unsigned> numFinds; - std::atomic<unsigned> numCollisions; - std::atomic<unsigned> numLookups; - std::atomic<unsigned> numLookupProbing; - std::atomic<unsigned> numAdds; - std::atomic<unsigned> numRemoves; - std::atomic<unsigned> numRehashes; - std::atomic<unsigned> numReinserts; -}; - -JS_EXPORTDATA extern PropertyMapHashTableStats* propertyMapHashTableStats; +extern int numProbes; +extern int numCollisions; +extern int numRehashes; +extern int numRemoves; #endif +#define PROPERTY_MAP_DELETED_ENTRY_KEY ((StringImpl*)1) + +namespace JSC { + inline bool isPowerOf2(unsigned v) { return hasOneBitSet(v); @@ -77,7 +72,22 @@ inline unsigned nextPowerOf2(unsigned v) return v; } -class PropertyTable final : public JSCell { +struct PropertyMapEntry { + StringImpl* key; + PropertyOffset offset; + unsigned attributes; + WriteBarrier<JSCell> specificValue; + + PropertyMapEntry(VM& vm, JSCell* owner, StringImpl* key, PropertyOffset offset, unsigned attributes, JSCell* specificValue) + : key(key) + , offset(offset) + , attributes(attributes) + , specificValue(vm, owner, specificValue, WriteBarrier<JSCell>::MayBeNull) + { + } +}; + +class PropertyTable : public JSCell { // This is the implementation for 'iterator' and 'const_iterator', // used for iterating over the table in insertion order. @@ -120,20 +130,20 @@ class PropertyTable final : public JSCell { }; public: - typedef JSCell Base; - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; - static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; static void destroy(JSCell*); DECLARE_EXPORT_INFO; static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); + return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, OverridesVisitChildren), info()); } - typedef UniquedStringImpl* KeyType; + static void visitChildren(JSCell*, SlotVisitor&); + + typedef StringImpl* KeyType; typedef PropertyMapEntry ValueType; // The in order iterator provides overloaded * and -> to access the Value at the current position. @@ -147,8 +157,8 @@ public: // Constructor is passed an initial capacity, a PropertyTable to copy, or both. static PropertyTable* create(VM&, unsigned initialCapacity); - static PropertyTable* clone(VM&, const PropertyTable&); - static PropertyTable* clone(VM&, unsigned initialCapacity, const PropertyTable&); + static PropertyTable* clone(VM&, JSCell* owner, const PropertyTable&); + static PropertyTable* clone(VM&, JSCell* owner, unsigned initialCapacity, const PropertyTable&); ~PropertyTable(); // Ordered iteration methods. @@ -159,7 +169,7 @@ public: // Find a value in the table. find_iterator find(const KeyType&); - ValueType* get(const KeyType&); + find_iterator findWithString(const KeyType&); // Add a value to the table enum EffectOnPropertyOffset { PropertyOffsetMayChange, PropertyOffsetMustNotChange }; std::pair<find_iterator, bool> add(const ValueType& entry, PropertyOffset&, EffectOnPropertyOffset); @@ -185,7 +195,7 @@ public: PropertyOffset nextOffset(PropertyOffset inlineCapacity); // Copy this PropertyTable, ensuring the copy has at least the capacity provided. - PropertyTable* copy(VM&, unsigned newCapacity); + PropertyTable* copy(VM&, JSCell* owner, unsigned newCapacity); #ifndef NDEBUG size_t sizeInMemory(); @@ -194,8 +204,8 @@ public: private: PropertyTable(VM&, unsigned initialCapacity); - PropertyTable(VM&, const PropertyTable&); - PropertyTable(VM&, unsigned initialCapacity, const PropertyTable&); + 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. @@ -241,9 +251,9 @@ private: unsigned* m_index; unsigned m_keyCount; unsigned m_deletedCount; - std::unique_ptr<Vector<PropertyOffset>> m_deletedOffsets; + OwnPtr< Vector<PropertyOffset>> m_deletedOffsets; - static const unsigned MinimumTableSize = 16; + static const unsigned MinimumTableSize = 8; static const unsigned EmptyEntryIndex = 0; }; @@ -270,12 +280,12 @@ inline PropertyTable::const_iterator PropertyTable::end() const inline PropertyTable::find_iterator PropertyTable::find(const KeyType& key) { ASSERT(key); - ASSERT(key->isAtomic() || key->isSymbol()); - unsigned hash = IdentifierRepHash::hash(key); + ASSERT(key->isIdentifier() || key->isEmptyUnique()); + unsigned hash = key->existingHash(); unsigned step = 0; #if DUMP_PROPERTYMAP_STATS - ++propertyMapHashTableStats->numFinds; + ++numProbes; #endif while (true) { @@ -285,51 +295,50 @@ inline PropertyTable::find_iterator PropertyTable::find(const KeyType& key) if (key == table()[entryIndex - 1].key) return std::make_pair(&table()[entryIndex - 1], hash & m_indexMask); - if (!step) - step = WTF::doubleHash(IdentifierRepHash::hash(key)) | 1; - #if DUMP_PROPERTYMAP_STATS - ++propertyMapHashTableStats->numCollisions; -#endif - -#if DUMP_PROPERTYMAP_COLLISIONS - dataLog("PropertyTable collision for ", key, " (", hash, ") with step ", step, "\n"); - dataLog("Collided with ", table()[entryIndex - 1].key, "(", IdentifierRepHash::hash(table()[entryIndex - 1].key), ")\n"); + ++numCollisions; #endif + if (!step) + step = WTF::doubleHash(key->existingHash()) | 1; hash += step; + +#if DUMP_PROPERTYMAP_STATS + ++numRehashes; +#endif } } -inline PropertyTable::ValueType* PropertyTable::get(const KeyType& key) +inline PropertyTable::find_iterator PropertyTable::findWithString(const KeyType& key) { ASSERT(key); - ASSERT(key->isAtomic() || key->isSymbol()); - - if (!m_keyCount) - return nullptr; - - unsigned hash = IdentifierRepHash::hash(key); + ASSERT(!key->isIdentifier() && !key->hasHash()); + unsigned hash = key->hash(); unsigned step = 0; #if DUMP_PROPERTYMAP_STATS - ++propertyMapHashTableStats->numLookups; + ++numProbes; #endif while (true) { unsigned entryIndex = m_index[hash & m_indexMask]; if (entryIndex == EmptyEntryIndex) - return nullptr; - if (key == table()[entryIndex - 1].key) - return &table()[entryIndex - 1]; + return std::make_pair((ValueType*)0, hash & m_indexMask); + const KeyType& keyInMap = table()[entryIndex - 1].key; + if (equal(key, keyInMap) && keyInMap->isIdentifier()) + return std::make_pair(&table()[entryIndex - 1], hash & m_indexMask); #if DUMP_PROPERTYMAP_STATS - ++propertyMapHashTableStats->numLookupProbing; + ++numCollisions; #endif if (!step) - step = WTF::doubleHash(IdentifierRepHash::hash(key)) | 1; + step = WTF::doubleHash(key->existingHash()) | 1; hash += step; + +#if DUMP_PROPERTYMAP_STATS + ++numRehashes; +#endif } } @@ -342,10 +351,6 @@ inline std::pair<PropertyTable::find_iterator, bool> PropertyTable::add(const Va return std::make_pair(iter, false); } -#if DUMP_PROPERTYMAP_STATS - ++propertyMapHashTableStats->numAdds; -#endif - // Ref the key entry.key->ref(); @@ -379,7 +384,7 @@ inline void PropertyTable::remove(const find_iterator& iter) return; #if DUMP_PROPERTYMAP_STATS - ++propertyMapHashTableStats->numRemoves; + ++numRemoves; #endif // Replace this one element with the deleted sentinel. Also clear out @@ -419,7 +424,7 @@ inline unsigned PropertyTable::propertyStorageSize() const inline void PropertyTable::clearDeletedOffsets() { - m_deletedOffsets = nullptr; + m_deletedOffsets.clear(); } inline bool PropertyTable::hasDeletedOffset() @@ -437,7 +442,7 @@ inline PropertyOffset PropertyTable::getDeletedOffset() inline void PropertyTable::addDeletedOffset(PropertyOffset offset) { if (!m_deletedOffsets) - m_deletedOffsets = std::make_unique<Vector<PropertyOffset>>(); + m_deletedOffsets = adoptPtr(new Vector<PropertyOffset>); m_deletedOffsets->append(offset); } @@ -449,15 +454,15 @@ inline PropertyOffset PropertyTable::nextOffset(PropertyOffset inlineCapacity) return offsetForPropertyNumber(size(), inlineCapacity); } -inline PropertyTable* PropertyTable::copy(VM& vm, 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 PropertyTable::clone(vm, *this); - return PropertyTable::clone(vm, newCapacity, *this); + return PropertyTable::clone(vm, owner, *this); + return PropertyTable::clone(vm, owner, newCapacity, *this); } #ifndef NDEBUG @@ -472,10 +477,6 @@ inline size_t PropertyTable::sizeInMemory() inline void PropertyTable::reinsert(const ValueType& entry) { -#if DUMP_PROPERTYMAP_STATS - ++propertyMapHashTableStats->numReinserts; -#endif - // Used to insert a value known not to be in the table, and where // we know capacity to be available. ASSERT(canInsert()); @@ -491,10 +492,6 @@ inline void PropertyTable::reinsert(const ValueType& entry) inline void PropertyTable::rehash(unsigned newCapacity) { -#if DUMP_PROPERTYMAP_STATS - ++propertyMapHashTableStats->numRehashes; -#endif - unsigned* oldEntryIndices = m_index; iterator iter = this->begin(); iterator end = this->end(); diff --git a/Source/JavaScriptCore/runtime/PropertyName.h b/Source/JavaScriptCore/runtime/PropertyName.h index eaba62804..e4d5fabd5 100644 --- a/Source/JavaScriptCore/runtime/PropertyName.h +++ b/Source/JavaScriptCore/runtime/PropertyName.h @@ -28,54 +28,90 @@ #include "Identifier.h" #include "PrivateName.h" -#include <wtf/Optional.h> namespace JSC { -class PropertyName { -public: - PropertyName(UniquedStringImpl* propertyName) - : m_impl(propertyName) - { +template <typename CharType> +ALWAYS_INLINE uint32_t toUInt32FromCharacters(const CharType* characters, unsigned length) +{ + // An empty string is not a number. + if (!length) + return UINT_MAX; + + // Get the first character, turning it into a digit. + uint32_t value = characters[0] - '0'; + if (value > 9) + return UINT_MAX; + + // Check for leading zeros. If the first characher is 0, then the + // length of the string must be one - e.g. "042" is not equal to "42". + if (!value && length > 1) + return UINT_MAX; + + while (--length) { + // Multiply value by 10, checking for overflow out of 32 bits. + if (value > 0xFFFFFFFFU / 10) + return UINT_MAX; + value *= 10; + + // Get the next character, turning it into a digit. + uint32_t newValue = *(++characters) - '0'; + if (newValue > 9) + return UINT_MAX; + + // Add in the old value, checking for overflow out of 32 bits. + newValue += value; + if (newValue < value) + return UINT_MAX; + value = newValue; } + + return value; +} +ALWAYS_INLINE uint32_t toUInt32FromStringImpl(StringImpl* impl) +{ + if (impl->is8Bit()) + return toUInt32FromCharacters(impl->characters8(), impl->length()); + return toUInt32FromCharacters(impl->characters16(), impl->length()); +} + +class PropertyName { +public: PropertyName(const Identifier& propertyName) - : PropertyName(propertyName.impl()) + : m_impl(propertyName.impl()) { + ASSERT(!m_impl || m_impl->isIdentifier() || m_impl->isEmptyUnique()); } PropertyName(const PrivateName& propertyName) : m_impl(propertyName.uid()) { - ASSERT(m_impl); - ASSERT(m_impl->isSymbol()); + ASSERT(m_impl && m_impl->isEmptyUnique()); } - bool isSymbol() - { - return m_impl && m_impl->isSymbol(); - } - - UniquedStringImpl* uid() const + StringImpl* uid() const { + ASSERT(!m_impl || (m_impl->isIdentifier() == !m_impl->isEmptyUnique())); return m_impl; } - AtomicStringImpl* publicName() const + StringImpl* publicName() const { - return (!m_impl || m_impl->isSymbol()) ? nullptr : static_cast<AtomicStringImpl*>(m_impl); + ASSERT(!m_impl || (m_impl->isIdentifier() == !m_impl->isEmptyUnique())); + return m_impl->isIdentifier() ? m_impl : 0; } - void dump(PrintStream& out) const + static const uint32_t NotAnIndex = UINT_MAX; + + uint32_t asIndex() { - if (m_impl) - out.print(m_impl); - else - out.print("<null property name>"); + ASSERT(!m_impl || (m_impl->isIdentifier() == !m_impl->isEmptyUnique())); + return m_impl ? toUInt32FromStringImpl(m_impl) : NotAnIndex; } private: - UniquedStringImpl* m_impl; + StringImpl* m_impl; }; inline bool operator==(PropertyName a, const Identifier& b) @@ -93,11 +129,6 @@ inline bool operator==(PropertyName a, PropertyName b) return a.uid() == b.uid(); } -inline bool operator==(PropertyName a, const char* b) -{ - return equal(a.uid(), b); -} - inline bool operator!=(PropertyName a, const Identifier& b) { return a.uid() != b.impl(); @@ -113,16 +144,6 @@ inline bool operator!=(PropertyName a, PropertyName b) return a.uid() != b.uid(); } -ALWAYS_INLINE Optional<uint32_t> parseIndex(PropertyName propertyName) -{ - auto uid = propertyName.uid(); - if (!uid) - return Nullopt; - if (uid->isSymbol()) - return Nullopt; - return parseIndex(*uid); -} - } #endif diff --git a/Source/JavaScriptCore/runtime/PropertyNameArray.cpp b/Source/JavaScriptCore/runtime/PropertyNameArray.cpp new file mode 100644 index 000000000..08a5296a4 --- /dev/null +++ b/Source/JavaScriptCore/runtime/PropertyNameArray.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "PropertyNameArray.h" + +#include "JSObject.h" + +#include "Structure.h" +#include "StructureChain.h" + +namespace JSC { + +static const size_t setThreshold = 20; + +void PropertyNameArray::add(StringImpl* identifier) +{ + ASSERT(!identifier || identifier == StringImpl::empty() || identifier->isIdentifier()); + + size_t size = m_data->propertyNameVector().size(); + if (size < setThreshold) { + for (size_t i = 0; i < size; ++i) { + if (identifier == m_data->propertyNameVector()[i].impl()) + return; + } + } else { + if (m_set.isEmpty()) { + for (size_t i = 0; i < size; ++i) + m_set.add(m_data->propertyNameVector()[i].impl()); + } + if (!m_set.add(identifier).isNewEntry) + return; + } + + addKnownUnique(identifier); +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/PropertyNameArray.h b/Source/JavaScriptCore/runtime/PropertyNameArray.h index 14f6f785c..bfbddaa60 100644 --- a/Source/JavaScriptCore/runtime/PropertyNameArray.h +++ b/Source/JavaScriptCore/runtime/PropertyNameArray.h @@ -27,129 +27,88 @@ #include <wtf/Vector.h> namespace JSC { + + class Structure; + class StructureChain; -// FIXME: Rename to PropertyNameArray. -class PropertyNameArrayData : public RefCounted<PropertyNameArrayData> { -public: - typedef Vector<Identifier, 20> PropertyNameVector; - - static Ref<PropertyNameArrayData> create() { return adoptRef(*new PropertyNameArrayData); } - - PropertyNameVector& propertyNameVector() { return m_propertyNameVector; } - -private: - PropertyNameArrayData() - { - } - - PropertyNameVector m_propertyNameVector; -}; - -// FIXME: Rename to PropertyNameArrayBuilder. -class PropertyNameArray { -public: - PropertyNameArray(VM* vm, PropertyNameMode mode) - : m_data(PropertyNameArrayData::create()) - , m_vm(vm) - , m_mode(mode) - { - } - - PropertyNameArray(ExecState* exec, PropertyNameMode mode) - : PropertyNameArray(&exec->vm(), mode) - { - } - - VM* vm() { return m_vm; } - - void add(uint32_t index) - { - add(Identifier::from(m_vm, index)); - } - - void add(const Identifier&); - void add(UniquedStringImpl*); - void addKnownUnique(UniquedStringImpl*); - - Identifier& operator[](unsigned i) { return m_data->propertyNameVector()[i]; } - const Identifier& operator[](unsigned i) const { return m_data->propertyNameVector()[i]; } - - void setData(PassRefPtr<PropertyNameArrayData> data) { m_data = data; } - PropertyNameArrayData* data() { return m_data.get(); } - PassRefPtr<PropertyNameArrayData> releaseData() { return m_data.release(); } - - // FIXME: Remove these functions. - bool canAddKnownUniqueForStructure() const { return m_data->propertyNameVector().isEmpty(); } - typedef PropertyNameArrayData::PropertyNameVector::const_iterator const_iterator; - size_t size() const { return m_data->propertyNameVector().size(); } - const_iterator begin() const { return m_data->propertyNameVector().begin(); } - const_iterator end() const { return m_data->propertyNameVector().end(); } - - PropertyNameMode mode() const { return m_mode; } - bool includeSymbolProperties() const; - bool includeStringProperties() const; - -private: - bool isUidMatchedToTypeMode(UniquedStringImpl* identifier); - - RefPtr<PropertyNameArrayData> m_data; - HashSet<UniquedStringImpl*> m_set; - VM* m_vm; - PropertyNameMode m_mode; -}; - -ALWAYS_INLINE void PropertyNameArray::add(const Identifier& identifier) -{ - add(identifier.impl()); -} - -ALWAYS_INLINE void PropertyNameArray::addKnownUnique(UniquedStringImpl* identifier) -{ - if (!isUidMatchedToTypeMode(identifier)) - return; - m_data->propertyNameVector().append(Identifier::fromUid(m_vm, identifier)); -} - -ALWAYS_INLINE void PropertyNameArray::add(UniquedStringImpl* identifier) -{ - static const unsigned setThreshold = 20; - - ASSERT(identifier); - - if (!isUidMatchedToTypeMode(identifier)) - return; - - if (size() < setThreshold) { - if (m_data->propertyNameVector().contains(identifier)) - return; - } else { - if (m_set.isEmpty()) { - for (Identifier& name : m_data->propertyNameVector()) - m_set.add(name.impl()); + // FIXME: Rename to PropertyNameArray. + class PropertyNameArrayData : public RefCounted<PropertyNameArrayData> { + public: + typedef Vector<Identifier, 20> PropertyNameVector; + + static PassRefPtr<PropertyNameArrayData> create() { return adoptRef(new PropertyNameArrayData); } + + PropertyNameVector& propertyNameVector() { return m_propertyNameVector; } + + private: + PropertyNameArrayData() + { + } + + PropertyNameVector m_propertyNameVector; + }; + + // FIXME: Rename to PropertyNameArrayBuilder. + class PropertyNameArray { + public: + PropertyNameArray(VM* vm) + : m_data(PropertyNameArrayData::create()) + , m_vm(vm) + , m_numCacheableSlots(0) + , m_baseObject(0) + { } - if (!m_set.add(identifier).isNewEntry) - return; - } - - addKnownUnique(identifier); -} - -ALWAYS_INLINE bool PropertyNameArray::isUidMatchedToTypeMode(UniquedStringImpl* identifier) -{ - if (identifier->isSymbol()) - return includeSymbolProperties(); - return includeStringProperties(); -} - -ALWAYS_INLINE bool PropertyNameArray::includeSymbolProperties() const -{ - return static_cast<std::underlying_type<PropertyNameMode>::type>(m_mode) & static_cast<std::underlying_type<PropertyNameMode>::type>(PropertyNameMode::Symbols); -} - -ALWAYS_INLINE bool PropertyNameArray::includeStringProperties() const -{ - return static_cast<std::underlying_type<PropertyNameMode>::type>(m_mode) & static_cast<std::underlying_type<PropertyNameMode>::type>(PropertyNameMode::Strings); -} + + PropertyNameArray(ExecState* exec) + : m_data(PropertyNameArrayData::create()) + , m_vm(&exec->vm()) + , m_numCacheableSlots(0) + , m_baseObject(0) + { + } + + 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_vm, identifier)); } + + Identifier& operator[](unsigned i) { return m_data->propertyNameVector()[i]; } + const Identifier& operator[](unsigned i) const { return m_data->propertyNameVector()[i]; } + + void setData(PassRefPtr<PropertyNameArrayData> data) { m_data = data; } + PropertyNameArrayData* data() { return m_data.get(); } + PassRefPtr<PropertyNameArrayData> releaseData() { return m_data.release(); } + + // FIXME: Remove these functions. + typedef PropertyNameArrayData::PropertyNameVector::const_iterator const_iterator; + size_t size() const { return m_data->propertyNameVector().size(); } + const_iterator begin() const { return m_data->propertyNameVector().begin(); } + const_iterator end() const { return m_data->propertyNameVector().end(); } + + size_t numCacheableSlots() const { return m_numCacheableSlots; } + void setNumCacheableSlotsForObject(JSObject* object, size_t numCacheableSlots) + { + if (object != m_baseObject) + return; + m_numCacheableSlots = numCacheableSlots; + } + void setBaseObject(JSObject* object) + { + if (m_baseObject) + return; + m_baseObject = object; + } + + private: + typedef HashSet<StringImpl*, PtrHash<StringImpl*>> IdentifierSet; + + RefPtr<PropertyNameArrayData> m_data; + IdentifierSet m_set; + VM* m_vm; + size_t m_numCacheableSlots; + JSObject* m_baseObject; + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/PropertyOffset.h b/Source/JavaScriptCore/runtime/PropertyOffset.h index aeedb70bd..dc0297bf7 100644 --- a/Source/JavaScriptCore/runtime/PropertyOffset.h +++ b/Source/JavaScriptCore/runtime/PropertyOffset.h @@ -26,6 +26,7 @@ #ifndef PropertyOffset_h #define PropertyOffset_h +#include <wtf/Platform.h> #include <wtf/StdLibExtras.h> namespace JSC { diff --git a/Source/JavaScriptCore/runtime/PropertySlot.h b/Source/JavaScriptCore/runtime/PropertySlot.h index 7aefcd37f..ae93455a4 100644 --- a/Source/JavaScriptCore/runtime/PropertySlot.h +++ b/Source/JavaScriptCore/runtime/PropertySlot.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005, 2007, 2008, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2005, 2007, 2008 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -31,23 +31,16 @@ namespace JSC { class ExecState; class GetterSetter; -class JSObject; // ECMA 262-3 8.6.1 // Property attributes enum Attribute { - None = 0, - ReadOnly = 1 << 1, // property can be only read, not written - DontEnum = 1 << 2, // property doesn't appear in (for .. in ..) - DontDelete = 1 << 3, // property can't be deleted - Function = 1 << 4, // property is a function - only used by static hashtables - Accessor = 1 << 5, // property is a getter/setter - CustomAccessor = 1 << 6, - Builtin = 1 << 7, // property is a builtin function - only used by static hashtables - ConstantInteger = 1 << 8, // property is a constant integer - only used by static hashtables - BuiltinOrFunction = Builtin | Function, // helper only used by static hashtables - BuiltinOrFunctionOrAccessor = Builtin | Function | Accessor, // helper only used by static hashtables - BuiltinOrFunctionOrAccessorOrConstant = Builtin | Function | Accessor | ConstantInteger, // helper only used by static hashtables + None = 0, + ReadOnly = 1 << 1, // property can be only read, not written + DontEnum = 1 << 2, // property doesn't appear in (for .. in ..) + DontDelete = 1 << 3, // property can't be deleted + Function = 1 << 4, // property is a function - only used by static hashtables + Accessor = 1 << 5, // property is a getter/setter }; class PropertySlot { @@ -55,12 +48,8 @@ class PropertySlot { TypeUnset, TypeValue, TypeGetter, - TypeCustom - }; - - enum CacheabilityType { - CachingDisallowed, - CachingAllowed + TypeCustom, + TypeCustomIndex }; public: @@ -68,19 +57,16 @@ public: : m_propertyType(TypeUnset) , m_offset(invalidOffset) , m_thisValue(thisValue) - , m_slotBase(nullptr) - , m_watchpointSet(nullptr) - , m_cacheability(CachingAllowed) { } - typedef EncodedJSValue (*GetValueFunc)(ExecState*, JSObject* slotBase, EncodedJSValue thisValue, PropertyName); + typedef EncodedJSValue (*GetValueFunc)(ExecState*, EncodedJSValue slotBase, EncodedJSValue thisValue, PropertyName); + typedef EncodedJSValue (*GetIndexValueFunc)(ExecState*, EncodedJSValue slotBase, EncodedJSValue thisValue, unsigned); JSValue getValue(ExecState*, PropertyName) const; JSValue getValue(ExecState*, unsigned propertyName) const; - bool isCacheable() const { return m_cacheability == CachingAllowed && m_offset != invalidOffset; } - bool isUnset() const { return m_propertyType == TypeUnset; } + bool isCacheable() const { return m_offset != invalidOffset; } bool isValue() const { return m_propertyType == TypeValue; } bool isAccessor() const { return m_propertyType == TypeGetter; } bool isCustom() const { return m_propertyType == TypeCustom; } @@ -88,11 +74,6 @@ public: bool isCacheableGetter() const { return isCacheable() && isAccessor(); } bool isCacheableCustom() const { return isCacheable() && isCustom(); } - void disableCaching() - { - m_cacheability = CachingDisallowed; - } - unsigned attributes() const { return m_attributes; } PropertyOffset cachedOffset() const @@ -115,16 +96,13 @@ public: JSObject* slotBase() const { + ASSERT(m_propertyType != TypeUnset); return m_slotBase; } - WatchpointSet* watchpointSet() const - { - return m_watchpointSet; - } - void setValue(JSObject* slotBase, unsigned attributes, JSValue value) { + ASSERT(value); m_data.value = JSValue::encode(value); m_attributes = attributes; @@ -181,6 +159,19 @@ public: m_offset = !invalidOffset; } + void setCustomIndex(JSObject* slotBase, unsigned attributes, unsigned index, GetIndexValueFunc getIndexValue) + { + ASSERT(getIndexValue); + m_data.customIndex.getIndexValue = getIndexValue; + m_data.customIndex.index = index; + m_attributes = attributes; + + ASSERT(slotBase); + m_slotBase = slotBase; + m_propertyType = TypeCustomIndex; + m_offset = invalidOffset; + } + void setGetterSlot(JSObject* slotBase, unsigned attributes, GetterSetter* getterSetter) { ASSERT(getterSetter); @@ -205,11 +196,6 @@ public: m_offset = offset; } - void setThisValue(JSValue thisValue) - { - m_thisValue = thisValue; - } - void setUndefined() { m_data.value = JSValue::encode(jsUndefined()); @@ -220,11 +206,6 @@ public: m_offset = invalidOffset; } - void setWatchpointSet(WatchpointSet& set) - { - m_watchpointSet = &set; - } - private: JS_EXPORT_PRIVATE JSValue functionGetter(ExecState*) const; @@ -237,34 +218,18 @@ private: struct { GetValueFunc getValue; } custom; + struct { + GetIndexValueFunc getIndexValue; + unsigned index; + } customIndex; } m_data; PropertyType m_propertyType; PropertyOffset m_offset; - JSValue m_thisValue; + const JSValue m_thisValue; JSObject* m_slotBase; - WatchpointSet* m_watchpointSet; - CacheabilityType m_cacheability; }; -ALWAYS_INLINE JSValue PropertySlot::getValue(ExecState* exec, PropertyName propertyName) const -{ - if (m_propertyType == TypeValue) - return JSValue::decode(m_data.value); - if (m_propertyType == TypeGetter) - return functionGetter(exec); - return JSValue::decode(m_data.custom.getValue(exec, slotBase(), JSValue::encode(m_thisValue), propertyName)); -} - -ALWAYS_INLINE JSValue PropertySlot::getValue(ExecState* exec, unsigned propertyName) const -{ - if (m_propertyType == TypeValue) - return JSValue::decode(m_data.value); - if (m_propertyType == TypeGetter) - return functionGetter(exec); - return JSValue::decode(m_data.custom.getValue(exec, slotBase(), JSValue::encode(m_thisValue), Identifier::from(exec, propertyName))); -} - } // namespace JSC #endif // PropertySlot_h diff --git a/Source/JavaScriptCore/runtime/PropertyTable.cpp b/Source/JavaScriptCore/runtime/PropertyTable.cpp index 74474c6d9..82210da95 100644 --- a/Source/JavaScriptCore/runtime/PropertyTable.cpp +++ b/Source/JavaScriptCore/runtime/PropertyTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * 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 @@ -10,10 +10,10 @@ * 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 + * 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 INC. OR + * 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 @@ -35,7 +35,7 @@ namespace JSC { -const ClassInfo PropertyTable::s_info = { "PropertyTable", 0, 0, CREATE_METHOD_TABLE(PropertyTable) }; +const ClassInfo PropertyTable::s_info = { "PropertyTable", 0, 0, 0, CREATE_METHOD_TABLE(PropertyTable) }; PropertyTable* PropertyTable::create(VM& vm, unsigned initialCapacity) { @@ -44,16 +44,16 @@ PropertyTable* PropertyTable::create(VM& vm, unsigned initialCapacity) return table; } -PropertyTable* PropertyTable::clone(VM& vm, const PropertyTable& other) +PropertyTable* PropertyTable::clone(VM& vm, JSCell* owner, const PropertyTable& other) { - PropertyTable* table = new (NotNull, allocateCell<PropertyTable>(vm.heap)) PropertyTable(vm, other); + PropertyTable* table = new (NotNull, allocateCell<PropertyTable>(vm.heap)) PropertyTable(vm, owner, other); table->finishCreation(vm); return table; } -PropertyTable* PropertyTable::clone(VM& vm, unsigned initialCapacity, const PropertyTable& other) +PropertyTable* PropertyTable::clone(VM& vm, JSCell* owner, unsigned initialCapacity, const PropertyTable& other) { - PropertyTable* table = new (NotNull, allocateCell<PropertyTable>(vm.heap)) PropertyTable(vm, initialCapacity, other); + PropertyTable* table = new (NotNull, allocateCell<PropertyTable>(vm.heap)) PropertyTable(vm, owner, initialCapacity, other); table->finishCreation(vm); return table; } @@ -69,7 +69,7 @@ PropertyTable::PropertyTable(VM& vm, unsigned initialCapacity) ASSERT(isPowerOf2(m_indexSize)); } -PropertyTable::PropertyTable(VM& vm, const PropertyTable& other) +PropertyTable::PropertyTable(VM& vm, JSCell* owner, const PropertyTable& other) : JSCell(vm, vm.propertyTableStructure.get()) , m_indexSize(other.m_indexSize) , m_indexMask(other.m_indexMask) @@ -82,16 +82,18 @@ PropertyTable::PropertyTable(VM& vm, const PropertyTable& other) memcpy(m_index, other.m_index, dataSize()); iterator end = this->end(); - for (iterator iter = begin(); iter != end; ++iter) + 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 = std::make_unique<Vector<PropertyOffset>>(*otherDeletedOffsets); + m_deletedOffsets = adoptPtr(new Vector<PropertyOffset>(*otherDeletedOffsets)); } -PropertyTable::PropertyTable(VM& vm, unsigned initialCapacity, const PropertyTable& other) +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) @@ -107,12 +109,13 @@ PropertyTable::PropertyTable(VM& vm, unsigned initialCapacity, const PropertyTab 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 = std::make_unique<Vector<PropertyOffset>>(*otherDeletedOffsets); + m_deletedOffsets = adoptPtr(new Vector<PropertyOffset>(*otherDeletedOffsets)); } void PropertyTable::destroy(JSCell* cell) @@ -129,5 +132,17 @@ PropertyTable::~PropertyTable() fastFree(m_index); } -} // namespace JSC +void PropertyTable::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + PropertyTable* thisObject = jsCast<PropertyTable*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, 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 e72cafb82..78dd319a3 100644 --- a/Source/JavaScriptCore/runtime/Protect.h +++ b/Source/JavaScriptCore/runtime/Protect.h @@ -27,39 +27,39 @@ namespace JSC { -inline void gcProtect(JSCell* val) -{ - Heap::heap(val)->protect(val); -} + inline void gcProtect(JSCell* val) + { + Heap::heap(val)->protect(val); + } -inline void gcUnprotect(JSCell* val) -{ - Heap::heap(val)->unprotect(val); -} + inline void gcUnprotect(JSCell* val) + { + Heap::heap(val)->unprotect(val); + } -inline void gcProtectNullTolerant(JSCell* val) -{ - if (val) - gcProtect(val); -} + inline void gcProtectNullTolerant(JSCell* val) + { + if (val) + gcProtect(val); + } -inline void gcUnprotectNullTolerant(JSCell* val) -{ - if (val) - gcUnprotect(val); -} + inline void gcUnprotectNullTolerant(JSCell* val) + { + if (val) + gcUnprotect(val); + } + + inline void gcProtect(JSValue value) + { + if (value && value.isCell()) + gcProtect(value.asCell()); + } -inline void gcProtect(JSValue value) -{ - if (value && value.isCell()) - gcProtect(value.asCell()); -} - -inline void gcUnprotect(JSValue value) -{ - if (value && value.isCell()) - gcUnprotect(value.asCell()); -} + inline void gcUnprotect(JSValue value) + { + if (value && value.isCell()) + gcUnprotect(value.asCell()); + } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/PrototypeMap.cpp b/Source/JavaScriptCore/runtime/PrototypeMap.cpp index 43f03441b..78d6a7171 100644 --- a/Source/JavaScriptCore/runtime/PrototypeMap.cpp +++ b/Source/JavaScriptCore/runtime/PrototypeMap.cpp @@ -27,13 +27,13 @@ #include "PrototypeMap.h" #include "JSGlobalObject.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { void PrototypeMap::addPrototype(JSObject* object) { - m_prototypes.set(object, 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 @@ -54,16 +54,16 @@ void PrototypeMap::addPrototype(JSObject* object) Structure* PrototypeMap::emptyObjectStructureForPrototype(JSObject* prototype, unsigned inlineCapacity) { - auto key = std::make_pair(prototype, inlineCapacity); - if (Structure* structure = m_structures.get(key)) { + StructureMap::AddResult addResult = m_structures.add(std::make_pair(prototype, inlineCapacity), nullptr); + if (!addResult.isNewEntry) { ASSERT(isPrototype(prototype)); - return structure; + return addResult.iterator->value.get(); } addPrototype(prototype); Structure* structure = JSFinalObject::createStructure( prototype->globalObject()->vm(), prototype->globalObject(), prototype, inlineCapacity); - m_structures.set(key, Weak<Structure>(structure)); + addResult.iterator->value = Weak<Structure>(structure); return structure; } diff --git a/Source/JavaScriptCore/runtime/PrototypeMap.h b/Source/JavaScriptCore/runtime/PrototypeMap.h index 505e0b85c..9752ca7ea 100644 --- a/Source/JavaScriptCore/runtime/PrototypeMap.h +++ b/Source/JavaScriptCore/runtime/PrototypeMap.h @@ -33,17 +33,10 @@ namespace JSC { class JSObject; class Structure; -class VM; // Tracks the canonical structure an object should be allocated with when inheriting from a given prototype. class PrototypeMap { public: - explicit PrototypeMap(VM& vm) - : m_prototypes(vm) - , m_structures(vm) - { - } - JS_EXPORT_PRIVATE Structure* emptyObjectStructureForPrototype(JSObject*, unsigned inlineCapacity); void clearEmptyObjectStructureForPrototype(JSObject*, unsigned inlineCapacity); void addPrototype(JSObject*); diff --git a/Source/JavaScriptCore/runtime/PureNaN.h b/Source/JavaScriptCore/runtime/PureNaN.h deleted file mode 100644 index a236d09e1..000000000 --- a/Source/JavaScriptCore/runtime/PureNaN.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2014 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 PureNaN_h -#define PureNaN_h - -#include <wtf/Assertions.h> -#include <wtf/StdLibExtras.h> - -namespace JSC { - -// NaN (not-a-number) double values are central to how JavaScriptCore encodes JavaScript -// values (JSValues). All values, including integers and non-numeric values, are always -// encoded using the IEEE 854 binary double format. Non-double values are encoded using -// a NaN with the sign bit set. The 51-bit payload is then used for encoding the actual -// value - be it an integer or a pointer to an object, or something else. But we only -// make use of the low 49 bits and the top 15 bits being all set to 1 is the indicator -// that a value is not a double. Top 15 bits being set to 1 also indicate a signed -// signaling NaN with some additional NaN payload bits. -// -// Our use of NaN encoding means that we have to be careful with how we use NaNs for -// ordinary doubles. For example, it would be wrong to ever use a NaN that has the top -// 15 bits set, as that would look like a non-double value to JSC. -// -// We can trust that on all of the hardware/OS combinations that we care about, -// NaN-producing math operations never produce a NaN that looks like a tagged value. But -// if we're ever in a situation where we worry about it, we can use purifyNaN() to get a -// NaN that doesn't look like a tagged non-double value. The JavaScript language doesn't -// distinguish between different flavors of NaN and there is no way to detect what kind -// of NaN you have - hence so long as all double NaNs are purified then our tagging -// scheme remains sound. -// -// It's worth noting that there are cases, like sin(), that will almost produce a NaN -// that breaks us. sin(-inf) returns 0xfff8000000000000. This doesn't break us because -// not all of the top 15 bits are set. But it's very close. Hence our assumptions about -// NaN are just about the most aggressive assumptions we could possibly make without -// having to call purifyNaN() in surprising places. -// -// For naming purposes, we say that a NaN is "pure" if it is safe to tag, in the sense -// that doing so would result in a tagged value that would pass the "are you a double" -// test. We say that a NaN is "impure" if attempting to tag it would result in a value -// that would look like something other than a double. - -// Returns some kind of pure NaN. -inline double pureNaN() -{ - // Be sure that we return exactly the kind of NaN that is safe. We engineer the bits - // ourselves to ensure that it's !isImpureNaN(). FWIW, this is what - // numeric_limits<double>::quiet_NaN() returns on Mac/X86_64. But AFAICT there is - // no guarantee that quiet_NaN would return a pureNaN on all platforms. For example, - // the docs appear to imply that quiet_NaN could even return a double with the - // signaling bit set on hardware that doesn't do signaling. That would probably - // never happen, but it's healthy to be paranoid. - return bitwise_cast<double>(0x7ff8000000000000ll); -} - -#define PNaN (pureNaN()) - -inline bool isImpureNaN(double value) -{ - // Tests if the double value would break JSVALUE64 encoding, which is the most - // aggressive kind of encoding that we currently use. - return bitwise_cast<uint64_t>(value) >= 0xfffe000000000000llu; -} - -// If the given value is NaN then return a NaN that is known to be pure. -inline double purifyNaN(double value) -{ - if (value != value) - return PNaN; - return value; -} - -} // namespace JSC - -#endif // PureNaN_h diff --git a/Source/JavaScriptCore/runtime/PutPropertySlot.h b/Source/JavaScriptCore/runtime/PutPropertySlot.h index d105ac600..2004b451a 100644 --- a/Source/JavaScriptCore/runtime/PutPropertySlot.h +++ b/Source/JavaScriptCore/runtime/PutPropertySlot.h @@ -11,10 +11,10 @@ * 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 + * 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 INC. OR + * 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 @@ -28,92 +28,75 @@ #define PutPropertySlot_h #include "JSCJSValue.h" -#include "PropertyOffset.h" #include <wtf/Assertions.h> namespace JSC { -class JSObject; -class JSFunction; + class JSObject; + class JSFunction; -class PutPropertySlot { -public: - enum Type { Uncachable, ExistingProperty, NewProperty, SetterProperty, CustomProperty }; - enum Context { UnknownContext, PutById, PutByIdEval }; - typedef void (*PutValueFunc)(ExecState*, JSObject* base, EncodedJSValue thisObject, EncodedJSValue value); - - PutPropertySlot(JSValue thisValue, bool isStrictMode = false, Context context = UnknownContext) - : m_type(Uncachable) - , m_base(0) - , m_thisValue(thisValue) - , m_offset(invalidOffset) - , m_isStrictMode(isStrictMode) - , m_context(context) - , m_putFunction(nullptr) - { - } - - void setExistingProperty(JSObject* base, PropertyOffset offset) - { - m_type = ExistingProperty; - m_base = base; - m_offset = offset; - } - - void setNewProperty(JSObject* base, PropertyOffset offset) - { - m_type = NewProperty; - m_base = base; - m_offset = offset; - } - - void setCustomProperty(JSObject* base, PutValueFunc function) - { - m_type = CustomProperty; - m_base = base; - m_putFunction = function; - } - - void setCacheableSetter(JSObject* base, PropertyOffset offset) - { - m_type = SetterProperty; - m_base = base; - m_offset = offset; - } - - void setThisValue(JSValue thisValue) - { - m_thisValue = thisValue; - } - - PutValueFunc customSetter() const { return m_putFunction; } - - Context context() const { return static_cast<Context>(m_context); } - - Type type() const { return m_type; } - JSObject* base() const { return m_base; } - JSValue thisValue() const { return m_thisValue; } - - bool isStrictMode() const { return m_isStrictMode; } - bool isCacheablePut() const { return m_type == NewProperty || m_type == ExistingProperty; } - bool isCacheableSetter() const { return m_type == SetterProperty; } - bool isCacheableCustom() const { return m_type == CustomProperty; } - - PropertyOffset cachedOffset() const - { - return m_offset; - } - -private: - Type m_type; - JSObject* m_base; - JSValue m_thisValue; - PropertyOffset m_offset; - bool m_isStrictMode; - uint8_t m_context; - PutValueFunc m_putFunction; -}; + class PutPropertySlot { + public: + enum Type { Uncachable, ExistingProperty, NewProperty, CustomProperty }; + enum Context { UnknownContext, PutById, PutByIdEval }; + typedef void (*PutValueFunc)(ExecState*, JSObject* base, EncodedJSValue thisObject, EncodedJSValue value); + + PutPropertySlot(JSValue thisValue, bool isStrictMode = false, Context context = UnknownContext) + : m_type(Uncachable) + , m_base(0) + , m_thisValue(thisValue) + , m_isStrictMode(isStrictMode) + , m_context(context) + , m_putFunction(nullptr) + { + } + + void setExistingProperty(JSObject* base, PropertyOffset offset) + { + m_type = ExistingProperty; + m_base = base; + m_offset = offset; + } + + void setNewProperty(JSObject* base, PropertyOffset offset) + { + m_type = NewProperty; + m_base = base; + m_offset = offset; + } + + void setCustomProperty(JSObject* base, PutValueFunc function) + { + m_type = CustomProperty; + m_base = base; + m_putFunction = function; + } + + Context context() const { return static_cast<Context>(m_context); } + + Type type() const { return m_type; } + JSObject* base() const { return m_base; } + JSValue thisValue() const { return m_thisValue; } + + bool isStrictMode() const { return m_isStrictMode; } + bool isCacheable() const { return m_type != Uncachable && m_type != CustomProperty; } + PropertyOffset cachedOffset() const + { + ASSERT(isCacheable()); + return m_offset; + } + + private: + Type m_type; + JSObject* m_base; + JSValue m_thisValue; + PropertyOffset m_offset; + bool m_isStrictMode; + uint8_t m_context; + PutValueFunc m_putFunction; + + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ReflectObject.cpp b/Source/JavaScriptCore/runtime/ReflectObject.cpp deleted file mode 100644 index b9a127ecf..000000000 --- a/Source/JavaScriptCore/runtime/ReflectObject.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2015 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 "ReflectObject.h" - -#include "JSCInlines.h" -#include "JSGlobalObjectFunctions.h" -#include "JSPropertyNameIterator.h" -#include "Lookup.h" -#include "ObjectConstructor.h" - -namespace JSC { - -static EncodedJSValue JSC_HOST_CALL reflectObjectDefineProperty(ExecState*); -static EncodedJSValue JSC_HOST_CALL reflectObjectEnumerate(ExecState*); -static EncodedJSValue JSC_HOST_CALL reflectObjectGetPrototypeOf(ExecState*); -static EncodedJSValue JSC_HOST_CALL reflectObjectIsExtensible(ExecState*); -static EncodedJSValue JSC_HOST_CALL reflectObjectOwnKeys(ExecState*); -static EncodedJSValue JSC_HOST_CALL reflectObjectPreventExtensions(ExecState*); -static EncodedJSValue JSC_HOST_CALL reflectObjectSetPrototypeOf(ExecState*); - -} - -#include "ReflectObject.lut.h" - -namespace JSC { - -STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ReflectObject); - -const ClassInfo ReflectObject::s_info = { "Reflect", &Base::s_info, &reflectObjectTable, CREATE_METHOD_TABLE(ReflectObject) }; - -/* Source for ReflectObject.lut.h -@begin reflectObjectTable - apply reflectObjectApply DontEnum|Function 3 - defineProperty reflectObjectDefineProperty DontEnum|Function 3 - deleteProperty reflectObjectDeleteProperty DontEnum|Function 2 - enumerate reflectObjectEnumerate DontEnum|Function 1 - getPrototypeOf reflectObjectGetPrototypeOf DontEnum|Function 1 - has reflectObjectHas DontEnum|Function 2 - isExtensible reflectObjectIsExtensible DontEnum|Function 1 - ownKeys reflectObjectOwnKeys DontEnum|Function 1 - preventExtensions reflectObjectPreventExtensions DontEnum|Function 1 - setPrototypeOf reflectObjectSetPrototypeOf DontEnum|Function 2 -@end -*/ - -ReflectObject::ReflectObject(VM& vm, Structure* structure) - : JSNonFinalObject(vm, structure) -{ -} - -void ReflectObject::finishCreation(VM& vm, JSGlobalObject*) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); -} - -bool ReflectObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot) -{ - return getStaticFunctionSlot<Base>(exec, reflectObjectTable, jsCast<ReflectObject*>(object), propertyName, slot); -} - -// ------------------------------ Functions -------------------------------- - -// http://www.ecma-international.org/ecma-262/6.0/#sec-reflect.defineproperty -EncodedJSValue JSC_HOST_CALL reflectObjectDefineProperty(ExecState* exec) -{ - JSValue target = exec->argument(0); - if (!target.isObject()) - return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.defineProperty requires the first argument be an object"))); - auto propertyName = exec->argument(1).toPropertyKey(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - PropertyDescriptor descriptor; - if (!toPropertyDescriptor(exec, exec->argument(2), descriptor)) - return JSValue::encode(jsUndefined()); - ASSERT((descriptor.attributes() & Accessor) || (!descriptor.isAccessorDescriptor())); - ASSERT(!exec->hadException()); - - // Reflect.defineProperty should not throw an error when the defineOwnProperty operation fails. - bool shouldThrow = false; - JSObject* targetObject = asObject(target); - return JSValue::encode(jsBoolean(targetObject->methodTable(exec->vm())->defineOwnProperty(targetObject, exec, propertyName, descriptor, shouldThrow))); -} - -// http://www.ecma-international.org/ecma-262/6.0/#sec-reflect.enumerate -EncodedJSValue JSC_HOST_CALL reflectObjectEnumerate(ExecState* exec) -{ - JSValue target = exec->argument(0); - if (!target.isObject()) - return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.enumerate requires the first argument be an object"))); - return JSValue::encode(JSPropertyNameIterator::create(exec, exec->lexicalGlobalObject()->propertyNameIteratorStructure(), asObject(target))); -} - -// http://www.ecma-international.org/ecma-262/6.0/#sec-reflect.getprototypeof -EncodedJSValue JSC_HOST_CALL reflectObjectGetPrototypeOf(ExecState* exec) -{ - JSValue target = exec->argument(0); - if (!target.isObject()) - return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.getPrototypeOf requires the first argument be an object"))); - return JSValue::encode(objectConstructorGetPrototypeOf(exec, asObject(target))); -} - -// http://www.ecma-international.org/ecma-262/6.0/#sec-reflect.isextensible -EncodedJSValue JSC_HOST_CALL reflectObjectIsExtensible(ExecState* exec) -{ - JSValue target = exec->argument(0); - if (!target.isObject()) - return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.isExtensible requires the first argument be an object"))); - return JSValue::encode(jsBoolean(asObject(target)->isExtensible())); -} - -// http://www.ecma-international.org/ecma-262/6.0/#sec-reflect.ownkeys -EncodedJSValue JSC_HOST_CALL reflectObjectOwnKeys(ExecState* exec) -{ - JSValue target = exec->argument(0); - if (!target.isObject()) - return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.ownKeys requires the first argument be an object"))); - return JSValue::encode(ownPropertyKeys(exec, jsCast<JSObject*>(target), PropertyNameMode::StringsAndSymbols, DontEnumPropertiesMode::Include)); -} - -// http://www.ecma-international.org/ecma-262/6.0/#sec-reflect.preventextensions -EncodedJSValue JSC_HOST_CALL reflectObjectPreventExtensions(ExecState* exec) -{ - JSValue target = exec->argument(0); - if (!target.isObject()) - return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.preventExtensions requires the first argument be an object"))); - asObject(target)->preventExtensions(exec->vm()); - return JSValue::encode(jsBoolean(true)); -} - -// http://www.ecma-international.org/ecma-262/6.0/#sec-reflect.setprototypeof -EncodedJSValue JSC_HOST_CALL reflectObjectSetPrototypeOf(ExecState* exec) -{ - JSValue target = exec->argument(0); - if (!target.isObject()) - return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.setPrototypeOf requires the first argument be an object"))); - JSValue proto = exec->argument(1); - if (!proto.isObject() && !proto.isNull()) - return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.setPrototypeOf requires the second argument be either an object or null"))); - - JSObject* object = asObject(target); - - if (!checkProtoSetterAccessAllowed(exec, object)) - return JSValue::encode(jsBoolean(false)); - - if (object->prototype() == proto) - return JSValue::encode(jsBoolean(true)); - - if (!object->isExtensible()) - return JSValue::encode(jsBoolean(false)); - - return JSValue::encode(jsBoolean(object->setPrototypeWithCycleCheck(exec, proto))); -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ReflectObject.h b/Source/JavaScriptCore/runtime/ReflectObject.h deleted file mode 100644 index 6a7350229..000000000 --- a/Source/JavaScriptCore/runtime/ReflectObject.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2015 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 ReflectObject_h -#define ReflectObject_h - -#include "JSObject.h" - -namespace JSC { - -class ReflectObject : public JSNonFinalObject { -private: - ReflectObject(VM&, Structure*); - -public: - typedef JSNonFinalObject Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; - - static ReflectObject* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) - { - ReflectObject* object = new (NotNull, allocateCell<ReflectObject>(vm.heap)) ReflectObject(vm, structure); - object->finishCreation(vm, globalObject); - return object; - } - - DECLARE_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } - - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); - -protected: - void finishCreation(VM&, JSGlobalObject*); -}; - -} // namespace JSC - -#endif // ReflectObject_h diff --git a/Source/JavaScriptCore/runtime/RegExp.cpp b/Source/JavaScriptCore/runtime/RegExp.cpp index 7a6f80c9e..30c105d29 100644 --- a/Source/JavaScriptCore/runtime/RegExp.cpp +++ b/Source/JavaScriptCore/runtime/RegExp.cpp @@ -24,7 +24,7 @@ #include "RegExp.h" #include "Lexer.h" -#include "JSCInlines.h" +#include "Operations.h" #include "RegExpCache.h" #include "Yarr.h" #include "YarrJIT.h" @@ -40,7 +40,7 @@ namespace JSC { -const ClassInfo RegExp::s_info = { "RegExp", 0, 0, CREATE_METHOD_TABLE(RegExp) }; +const ClassInfo RegExp::s_info = { "RegExp", 0, 0, 0, CREATE_METHOD_TABLE(RegExp) }; RegExpFlags regExpFlags(const String& string) { @@ -113,7 +113,7 @@ RegExpFunctionalTestCollector* RegExpFunctionalTestCollector::get() return s_instance; } -void RegExpFunctionalTestCollector::outputOneTest(RegExp* regExp, const String& s, int startOffset, int* ovector, int result) +void RegExpFunctionalTestCollector::outputOneTest(RegExp* regExp, String s, int startOffset, int* ovector, int result) { if ((!m_lastRegExp) || (m_lastRegExp != regExp)) { m_lastRegExp = regExp; @@ -227,10 +227,6 @@ RegExp::RegExp(VM& vm, const String& patternString, RegExpFlags flags) , m_constructionError(0) , m_numSubpatterns(0) #if ENABLE(REGEXP_TRACING) - , m_rtMatchOnlyTotalSubjectStringLen(0.0) - , m_rtMatchTotalSubjectStringLen(0.0) - , m_rtMatchOnlyCallCount(0) - , m_rtMatchOnlyFoundCount(0) , m_rtMatchCallCount(0) , m_rtMatchFoundCount(0) #endif @@ -273,10 +269,8 @@ void RegExp::compile(VM* vm, Yarr::YarrCharSize charSize) Yarr::YarrPattern pattern(m_patternString, ignoreCase(), multiline(), &m_constructionError); if (m_constructionError) { RELEASE_ASSERT_NOT_REACHED(); -#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE) m_state = ParseError; return; -#endif } ASSERT(m_numSubpatterns == pattern.m_numSubpatterns); @@ -287,18 +281,24 @@ void RegExp::compile(VM* vm, Yarr::YarrCharSize charSize) } #if ENABLE(YARR_JIT) - if (!pattern.m_containsBackreferences && !pattern.containsUnsignedLengthPattern() && vm->canUseRegExpJIT()) { + 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; + else + m_state = ByteCode; +#else if (!m_regExpJITCode.isFallBack()) { m_state = JITCode; return; } +#endif } #else UNUSED_PARAM(charSize); #endif - m_state = ByteCode; m_regExpBytecode = Yarr::byteCompile(pattern, &vm->m_regExpAllocator); } @@ -324,7 +324,6 @@ int RegExp::match(VM& vm, const String& s, unsigned startOffset, Vector<int, 32> { #if ENABLE(REGEXP_TRACING) m_rtMatchCallCount++; - m_rtMatchTotalSubjectStringLen += (double)(s.length() - startOffset); #endif ASSERT(m_state != ParseError); @@ -392,10 +391,8 @@ void RegExp::compileMatchOnly(VM* vm, Yarr::YarrCharSize charSize) Yarr::YarrPattern pattern(m_patternString, ignoreCase(), multiline(), &m_constructionError); if (m_constructionError) { RELEASE_ASSERT_NOT_REACHED(); -#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE) m_state = ParseError; return; -#endif } ASSERT(m_numSubpatterns == pattern.m_numSubpatterns); @@ -406,18 +403,24 @@ void RegExp::compileMatchOnly(VM* vm, Yarr::YarrCharSize charSize) } #if ENABLE(YARR_JIT) - if (!pattern.m_containsBackreferences && !pattern.containsUnsignedLengthPattern() && vm->canUseRegExpJIT()) { + 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; + else + m_state = ByteCode; +#else if (!m_regExpJITCode.isFallBack()) { m_state = JITCode; return; } +#endif } #else UNUSED_PARAM(charSize); #endif - m_state = ByteCode; m_regExpBytecode = Yarr::byteCompile(pattern, &vm->m_regExpAllocator); } @@ -442,8 +445,7 @@ void RegExp::compileIfNecessaryMatchOnly(VM& vm, Yarr::YarrCharSize charSize) MatchResult RegExp::match(VM& vm, const String& s, unsigned startOffset) { #if ENABLE(REGEXP_TRACING) - m_rtMatchOnlyCallCount++; - m_rtMatchOnlyTotalSubjectStringLen += (double)(s.length() - startOffset); + m_rtMatchCallCount++; #endif ASSERT(m_state != ParseError); @@ -456,7 +458,7 @@ MatchResult RegExp::match(VM& vm, const String& s, unsigned startOffset) m_regExpJITCode.execute(s.characters16(), startOffset, s.length()); #if ENABLE(REGEXP_TRACING) if (!result) - m_rtMatchOnlyFoundCount++; + m_rtMatchFoundCount++; #endif return result; } @@ -474,7 +476,7 @@ MatchResult RegExp::match(VM& vm, const String& s, unsigned startOffset) if (r >= 0) { #if ENABLE(REGEXP_TRACING) - m_rtMatchOnlyFoundCount++; + m_rtMatchFoundCount++; #endif return MatchResult(r, reinterpret_cast<unsigned*>(offsetVector)[1]); } @@ -482,7 +484,7 @@ MatchResult RegExp::match(VM& vm, const String& s, unsigned startOffset) return MatchResult::failed(); } -void RegExp::deleteCode() +void RegExp::invalidateCode() { if (!hasCode()) return; @@ -490,7 +492,7 @@ void RegExp::deleteCode() #if ENABLE(YARR_JIT) m_regExpJITCode.clear(); #endif - m_regExpBytecode = nullptr; + m_regExpBytecode.clear(); } #if ENABLE(YARR_JIT_DEBUG) @@ -561,32 +563,16 @@ void RegExp::matchCompareWithInterpreter(const String& s, int startOffset, int* Yarr::YarrCodeBlock& codeBlock = m_regExpJITCode; const size_t jitAddrSize = 20; - char jit8BitMatchOnlyAddr[jitAddrSize]; - char jit16BitMatchOnlyAddr[jitAddrSize]; - char jit8BitMatchAddr[jitAddrSize]; - char jit16BitMatchAddr[jitAddrSize]; - if (m_state == ByteCode) { - snprintf(jit8BitMatchOnlyAddr, jitAddrSize, "fallback "); - snprintf(jit16BitMatchOnlyAddr, jitAddrSize, "---- "); - snprintf(jit8BitMatchAddr, jitAddrSize, "fallback "); - snprintf(jit16BitMatchAddr, jitAddrSize, "---- "); - } else { - snprintf(jit8BitMatchOnlyAddr, jitAddrSize, "0x%014lx", reinterpret_cast<unsigned long int>(codeBlock.get8BitMatchOnlyAddr())); - snprintf(jit16BitMatchOnlyAddr, jitAddrSize, "0x%014lx", reinterpret_cast<unsigned long int>(codeBlock.get16BitMatchOnlyAddr())); - snprintf(jit8BitMatchAddr, jitAddrSize, "0x%014lx", reinterpret_cast<unsigned long int>(codeBlock.get8BitMatchAddr())); - snprintf(jit16BitMatchAddr, jitAddrSize, "0x%014lx", reinterpret_cast<unsigned long int>(codeBlock.get16BitMatchAddr())); - } + char jitAddr[jitAddrSize]; + if (m_state == JITCode) + snprintf(jitAddr, jitAddrSize, "fallback"); + else + snprintf(jitAddr, jitAddrSize, "0x%014lx", reinterpret_cast<unsigned long int>(codeBlock.getAddr())); #else - const char* jit8BitMatchOnlyAddr = "JIT Off"; - const char* jit16BitMatchOnlyAddr = ""; - const char* jit8BitMatchAddr = "JIT Off"; - const char* jit16BitMatchAddr = ""; + const char* jitAddr = "JIT Off"; #endif - unsigned averageMatchOnlyStringLen = (unsigned)(m_rtMatchOnlyTotalSubjectStringLen / m_rtMatchOnlyCallCount); - unsigned averageMatchStringLen = (unsigned)(m_rtMatchTotalSubjectStringLen / m_rtMatchCallCount); - printf("%-40.40s %16.16s %16.16s %10d %10d %10u\n", formattedPattern, jit8BitMatchOnlyAddr, jit16BitMatchOnlyAddr, m_rtMatchOnlyCallCount, m_rtMatchOnlyFoundCount, averageMatchOnlyStringLen); - printf(" %16.16s %16.16s %10d %10d %10u\n", jit8BitMatchAddr, jit16BitMatchAddr, m_rtMatchCallCount, m_rtMatchFoundCount, averageMatchStringLen); + printf("%-40.40s %16.16s %10d %10d\n", formattedPattern, jitAddr, m_rtMatchCallCount, m_rtMatchFoundCount); } #endif diff --git a/Source/JavaScriptCore/runtime/RegExp.h b/Source/JavaScriptCore/runtime/RegExp.h index 5c05c5b1a..d982ce4c3 100644 --- a/Source/JavaScriptCore/runtime/RegExp.h +++ b/Source/JavaScriptCore/runtime/RegExp.h @@ -37,99 +37,93 @@ namespace JSC { -struct RegExpRepresentation; -class VM; + struct RegExpRepresentation; + class VM; -JS_EXPORT_PRIVATE RegExpFlags regExpFlags(const String&); + JS_EXPORT_PRIVATE RegExpFlags regExpFlags(const String&); -class RegExp final : public JSCell { -public: - typedef JSCell Base; - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; + class RegExp : public JSCell { + public: + typedef JSCell Base; - JS_EXPORT_PRIVATE static RegExp* create(VM&, const String& pattern, RegExpFlags); - static const bool needsDestruction = true; - static void destroy(JSCell*); + 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*); - bool global() const { return m_flags & FlagGlobal; } - bool ignoreCase() const { return m_flags & FlagIgnoreCase; } - bool multiline() const { return m_flags & FlagMultiline; } + bool global() const { return m_flags & FlagGlobal; } + bool ignoreCase() const { return m_flags & FlagIgnoreCase; } + bool multiline() const { return m_flags & FlagMultiline; } - const String& pattern() const { return m_patternString; } + const String& pattern() const { return m_patternString; } - bool isValid() const { return !m_constructionError && m_flags != InvalidFlags; } - const char* errorMessage() const { return m_constructionError; } + bool isValid() const { return !m_constructionError && m_flags != InvalidFlags; } + const char* errorMessage() const { return m_constructionError; } - JS_EXPORT_PRIVATE int match(VM&, const String&, unsigned startOffset, Vector<int, 32>& ovector); - JS_EXPORT_PRIVATE MatchResult match(VM&, const String&, unsigned startOffset); - unsigned numSubpatterns() const { return m_numSubpatterns; } + 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() - { - return m_state != NotCompiled; - } - - void deleteCode(); + bool hasCode() + { + return m_state != NotCompiled; + } + void invalidateCode(); + #if ENABLE(REGEXP_TRACING) - void printTraceData(); + void printTraceData(); #endif - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); - } - - DECLARE_INFO; + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(LeafType, 0), info()); + } + + DECLARE_INFO; - RegExpKey key() { return RegExpKey(m_flags, m_patternString); } + RegExpKey key() { return RegExpKey(m_flags, m_patternString); } -protected: - void finishCreation(VM&); + protected: + void finishCreation(VM&); -private: - friend class RegExpCache; - RegExp(VM&, const String&, RegExpFlags); + private: + friend class RegExpCache; + RegExp(VM&, const String&, RegExpFlags); - static RegExp* createWithoutCaching(VM&, const String&, RegExpFlags); + static RegExp* createWithoutCaching(VM&, const String&, RegExpFlags); - enum RegExpState { - ParseError, - JITCode, - ByteCode, - NotCompiled - }; + enum RegExpState { + ParseError, + JITCode, + ByteCode, + NotCompiled + } m_state; - RegExpState m_state; + void compile(VM*, Yarr::YarrCharSize); + void compileIfNecessary(VM&, Yarr::YarrCharSize); - void compile(VM*, Yarr::YarrCharSize); - void compileIfNecessary(VM&, Yarr::YarrCharSize); - - void compileMatchOnly(VM*, Yarr::YarrCharSize); - void compileIfNecessaryMatchOnly(VM&, 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); + void matchCompareWithInterpreter(const String&, int startOffset, int* offsetVector, int jitResult); #endif - String m_patternString; - RegExpFlags m_flags; - const char* m_constructionError; - unsigned m_numSubpatterns; + String m_patternString; + RegExpFlags m_flags; + const char* m_constructionError; + unsigned m_numSubpatterns; #if ENABLE(REGEXP_TRACING) - double m_rtMatchOnlyTotalSubjectStringLen; - double m_rtMatchTotalSubjectStringLen; - unsigned m_rtMatchOnlyCallCount; - unsigned m_rtMatchOnlyFoundCount; - unsigned m_rtMatchCallCount; - unsigned m_rtMatchFoundCount; + unsigned m_rtMatchCallCount; + unsigned m_rtMatchFoundCount; #endif #if ENABLE(YARR_JIT) - Yarr::YarrCodeBlock m_regExpJITCode; + Yarr::YarrCodeBlock m_regExpJITCode; #endif - std::unique_ptr<Yarr::BytecodePattern> m_regExpBytecode; -}; + OwnPtr<Yarr::BytecodePattern> m_regExpBytecode; + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/RegExpCache.cpp b/Source/JavaScriptCore/runtime/RegExpCache.cpp index 8f4660a78..126004701 100644 --- a/Source/JavaScriptCore/runtime/RegExpCache.cpp +++ b/Source/JavaScriptCore/runtime/RegExpCache.cpp @@ -29,7 +29,7 @@ #include "config.h" #include "RegExpCache.h" -#include "JSCInlines.h" +#include "Operations.h" #include "RegExpObject.h" #include "StrongInlines.h" @@ -60,6 +60,7 @@ void RegExpCache::finalize(Handle<Unknown> handle, void*) { RegExp* regExp = static_cast<RegExp*>(handle.get().asCell()); weakRemove(m_weakCache, regExp->key(), regExp); + regExp->invalidateCode(); } void RegExpCache::addToStrongCache(RegExp* regExp) @@ -73,7 +74,7 @@ void RegExpCache::addToStrongCache(RegExp* regExp) m_nextEntryInStrongCache = 0; } -void RegExpCache::deleteAllCode() +void RegExpCache::invalidateCode() { for (int i = 0; i < maxStrongCacheableEntries; i++) m_strongCache[i].clear(); @@ -84,7 +85,7 @@ void RegExpCache::deleteAllCode() RegExp* regExp = it->value.get(); if (!regExp) // Skip zombies. continue; - regExp->deleteCode(); + regExp->invalidateCode(); } } diff --git a/Source/JavaScriptCore/runtime/RegExpCache.h b/Source/JavaScriptCore/runtime/RegExpCache.h index 942f3dcb9..d2bfdfef3 100644 --- a/Source/JavaScriptCore/runtime/RegExpCache.h +++ b/Source/JavaScriptCore/runtime/RegExpCache.h @@ -39,14 +39,12 @@ namespace JSC { class RegExpCache : private WeakHandleOwner { - WTF_MAKE_FAST_ALLOCATED; - - friend class RegExp; - typedef HashMap<RegExpKey, Weak<RegExp>> RegExpCacheMap; +friend class RegExp; +typedef HashMap<RegExpKey, Weak<RegExp>> RegExpCacheMap; public: RegExpCache(VM* vm); - void deleteAllCode(); + void invalidateCode(); private: diff --git a/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp b/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp index e93061886..c54b4783d 100644 --- a/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp +++ b/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "RegExpCachedResult.h" -#include "JSCInlines.h" +#include "Operations.h" #include "RegExpMatchesArray.h" namespace JSC { @@ -37,45 +37,23 @@ void RegExpCachedResult::visitChildren(SlotVisitor& visitor) visitor.append(&m_lastRegExp); visitor.append(&m_reifiedInput); visitor.append(&m_reifiedResult); - visitor.append(&m_reifiedLeftContext); - visitor.append(&m_reifiedRightContext); } -JSArray* RegExpCachedResult::lastResult(ExecState* exec, JSObject* owner) +RegExpMatchesArray* RegExpCachedResult::lastResult(ExecState* exec, JSObject* owner) { - if (!m_reified) { + if (m_result) { m_reifiedInput.set(exec->vm(), owner, m_lastInput.get()); - m_reifiedResult.set(exec->vm(), owner, createRegExpMatchesArray(exec, m_lastInput.get(), m_lastRegExp.get(), m_result)); - m_reified = true; + 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(); } -JSString* RegExpCachedResult::leftContext(ExecState* exec, JSObject* owner) -{ - // Make sure we're reified. - lastResult(exec, owner); - if (!m_reifiedLeftContext) - m_reifiedLeftContext.set(exec->vm(), owner, m_result.start ? jsSubstring(exec, m_reifiedInput.get(), 0, m_result.start) : jsEmptyString(exec)); - return m_reifiedLeftContext.get(); -} - -JSString* RegExpCachedResult::rightContext(ExecState* exec, JSObject* owner) -{ - // Make sure we're reified. - lastResult(exec, owner); - if (!m_reifiedRightContext) { - unsigned length = m_reifiedInput->length(); - m_reifiedRightContext.set(exec->vm(), owner, m_result.end != length ? jsSubstring(exec, m_reifiedInput.get(), m_result.end, length - m_result.end) : jsEmptyString(exec)); - } - return m_reifiedRightContext.get(); -} - void RegExpCachedResult::setInput(ExecState* exec, JSObject* owner, JSString* input) { // Make sure we're reified, otherwise m_reifiedInput will be ignored. lastResult(exec, owner); - ASSERT(m_reified); + ASSERT(!m_result); m_reifiedInput.set(exec->vm(), owner, input); } diff --git a/Source/JavaScriptCore/runtime/RegExpCachedResult.h b/Source/JavaScriptCore/runtime/RegExpCachedResult.h index bf6c0b864..d2763bc77 100644 --- a/Source/JavaScriptCore/runtime/RegExpCachedResult.h +++ b/Source/JavaScriptCore/runtime/RegExpCachedResult.h @@ -30,61 +30,54 @@ namespace JSC { -class JSArray; -class JSString; + class JSString; + class RegExpMatchesArray; -// RegExpCachedResult is used to track the cached results of the last -// match, stores on the RegExp constructor (e.g. $&, $_, $1, $2 ...). -// These values will be lazily generated on demand, so the cached result -// may be in a lazy or reified state. A lazy state is indicated by a -// value of m_result indicating a successful match, and a reified state -// is indicated by setting m_result to MatchResult::failed(). -// Following a successful match, m_result, m_lastInput and m_lastRegExp -// can be used to reify the results from the match, following reification -// m_reifiedResult and m_reifiedInput hold the cached results. -class RegExpCachedResult { -public: - RegExpCachedResult(VM& vm, JSObject* owner, RegExp* emptyRegExp) - : m_result(0, 0) - , m_reified(false) - { - m_lastInput.set(vm, owner, jsEmptyString(&vm)); - m_lastRegExp.set(vm, owner, emptyRegExp); - } + // RegExpCachedResult is used to track the cached results of the last + // match, stores on the RegExp constructor (e.g. $&, $_, $1, $2 ...). + // These values will be lazily generated on demand, so the cached result + // may be in a lazy or reified state. A lazy state is indicated by a + // value of m_result indicating a successful match, and a reified state + // is indicated by setting m_result to MatchResult::failed(). + // Following a successful match, m_result, m_lastInput and m_lastRegExp + // can be used to reify the results from the match, following reification + // m_reifiedResult and m_reifiedInput hold the cached results. + class RegExpCachedResult { + public: + RegExpCachedResult(VM& vm, JSObject* owner, RegExp* emptyRegExp) + : m_result(0, 0) + { + m_lastInput.set(vm, owner, jsEmptyString(&vm)); + m_lastRegExp.set(vm, owner, emptyRegExp); + } - ALWAYS_INLINE void record(VM& vm, JSObject* owner, RegExp* regExp, JSString* input, MatchResult result) - { - m_lastRegExp.set(vm, owner, regExp); - m_lastInput.set(vm, owner, input); - m_reifiedLeftContext.clear(); - m_reifiedRightContext.clear(); - m_result = result; - m_reified = false; - } + ALWAYS_INLINE void record(VM& vm, JSObject* owner, RegExp* regExp, JSString* input, MatchResult result) + { + m_lastRegExp.set(vm, owner, regExp); + m_lastInput.set(vm, owner, input); + m_result = result; + } - JSArray* lastResult(ExecState*, JSObject* owner); - void setInput(ExecState*, JSObject* owner, JSString*); + RegExpMatchesArray* lastResult(ExecState*, JSObject* owner); + void setInput(ExecState*, JSObject* owner, JSString*); - JSString* leftContext(ExecState*, JSObject* owner); - JSString* rightContext(ExecState*, JSObject* owner); + JSString* input() + { + // If m_result showas a match then we're in a lazy state, so m_lastInput + // is the most recent value of the input property. If not then we have + // reified, in which case m_reifiedInput will contain the correct value. + return m_result ? m_lastInput.get() : m_reifiedInput.get(); + } - JSString* input() - { - return m_reified ? m_reifiedInput.get() : m_lastInput.get(); - } + void visitChildren(SlotVisitor&); - void visitChildren(SlotVisitor&); - -private: - MatchResult m_result; - bool m_reified; - WriteBarrier<JSString> m_lastInput; - WriteBarrier<RegExp> m_lastRegExp; - WriteBarrier<JSArray> m_reifiedResult; - WriteBarrier<JSString> m_reifiedInput; - WriteBarrier<JSString> m_reifiedLeftContext; - WriteBarrier<JSString> m_reifiedRightContext; -}; + private: + MatchResult m_result; + WriteBarrier<JSString> m_lastInput; + WriteBarrier<RegExp> m_lastRegExp; + WriteBarrier<RegExpMatchesArray> m_reifiedResult; + WriteBarrier<JSString> m_reifiedInput; + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp index ee1d8b3fc..bc516b06d 100644 --- a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp +++ b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp @@ -23,27 +23,27 @@ #include "RegExpConstructor.h" #include "Error.h" -#include "JSCInlines.h" +#include "Operations.h" #include "RegExpMatchesArray.h" #include "RegExpPrototype.h" namespace JSC { -static EncodedJSValue regExpConstructorInput(ExecState*, JSObject*, EncodedJSValue, PropertyName); -static EncodedJSValue regExpConstructorMultiline(ExecState*, JSObject*, EncodedJSValue, PropertyName); -static EncodedJSValue regExpConstructorLastMatch(ExecState*, JSObject*, EncodedJSValue, PropertyName); -static EncodedJSValue regExpConstructorLastParen(ExecState*, JSObject*, EncodedJSValue, PropertyName); -static EncodedJSValue regExpConstructorLeftContext(ExecState*, JSObject*, EncodedJSValue, PropertyName); -static EncodedJSValue regExpConstructorRightContext(ExecState*, JSObject*, EncodedJSValue, PropertyName); -static EncodedJSValue regExpConstructorDollar1(ExecState*, JSObject*, EncodedJSValue, PropertyName); -static EncodedJSValue regExpConstructorDollar2(ExecState*, JSObject*, EncodedJSValue, PropertyName); -static EncodedJSValue regExpConstructorDollar3(ExecState*, JSObject*, EncodedJSValue, PropertyName); -static EncodedJSValue regExpConstructorDollar4(ExecState*, JSObject*, EncodedJSValue, PropertyName); -static EncodedJSValue regExpConstructorDollar5(ExecState*, JSObject*, EncodedJSValue, PropertyName); -static EncodedJSValue regExpConstructorDollar6(ExecState*, JSObject*, EncodedJSValue, PropertyName); -static EncodedJSValue regExpConstructorDollar7(ExecState*, JSObject*, EncodedJSValue, PropertyName); -static EncodedJSValue regExpConstructorDollar8(ExecState*, JSObject*, EncodedJSValue, PropertyName); -static EncodedJSValue regExpConstructorDollar9(ExecState*, JSObject*, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorInput(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorMultiline(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorLastMatch(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorLastParen(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorLeftContext(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorRightContext(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorDollar1(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorDollar2(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorDollar3(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorDollar4(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorDollar5(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorDollar6(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorDollar7(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorDollar8(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); +static EncodedJSValue regExpConstructorDollar9(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); static void setRegExpConstructorInput(ExecState*, JSObject*, EncodedJSValue, EncodedJSValue); static void setRegExpConstructorMultiline(ExecState*, JSObject*, EncodedJSValue, EncodedJSValue); @@ -54,7 +54,7 @@ static void setRegExpConstructorMultiline(ExecState*, JSObject*, EncodedJSValue, namespace JSC { -const ClassInfo RegExpConstructor::s_info = { "Function", &InternalFunction::s_info, ®ExpConstructorTable, CREATE_METHOD_TABLE(RegExpConstructor) }; +const ClassInfo RegExpConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::regExpConstructorTable, CREATE_METHOD_TABLE(RegExpConstructor) }; /* Source for RegExpConstructor.lut.h @begin regExpConstructorTable @@ -91,7 +91,7 @@ RegExpConstructor::RegExpConstructor(VM& vm, Structure* structure, RegExpPrototy void RegExpConstructor::finishCreation(VM& vm, RegExpPrototype* regExpPrototype) { - Base::finishCreation(vm, regExpPrototype->classInfo()->className); + Base::finishCreation(vm, Identifier(&vm, "RegExp").string()); ASSERT(inherits(info())); // ECMA 15.10.5.1 RegExp.prototype @@ -110,13 +110,16 @@ void RegExpConstructor::visitChildren(JSCell* cell, SlotVisitor& visitor) { RegExpConstructor* thisObject = jsCast<RegExpConstructor*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + Base::visitChildren(thisObject, visitor); thisObject->m_cachedResult.visitChildren(visitor); } JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i) { - JSArray* array = m_cachedResult.lastResult(exec, this); + RegExpMatchesArray* array = m_cachedResult.lastResult(exec, this); if (i < array->length()) { JSValue result = JSValue(array).get(exec, i); @@ -129,7 +132,7 @@ JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i) JSValue RegExpConstructor::getLastParen(ExecState* exec) { - JSArray* array = m_cachedResult.lastResult(exec, this); + RegExpMatchesArray* array = m_cachedResult.lastResult(exec, this); unsigned length = array->length(); if (length > 1) { JSValue result = JSValue(array).get(exec, length - 1); @@ -142,90 +145,95 @@ JSValue RegExpConstructor::getLastParen(ExecState* exec) JSValue RegExpConstructor::getLeftContext(ExecState* exec) { - return m_cachedResult.leftContext(exec, this); + return m_cachedResult.lastResult(exec, this)->leftContext(exec); } JSValue RegExpConstructor::getRightContext(ExecState* exec) { - return m_cachedResult.rightContext(exec, this); + return m_cachedResult.lastResult(exec, this)->rightContext(exec); } bool RegExpConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { - return getStaticValueSlot<RegExpConstructor, InternalFunction>(exec, regExpConstructorTable, jsCast<RegExpConstructor*>(object), propertyName, slot); + return getStaticValueSlot<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec->vm()), jsCast<RegExpConstructor*>(object), propertyName, slot); +} + +static inline RegExpConstructor* asRegExpConstructor(EncodedJSValue value) +{ + return jsCast<RegExpConstructor*>(JSValue::decode(value)); } -EncodedJSValue regExpConstructorDollar1(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) +EncodedJSValue regExpConstructorDollar1(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName) { return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 1)); } -EncodedJSValue regExpConstructorDollar2(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) +EncodedJSValue regExpConstructorDollar2(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName) { return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 2)); } -EncodedJSValue regExpConstructorDollar3(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) +EncodedJSValue regExpConstructorDollar3(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName) { return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 3)); } -EncodedJSValue regExpConstructorDollar4(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) +EncodedJSValue regExpConstructorDollar4(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName) { return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 4)); } -EncodedJSValue regExpConstructorDollar5(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) +EncodedJSValue regExpConstructorDollar5(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName) { return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 5)); } -EncodedJSValue regExpConstructorDollar6(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) +EncodedJSValue regExpConstructorDollar6(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName) { return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 6)); } -EncodedJSValue regExpConstructorDollar7(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) +EncodedJSValue regExpConstructorDollar7(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName) { return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 7)); } -EncodedJSValue regExpConstructorDollar8(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) +EncodedJSValue regExpConstructorDollar8(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName) { return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 8)); } -EncodedJSValue regExpConstructorDollar9(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) +EncodedJSValue regExpConstructorDollar9(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName) { return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 9)); } -EncodedJSValue regExpConstructorInput(ExecState*, JSObject* slotBase, EncodedJSValue, PropertyName) +EncodedJSValue regExpConstructorInput(ExecState*, EncodedJSValue slotBase, EncodedJSValue, PropertyName) { return JSValue::encode(asRegExpConstructor(slotBase)->input()); } -EncodedJSValue regExpConstructorMultiline(ExecState*, JSObject* slotBase, EncodedJSValue, PropertyName) +EncodedJSValue regExpConstructorMultiline(ExecState*, EncodedJSValue slotBase, EncodedJSValue, PropertyName) { return JSValue::encode(jsBoolean(asRegExpConstructor(slotBase)->multiline())); } -EncodedJSValue regExpConstructorLastMatch(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) +EncodedJSValue regExpConstructorLastMatch(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName) { return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 0)); } -EncodedJSValue regExpConstructorLastParen(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) +EncodedJSValue regExpConstructorLastParen(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName) { return JSValue::encode(asRegExpConstructor(slotBase)->getLastParen(exec)); } -EncodedJSValue regExpConstructorLeftContext(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) +EncodedJSValue regExpConstructorLeftContext(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName) { return JSValue::encode(asRegExpConstructor(slotBase)->getLeftContext(exec)); } -EncodedJSValue regExpConstructorRightContext(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName) +EncodedJSValue regExpConstructorRightContext(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName) { return JSValue::encode(asRegExpConstructor(slotBase)->getRightContext(exec)); } diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.h b/Source/JavaScriptCore/runtime/RegExpConstructor.h index cabee19c9..9fa8ed8bf 100644 --- a/Source/JavaScriptCore/runtime/RegExpConstructor.h +++ b/Source/JavaScriptCore/runtime/RegExpConstructor.h @@ -25,103 +25,105 @@ #include "RegExp.h" #include "RegExpCachedResult.h" #include "RegExpObject.h" +#include <wtf/OwnPtr.h> + namespace JSC { -class RegExpPrototype; + class RegExpPrototype; -class RegExpConstructor : public InternalFunction { -public: - typedef InternalFunction Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; + class RegExpConstructor : public InternalFunction { + public: + typedef InternalFunction Base; - static RegExpConstructor* create(VM& vm, Structure* structure, RegExpPrototype* regExpPrototype) - { - RegExpConstructor* constructor = new (NotNull, allocateCell<RegExpConstructor>(vm.heap)) RegExpConstructor(vm, structure, regExpPrototype); - constructor->finishCreation(vm, regExpPrototype); - return constructor; - } + static RegExpConstructor* create(VM& vm, Structure* structure, RegExpPrototype* regExpPrototype) + { + RegExpConstructor* constructor = new (NotNull, allocateCell<RegExpConstructor>(vm.heap)) RegExpConstructor(vm, structure, regExpPrototype); + constructor->finishCreation(vm, regExpPrototype); + return constructor; + } - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); - DECLARE_INFO; + DECLARE_INFO; - MatchResult performMatch(VM&, RegExp*, JSString*, const String&, int startOffset, int** ovector); - MatchResult performMatch(VM&, 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; } + void setMultiline(bool multiline) { m_multiline = multiline; } + bool multiline() const { return m_multiline; } - JSValue getBackref(ExecState*, unsigned); - JSValue getLastParen(ExecState*); - JSValue getLeftContext(ExecState*); - JSValue getRightContext(ExecState*); + JSValue getBackref(ExecState*, unsigned); + JSValue getLastParen(ExecState*); + JSValue getLeftContext(ExecState*); + JSValue getRightContext(ExecState*); - void setInput(ExecState* exec, JSString* string) { m_cachedResult.setInput(exec, this, string); } - JSString* input() { return m_cachedResult.input(); } + void setInput(ExecState* exec, JSString* string) { m_cachedResult.setInput(exec, this, string); } + JSString* input() { return m_cachedResult.input(); } - static void visitChildren(JSCell*, SlotVisitor&); + static void visitChildren(JSCell*, SlotVisitor&); -protected: - void finishCreation(VM&, RegExpPrototype*); + protected: + void finishCreation(VM&, RegExpPrototype*); + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | Base::StructureFlags; -private: - RegExpConstructor(VM&, Structure*, RegExpPrototype*); - static void destroy(JSCell*); - static ConstructType getConstructData(JSCell*, ConstructData&); - static CallType getCallData(JSCell*, CallData&); + private: + RegExpConstructor(VM&, Structure*, RegExpPrototype*); + static void destroy(JSCell*); + static ConstructType getConstructData(JSCell*, ConstructData&); + static CallType getCallData(JSCell*, CallData&); - RegExpCachedResult m_cachedResult; - bool m_multiline; - Vector<int, 32> m_ovector; -}; + RegExpCachedResult m_cachedResult; + bool m_multiline; + Vector<int, 32> m_ovector; + }; -RegExpConstructor* asRegExpConstructor(JSValue); + RegExpConstructor* asRegExpConstructor(JSValue); -JSObject* constructRegExp(ExecState*, JSGlobalObject*, const ArgList&, bool callAsConstructor = false); + JSObject* constructRegExp(ExecState*, JSGlobalObject*, const ArgList&, bool callAsConstructor = false); -inline RegExpConstructor* asRegExpConstructor(JSValue value) -{ - ASSERT(asObject(value)->inherits(RegExpConstructor::info())); - return static_cast<RegExpConstructor*>(asObject(value)); -} + inline RegExpConstructor* asRegExpConstructor(JSValue value) + { + ASSERT(asObject(value)->inherits(RegExpConstructor::info())); + return static_cast<RegExpConstructor*>(asObject(value)); + } -/* - To facilitate result caching, exec(), test(), match(), search(), and replace() dipatch regular - expression matching through the performMatch function. We use cached results to calculate, - e.g., RegExp.lastMatch and RegExp.leftParen. -*/ -ALWAYS_INLINE MatchResult RegExpConstructor::performMatch(VM& vm, RegExp* regExp, JSString* string, const String& input, int startOffset, int** ovector) -{ - int position = regExp->match(vm, input, startOffset, m_ovector); + /* + To facilitate result caching, exec(), test(), match(), search(), and replace() dipatch regular + expression matching through the performMatch function. We use cached results to calculate, + e.g., RegExp.lastMatch and RegExp.leftParen. + */ + ALWAYS_INLINE MatchResult RegExpConstructor::performMatch(VM& vm, RegExp* regExp, JSString* string, const String& input, int startOffset, int** ovector) + { + int position = regExp->match(vm, input, startOffset, m_ovector); - if (ovector) - *ovector = m_ovector.data(); + if (ovector) + *ovector = m_ovector.data(); - if (position == -1) - return MatchResult::failed(); + if (position == -1) + return MatchResult::failed(); - ASSERT(!m_ovector.isEmpty()); - ASSERT(m_ovector[0] == position); - ASSERT(m_ovector[1] >= position); - size_t end = m_ovector[1]; + ASSERT(!m_ovector.isEmpty()); + ASSERT(m_ovector[0] == position); + ASSERT(m_ovector[1] >= position); + size_t end = m_ovector[1]; - m_cachedResult.record(vm, 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(VM& vm, RegExp* regExp, JSString* string, const String& input, int startOffset) -{ - MatchResult result = regExp->match(vm, input, startOffset); - if (result) - m_cachedResult.record(vm, this, regExp, string, result); - return result; -} + return MatchResult(position, end); + } + ALWAYS_INLINE MatchResult RegExpConstructor::performMatch(VM& vm, RegExp* regExp, JSString* string, const String& input, int startOffset) + { + MatchResult result = regExp->match(vm, input, startOffset); + if (result) + m_cachedResult.record(vm, this, regExp, string, result); + return result; + } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp index 440cc9512..3eb462240 100644 --- a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp +++ b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Apple Inc. All rights reserved. + * 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 @@ -27,71 +27,98 @@ #include "RegExpMatchesArray.h" #include "ButterflyInlines.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { -static const PropertyOffset indexPropertyOffset = 100; -static const PropertyOffset inputPropertyOffset = 101; +const ClassInfo RegExpMatchesArray::s_info = {"Array", &JSArray::s_info, 0, 0, CREATE_METHOD_TABLE(RegExpMatchesArray)}; -static JSArray* tryCreateUninitializedRegExpMatchesArray(VM& vm, Structure* structure, unsigned initialLength) +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) { - unsigned vectorLength = std::max(BASE_VECTOR_LEN, initialLength); - if (vectorLength > MAX_STORAGE_VECTOR_LENGTH) - return 0; - - void* temp; - if (!vm.heap.tryAllocateStorage(0, Butterfly::totalSize(0, structure->outOfLineCapacity(), true, vectorLength * sizeof(EncodedJSValue)), &temp)) - return 0; - Butterfly* butterfly = Butterfly::fromBase(temp, 0, structure->outOfLineCapacity()); - butterfly->setVectorLength(vectorLength); - butterfly->setPublicLength(initialLength); - - return JSArray::createWithButterfly(vm, structure, butterfly); + m_input.set(vm, this, input); + m_regExp.set(vm, this, regExp); } -JSArray* createRegExpMatchesArray(ExecState* exec, JSString* input, RegExp* regExp, MatchResult result) +RegExpMatchesArray* RegExpMatchesArray::create(ExecState* exec, JSString* input, RegExp* regExp, MatchResult result) { ASSERT(result); VM& vm = exec->vm(); - JSArray* array = tryCreateUninitializedRegExpMatchesArray(vm, exec->lexicalGlobalObject()->regExpMatchesArrayStructure(), regExp->numSubpatterns() + 1); - RELEASE_ASSERT(array); + Butterfly* butterfly = createArrayButterfly(vm, 0, 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(VM& vm) +{ + Base::finishCreation(vm); +} - SamplingRegion samplingRegion("Reifying substring properties"); +void RegExpMatchesArray::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + + Base::visitChildren(thisObject, visitor); + visitor.append(&thisObject->m_input); + visitor.append(&thisObject->m_regExp); +} - array->initializeIndex(vm, 0, jsSubstring(exec, input, result.start, result.end - result.start), ArrayWithContiguous); +void RegExpMatchesArray::reifyAllProperties(ExecState* exec) +{ + ASSERT(m_state != ReifiedAll); + ASSERT(m_result); + + reifyMatchPropertyIfNecessary(exec); - if (unsigned numSubpatterns = regExp->numSubpatterns()) { + if (unsigned numSubpatterns = m_regExp->numSubpatterns()) { Vector<int, 32> subpatternResults; - int position = regExp->match(vm, input->value(exec), result.start, subpatternResults); - ASSERT_UNUSED(position, position >= 0 && static_cast<size_t>(position) == result.start); - ASSERT(result.start == static_cast<size_t>(subpatternResults[0])); - ASSERT(result.end == static_cast<size_t>(subpatternResults[1])); + 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])); for (unsigned i = 1; i <= numSubpatterns; ++i) { int start = subpatternResults[2 * i]; if (start >= 0) - array->initializeIndex(vm, i, jsSubstring(exec, input, start, subpatternResults[2 * i + 1] - start), ArrayWithContiguous); + putDirectIndex(exec, i, jsSubstring(exec, m_input.get(), start, subpatternResults[2 * i + 1] - start)); else - array->initializeIndex(vm, i, jsUndefined(), ArrayWithContiguous); + putDirectIndex(exec, i, jsUndefined()); } } - array->putDirect(vm, indexPropertyOffset, jsNumber(result.start)); - array->putDirect(vm, inputPropertyOffset, input); + putDirect(exec->vm(), exec->propertyNames().index, jsNumber(m_result.start)); + putDirect(exec->vm(), exec->propertyNames().input, m_input.get()); - return array; + m_state = ReifiedAll; +} + +void RegExpMatchesArray::reifyMatchProperty(ExecState* exec) +{ + ASSERT(m_state == ReifiedNone); + ASSERT(m_result); + putDirectIndex(exec, 0, jsSubstring(exec, m_input.get(), m_result.start, m_result.end - m_result.start)); + m_state = ReifiedMatch; +} + +JSString* RegExpMatchesArray::leftContext(ExecState* exec) +{ + if (!m_result.start) + return jsEmptyString(exec); + return jsSubstring(exec, m_input.get(), 0, m_result.start); } -Structure* createRegExpMatchesArrayStructure(VM& vm, JSGlobalObject& globalObject) +JSString* RegExpMatchesArray::rightContext(ExecState* exec) { - Structure* structure = globalObject.arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous); - PropertyOffset offset; - structure = structure->addPropertyTransition(vm, structure, vm.propertyNames->index, 0, offset); - ASSERT(offset == indexPropertyOffset); - structure = structure->addPropertyTransition(vm, structure, vm.propertyNames->input, 0, offset); - ASSERT(offset == inputPropertyOffset); - return structure; + unsigned length = m_input->length(); + if (m_result.end == length) + return jsEmptyString(exec); + return jsSubstring(exec, m_input.get(), m_result.end, length - m_result.end); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/RegExpMatchesArray.h b/Source/JavaScriptCore/runtime/RegExpMatchesArray.h index 669dd39ed..67fdcb6e1 100644 --- a/Source/JavaScriptCore/runtime/RegExpMatchesArray.h +++ b/Source/JavaScriptCore/runtime/RegExpMatchesArray.h @@ -26,8 +26,114 @@ namespace JSC { -JSArray* createRegExpMatchesArray(ExecState*, JSString*, RegExp*, MatchResult); -Structure* createRegExpMatchesArrayStructure(VM&, JSGlobalObject&); + class RegExpMatchesArray : public JSArray { + private: + RegExpMatchesArray(VM&, Butterfly*, JSGlobalObject*, JSString*, RegExp*, MatchResult); + + enum ReifiedState { ReifiedNone, ReifiedMatch, ReifiedAll }; + + public: + typedef JSArray Base; + + static RegExpMatchesArray* create(ExecState*, JSString*, RegExp*, MatchResult); + + JSString* leftContext(ExecState*); + JSString* rightContext(ExecState*); + + DECLARE_INFO; + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), ArrayWithSlowPutArrayStorage); + } + + static void visitChildren(JSCell*, SlotVisitor&); + + protected: + void finishCreation(VM&); + + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags; + + private: + ALWAYS_INLINE void reifyAllPropertiesIfNecessary(ExecState* exec) + { + if (m_state != ReifiedAll) + reifyAllProperties(exec); + } + + ALWAYS_INLINE void reifyMatchPropertyIfNecessary(ExecState* exec) + { + if (m_state == ReifiedNone) + reifyMatchProperty(exec); + } + + static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) + { + RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(object); + thisObject->reifyAllPropertiesIfNecessary(exec); + return JSArray::getOwnPropertySlot(thisObject, exec, propertyName, slot); + } + + static bool getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned propertyName, PropertySlot& slot) + { + RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(object); + if (propertyName) + thisObject->reifyAllPropertiesIfNecessary(exec); + else + thisObject->reifyMatchPropertyIfNecessary(exec); + return JSArray::getOwnPropertySlotByIndex(thisObject, exec, propertyName, slot); + } + + static void put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue v, PutPropertySlot& slot) + { + RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell); + thisObject->reifyAllPropertiesIfNecessary(exec); + JSArray::put(thisObject, exec, propertyName, v, slot); + } + + static void putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue v, bool shouldThrow) + { + RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell); + thisObject->reifyAllPropertiesIfNecessary(exec); + JSArray::putByIndex(thisObject, exec, propertyName, v, shouldThrow); + } + + static bool deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) + { + RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell); + thisObject->reifyAllPropertiesIfNecessary(exec); + return JSArray::deleteProperty(thisObject, exec, propertyName); + } + + static bool deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName) + { + RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell); + thisObject->reifyAllPropertiesIfNecessary(exec); + return JSArray::deletePropertyByIndex(thisObject, exec, propertyName); + } + + static void getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& arr, EnumerationMode mode = ExcludeDontEnumProperties) + { + RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(object); + thisObject->reifyAllPropertiesIfNecessary(exec); + JSArray::getOwnPropertyNames(thisObject, exec, arr, mode); + } + + static bool defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow) + { + RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(object); + thisObject->reifyAllPropertiesIfNecessary(exec); + return JSArray::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow); + } + + void reifyAllProperties(ExecState*); + void reifyMatchProperty(ExecState*); + + WriteBarrier<JSString> m_input; + WriteBarrier<RegExp> m_regExp; + MatchResult m_result; + ReifiedState m_state; +}; } diff --git a/Source/JavaScriptCore/runtime/RegExpObject.cpp b/Source/JavaScriptCore/runtime/RegExpObject.cpp index 60a26ef67..f3b376c0d 100644 --- a/Source/JavaScriptCore/runtime/RegExpObject.cpp +++ b/Source/JavaScriptCore/runtime/RegExpObject.cpp @@ -28,18 +28,40 @@ #include "JSArray.h" #include "JSGlobalObject.h" #include "JSString.h" +#include "Lexer.h" #include "Lookup.h" -#include "JSCInlines.h" +#include "Operations.h" #include "RegExpConstructor.h" #include "RegExpMatchesArray.h" #include "RegExpPrototype.h" +#include <wtf/PassOwnPtr.h> #include <wtf/text/StringBuilder.h> namespace JSC { +static EncodedJSValue regExpObjectGlobal(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); +static EncodedJSValue regExpObjectIgnoreCase(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); +static EncodedJSValue regExpObjectMultiline(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); +static EncodedJSValue regExpObjectSource(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); + +} // namespace JSC + +#include "RegExpObject.lut.h" + +namespace JSC { + STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(RegExpObject); -const ClassInfo RegExpObject::s_info = { "RegExp", &Base::s_info, nullptr, CREATE_METHOD_TABLE(RegExpObject) }; +const ClassInfo RegExpObject::s_info = { "RegExp", &Base::s_info, 0, ExecState::regExpTable, CREATE_METHOD_TABLE(RegExpObject) }; + +/* Source for RegExpObject.lut.h +@begin regExpTable + global regExpObjectGlobal DontDelete|ReadOnly|DontEnum + ignoreCase regExpObjectIgnoreCase DontDelete|ReadOnly|DontEnum + multiline regExpObjectMultiline DontDelete|ReadOnly|DontEnum + source regExpObjectSource DontDelete|ReadOnly|DontEnum +@end +*/ RegExpObject::RegExpObject(VM& vm, Structure* structure, RegExp* regExp) : JSNonFinalObject(vm, structure) @@ -59,6 +81,9 @@ void RegExpObject::visitChildren(JSCell* cell, SlotVisitor& visitor) { RegExpObject* thisObject = jsCast<RegExpObject*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + Base::visitChildren(thisObject, visitor); visitor.append(&thisObject->m_regExp); visitor.append(&thisObject->m_lastIndex); @@ -72,7 +97,7 @@ bool RegExpObject::getOwnPropertySlot(JSObject* object, ExecState* exec, Propert slot.setValue(regExp, attributes, regExp->getLastIndex()); return true; } - return Base::getOwnPropertySlot(object, exec, propertyName, slot); + return getStaticValueSlot<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec->vm()), jsCast<RegExpObject*>(object), propertyName, slot); } bool RegExpObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) @@ -84,25 +109,18 @@ bool RegExpObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName pr void RegExpObject::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { - if (mode.includeDontEnumProperties()) + if (mode == IncludeDontEnumProperties) propertyNames.add(exec->propertyNames().lastIndex); Base::getOwnNonIndexPropertyNames(object, exec, propertyNames, mode); } void RegExpObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { - if (mode.includeDontEnumProperties()) + if (mode == IncludeDontEnumProperties) propertyNames.add(exec->propertyNames().lastIndex); Base::getPropertyNames(object, exec, propertyNames, mode); } -void RegExpObject::getGenericPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) -{ - if (mode.includeDontEnumProperties()) - propertyNames.add(exec->propertyNames().lastIndex); - Base::getGenericPropertyNames(object, exec, propertyNames, mode); -} - static bool reject(ExecState* exec, bool throwException, const char* message) { if (throwException) @@ -137,23 +155,146 @@ bool RegExpObject::defineOwnProperty(JSObject* object, ExecState* exec, Property return Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow); } -static void regExpObjectSetLastIndexStrict(ExecState* exec, JSObject* slotBase, EncodedJSValue, EncodedJSValue value) +static inline RegExpObject* asRegExpObject(EncodedJSValue value) +{ + return jsCast<RegExpObject*>(JSValue::decode(value)); +} + +EncodedJSValue regExpObjectGlobal(ExecState*, EncodedJSValue slotBase, EncodedJSValue, PropertyName) +{ + return JSValue::encode(jsBoolean(asRegExpObject(slotBase)->regExp()->global())); +} + +EncodedJSValue regExpObjectIgnoreCase(ExecState*, EncodedJSValue slotBase, EncodedJSValue, PropertyName) +{ + return JSValue::encode(jsBoolean(asRegExpObject(slotBase)->regExp()->ignoreCase())); +} + +EncodedJSValue regExpObjectMultiline(ExecState*, EncodedJSValue slotBase, EncodedJSValue, PropertyName) +{ + return JSValue::encode(jsBoolean(asRegExpObject(slotBase)->regExp()->multiline())); +} + +template <typename CharacterType> +static inline void appendLineTerminatorEscape(StringBuilder&, CharacterType); + +template <> +inline void appendLineTerminatorEscape<LChar>(StringBuilder& builder, LChar lineTerminator) +{ + if (lineTerminator == '\n') + builder.append('n'); + else + builder.append('r'); +} + +template <> +inline void appendLineTerminatorEscape<UChar>(StringBuilder& builder, UChar lineTerminator) { - asRegExpObject(slotBase)->setLastIndex(exec, JSValue::decode(value), true); + if (lineTerminator == '\n') + builder.append('n'); + else if (lineTerminator == '\r') + builder.append('r'); + else if (lineTerminator == 0x2028) + builder.appendLiteral("u2028"); + else + builder.appendLiteral("u2029"); +} + +template <typename CharacterType> +static inline JSValue regExpObjectSourceInternal(ExecState* exec, String pattern, const CharacterType* characters, unsigned length) +{ + bool previousCharacterWasBackslash = false; + bool inBrackets = false; + bool shouldEscape = false; + + // 15.10.6.4 specifies that RegExp.prototype.toString must return '/' + source + '/', + // and also states that the result must be a valid RegularExpressionLiteral. '//' is + // not a valid RegularExpressionLiteral (since it is a single line comment), and hence + // source cannot ever validly be "". If the source is empty, return a different Pattern + // that would match the same thing. + if (!length) + return jsNontrivialString(exec, ASCIILiteral("(?:)")); + + // early return for strings that don't contain a forwards slash and LineTerminator + for (unsigned i = 0; i < length; ++i) { + CharacterType ch = characters[i]; + if (!previousCharacterWasBackslash) { + if (inBrackets) { + if (ch == ']') + inBrackets = false; + } else { + if (ch == '/') { + shouldEscape = true; + break; + } + if (ch == '[') + inBrackets = true; + } + } + + if (Lexer<CharacterType>::isLineTerminator(ch)) { + shouldEscape = true; + break; + } + + if (previousCharacterWasBackslash) + previousCharacterWasBackslash = false; + else + previousCharacterWasBackslash = ch == '\\'; + } + + if (!shouldEscape) + return jsString(exec, pattern); + + previousCharacterWasBackslash = false; + inBrackets = false; + StringBuilder result; + for (unsigned i = 0; i < length; ++i) { + CharacterType ch = characters[i]; + if (!previousCharacterWasBackslash) { + if (inBrackets) { + if (ch == ']') + inBrackets = false; + } else { + if (ch == '/') + result.append('\\'); + else if (ch == '[') + inBrackets = true; + } + } + + // escape LineTerminator + if (Lexer<CharacterType>::isLineTerminator(ch)) { + if (!previousCharacterWasBackslash) + result.append('\\'); + + appendLineTerminatorEscape<CharacterType>(result, ch); + } else + result.append(ch); + + if (previousCharacterWasBackslash) + previousCharacterWasBackslash = false; + else + previousCharacterWasBackslash = ch == '\\'; + } + + return jsString(exec, result.toString()); } -static void regExpObjectSetLastIndexNonStrict(ExecState* exec, JSObject* slotBase, EncodedJSValue, EncodedJSValue value) + + +EncodedJSValue regExpObjectSource(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName) { - asRegExpObject(slotBase)->setLastIndex(exec, JSValue::decode(value), false); + String pattern = asRegExpObject(slotBase)->regExp()->pattern(); + if (pattern.is8Bit()) + return JSValue::encode(regExpObjectSourceInternal(exec, pattern, pattern.characters8(), pattern.length())); + return JSValue::encode(regExpObjectSourceInternal(exec, pattern, pattern.characters16(), pattern.length())); } void RegExpObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { if (propertyName == exec->propertyNames().lastIndex) { asRegExpObject(cell)->setLastIndex(exec, value, slot.isStrictMode()); - slot.setCustomProperty(asRegExpObject(cell), slot.isStrictMode() - ? regExpObjectSetLastIndexStrict - : regExpObjectSetLastIndexNonStrict); return; } Base::put(cell, exec, propertyName, value, slot); @@ -162,7 +303,7 @@ void RegExpObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue RegExpObject::exec(ExecState* exec, JSString* string) { if (MatchResult result = match(exec, string)) - return createRegExpMatchesArray(exec, string, regExp(), result); + return RegExpMatchesArray::create(exec, string, regExp(), result); return jsNull(); } diff --git a/Source/JavaScriptCore/runtime/RegExpObject.h b/Source/JavaScriptCore/runtime/RegExpObject.h index a1f571d9f..2b49ba2a4 100644 --- a/Source/JavaScriptCore/runtime/RegExpObject.h +++ b/Source/JavaScriptCore/runtime/RegExpObject.h @@ -26,82 +26,82 @@ namespace JSC { -class RegExpObject : public JSNonFinalObject { -public: - typedef JSNonFinalObject Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames; - - static RegExpObject* create(VM& vm, Structure* structure, RegExp* regExp) - { - RegExpObject* object = new (NotNull, allocateCell<RegExpObject>(vm.heap)) RegExpObject(vm, structure, regExp); - object->finishCreation(vm); - return object; - } - - 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) - { - m_lastIndex.setWithoutWriteBarrier(jsNumber(lastIndex)); - if (LIKELY(m_lastIndexIsWritable)) + class RegExpObject : public JSNonFinalObject { + public: + typedef JSNonFinalObject Base; + + static RegExpObject* create(VM& vm, Structure* structure, RegExp* regExp) + { + RegExpObject* object = new (NotNull, allocateCell<RegExpObject>(vm.heap)) RegExpObject(vm, structure, regExp); + object->finishCreation(vm); + return object; + } + + 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) + { m_lastIndex.setWithoutWriteBarrier(jsNumber(lastIndex)); - else - throwTypeError(exec, StrictModeReadonlyPropertyWriteError); - } - void setLastIndex(ExecState* exec, JSValue lastIndex, bool shouldThrow) - { - if (LIKELY(m_lastIndexIsWritable)) - m_lastIndex.set(exec->vm(), this, lastIndex); - else if (shouldThrow) - throwTypeError(exec, StrictModeReadonlyPropertyWriteError); - } - JSValue getLastIndex() const - { - return m_lastIndex.get(); - } - - bool test(ExecState* exec, JSString* string) { return match(exec, string); } - JSValue exec(ExecState*, JSString*); - - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); - static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); - - DECLARE_EXPORT_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + if (LIKELY(m_lastIndexIsWritable)) + m_lastIndex.setWithoutWriteBarrier(jsNumber(lastIndex)); + else + throwTypeError(exec, StrictModeReadonlyPropertyWriteError); + } + void setLastIndex(ExecState* exec, JSValue lastIndex, bool shouldThrow) + { + if (LIKELY(m_lastIndexIsWritable)) + m_lastIndex.set(exec->vm(), this, lastIndex); + else if (shouldThrow) + throwTypeError(exec, StrictModeReadonlyPropertyWriteError); + } + JSValue getLastIndex() const + { + return m_lastIndex.get(); + } + + bool test(ExecState* exec, JSString* string) { return match(exec, string); } + JSValue exec(ExecState*, JSString*); + + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); + + DECLARE_EXPORT_INFO; + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } + + protected: + JS_EXPORT_PRIVATE RegExpObject(VM&, Structure*, RegExp*); + JS_EXPORT_PRIVATE void finishCreation(VM&); + + static const unsigned StructureFlags = OverridesVisitChildren | OverridesGetOwnPropertySlot | Base::StructureFlags; + + static void visitChildren(JSCell*, SlotVisitor&); + + JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName); + JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow); + + private: + MatchResult match(ExecState*, JSString*); + + WriteBarrier<RegExp> m_regExp; + WriteBarrier<Unknown> m_lastIndex; + bool m_lastIndexIsWritable; + }; + + RegExpObject* asRegExpObject(JSValue); + + inline RegExpObject* asRegExpObject(JSValue value) { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + ASSERT(asObject(value)->inherits(RegExpObject::info())); + return static_cast<RegExpObject*>(asObject(value)); } -protected: - JS_EXPORT_PRIVATE RegExpObject(VM&, Structure*, RegExp*); - JS_EXPORT_PRIVATE void finishCreation(VM&); - - static void visitChildren(JSCell*, SlotVisitor&); - - JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName); - JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - JS_EXPORT_PRIVATE static void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow); - -private: - MatchResult match(ExecState*, JSString*); - - WriteBarrier<RegExp> m_regExp; - WriteBarrier<Unknown> m_lastIndex; - bool m_lastIndexIsWritable; -}; - -RegExpObject* asRegExpObject(JSValue); - -inline RegExpObject* asRegExpObject(JSValue value) -{ - ASSERT(asObject(value)->inherits(RegExpObject::info())); - return static_cast<RegExpObject*>(asObject(value)); -} - } // namespace JSC #endif // RegExpObject_h diff --git a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp index fb6fc5f4a..89d7ac1b8 100644 --- a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp +++ b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp @@ -29,9 +29,8 @@ #include "JSObject.h" #include "JSString.h" #include "JSStringBuilder.h" -#include "Lexer.h" #include "ObjectPrototype.h" -#include "JSCInlines.h" +#include "Operations.h" #include "RegExpObject.h" #include "RegExp.h" #include "RegExpCache.h" @@ -43,11 +42,6 @@ static EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState*); static EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState*); static EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState*); static EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState*); -static EncodedJSValue JSC_HOST_CALL regExpProtoGetterGlobal(ExecState*); -static EncodedJSValue JSC_HOST_CALL regExpProtoGetterIgnoreCase(ExecState*); -static EncodedJSValue JSC_HOST_CALL regExpProtoGetterMultiline(ExecState*); -static EncodedJSValue JSC_HOST_CALL regExpProtoGetterSource(ExecState*); -static EncodedJSValue JSC_HOST_CALL regExpProtoGetterFlags(ExecState*); } @@ -55,19 +49,14 @@ static EncodedJSValue JSC_HOST_CALL regExpProtoGetterFlags(ExecState*); namespace JSC { -const ClassInfo RegExpPrototype::s_info = { "RegExp", &RegExpObject::s_info, ®ExpPrototypeTable, CREATE_METHOD_TABLE(RegExpPrototype) }; +const ClassInfo RegExpPrototype::s_info = { "RegExp", &RegExpObject::s_info, 0, ExecState::regExpPrototypeTable, CREATE_METHOD_TABLE(RegExpPrototype) }; /* Source for RegExpPrototype.lut.h @begin regExpPrototypeTable - compile regExpProtoFuncCompile DontEnum|Function 2 - exec regExpProtoFuncExec DontEnum|Function 1 - test regExpProtoFuncTest DontEnum|Function 1 - toString regExpProtoFuncToString DontEnum|Function 0 - global regExpProtoGetterGlobal DontEnum|Accessor - ignoreCase regExpProtoGetterIgnoreCase DontEnum|Accessor - multiline regExpProtoGetterMultiline DontEnum|Accessor - source regExpProtoGetterSource DontEnum|Accessor - flags regExpProtoGetterFlags DontEnum|Accessor + compile regExpProtoFuncCompile DontEnum|Function 2 + exec regExpProtoFuncExec DontEnum|Function 1 + test regExpProtoFuncTest DontEnum|Function 1 + toString regExpProtoFuncToString DontEnum|Function 0 @end */ @@ -78,14 +67,14 @@ RegExpPrototype::RegExpPrototype(VM& vm, Structure* structure, RegExp* regExp) bool RegExpPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot) { - return getStaticFunctionSlot<Base>(exec, regExpPrototypeTable, jsCast<RegExpPrototype*>(object), propertyName, slot); + return getStaticFunctionSlot<RegExpObject>(exec, ExecState::regExpPrototypeTable(exec->vm()), jsCast<RegExpPrototype*>(object), propertyName, slot); } // ------------------------------ Functions --------------------------- EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(RegExpObject::info())) return throwVMTypeError(exec); return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->test(exec, exec->argument(0).toString(exec)))); @@ -93,7 +82,7 @@ EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState* exec) EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(RegExpObject::info())) return throwVMTypeError(exec); return JSValue::encode(asRegExpObject(thisValue)->exec(exec, exec->argument(0).toString(exec))); @@ -101,7 +90,7 @@ EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec) EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(RegExpObject::info())) return throwVMTypeError(exec); @@ -137,214 +126,29 @@ EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec) return JSValue::encode(jsUndefined()); } -typedef std::array<char, 3 + 1> FlagsString; // 3 different flags and a null character terminator. - -static inline FlagsString flagsString(ExecState* exec, JSObject* regexp) -{ - FlagsString string; - - JSValue globalValue = regexp->get(exec, exec->propertyNames().global); - if (exec->hadException()) - return string; - JSValue ignoreCaseValue = regexp->get(exec, exec->propertyNames().ignoreCase); - if (exec->hadException()) - return string; - JSValue multilineValue = regexp->get(exec, exec->propertyNames().multiline); - - unsigned index = 0; - if (globalValue.toBoolean(exec)) - string[index++] = 'g'; - if (ignoreCaseValue.toBoolean(exec)) - string[index++] = 'i'; - if (multilineValue.toBoolean(exec)) - string[index++] = 'm'; - ASSERT(index < string.size()); - string[index] = 0; - return string; -} - EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState* exec) { - JSValue thisValue = exec->thisValue(); - if (!thisValue.isObject()) + JSValue thisValue = exec->hostThisValue(); + if (!thisValue.inherits(RegExpObject::info())) return throwVMTypeError(exec); - JSObject* thisObject = asObject(thisValue); + RegExpObject* thisObject = asRegExpObject(thisValue); StringRecursionChecker checker(exec, thisObject); if (JSValue earlyReturnValue = checker.earlyReturnValue()) return JSValue::encode(earlyReturnValue); - JSValue sourceValue = thisObject->get(exec, exec->propertyNames().source); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - String source = sourceValue.toString(exec)->value(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - auto flags = flagsString(exec, thisObject); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - return JSValue::encode(jsMakeNontrivialString(exec, '/', source, '/', flags.data())); -} - -EncodedJSValue JSC_HOST_CALL regExpProtoGetterGlobal(ExecState* exec) -{ - JSValue thisValue = exec->thisValue(); - if (!thisValue.inherits(RegExpObject::info())) - return throwVMTypeError(exec); - - return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->regExp()->global())); -} - -EncodedJSValue JSC_HOST_CALL regExpProtoGetterIgnoreCase(ExecState* exec) -{ - JSValue thisValue = exec->thisValue(); - if (!thisValue.inherits(RegExpObject::info())) - return throwVMTypeError(exec); - - return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->regExp()->ignoreCase())); -} - -EncodedJSValue JSC_HOST_CALL regExpProtoGetterMultiline(ExecState* exec) -{ - JSValue thisValue = exec->thisValue(); - if (!thisValue.inherits(RegExpObject::info())) - return throwVMTypeError(exec); - - return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->regExp()->multiline())); -} - -EncodedJSValue JSC_HOST_CALL regExpProtoGetterFlags(ExecState* exec) -{ - JSValue thisValue = exec->thisValue(); - if (!thisValue.isObject()) - return throwVMTypeError(exec); - - auto flags = flagsString(exec, asObject(thisValue)); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - return JSValue::encode(jsString(exec, flags.data())); -} - -template <typename CharacterType> -static inline void appendLineTerminatorEscape(StringBuilder&, CharacterType); - -template <> -inline void appendLineTerminatorEscape<LChar>(StringBuilder& builder, LChar lineTerminator) -{ - if (lineTerminator == '\n') - builder.append('n'); - else - builder.append('r'); -} - -template <> -inline void appendLineTerminatorEscape<UChar>(StringBuilder& builder, UChar lineTerminator) -{ - if (lineTerminator == '\n') - builder.append('n'); - else if (lineTerminator == '\r') - builder.append('r'); - else if (lineTerminator == 0x2028) - builder.appendLiteral("u2028"); - else - builder.appendLiteral("u2029"); -} - -template <typename CharacterType> -static inline JSValue regExpProtoGetterSourceInternal(ExecState* exec, const String& pattern, const CharacterType* characters, unsigned length) -{ - bool previousCharacterWasBackslash = false; - bool inBrackets = false; - bool shouldEscape = false; - - // 15.10.6.4 specifies that RegExp.prototype.toString must return '/' + source + '/', - // and also states that the result must be a valid RegularExpressionLiteral. '//' is - // not a valid RegularExpressionLiteral (since it is a single line comment), and hence - // source cannot ever validly be "". If the source is empty, return a different Pattern - // that would match the same thing. - if (!length) - return jsNontrivialString(exec, ASCIILiteral("(?:)")); - - // early return for strings that don't contain a forwards slash and LineTerminator - for (unsigned i = 0; i < length; ++i) { - CharacterType ch = characters[i]; - if (!previousCharacterWasBackslash) { - if (inBrackets) { - if (ch == ']') - inBrackets = false; - } else { - if (ch == '/') { - shouldEscape = true; - break; - } - if (ch == '[') - inBrackets = true; - } - } - - if (Lexer<CharacterType>::isLineTerminator(ch)) { - shouldEscape = true; - break; - } - - if (previousCharacterWasBackslash) - previousCharacterWasBackslash = false; - else - previousCharacterWasBackslash = ch == '\\'; - } - - if (!shouldEscape) - return jsString(exec, pattern); - - previousCharacterWasBackslash = false; - inBrackets = false; - StringBuilder result; - for (unsigned i = 0; i < length; ++i) { - CharacterType ch = characters[i]; - if (!previousCharacterWasBackslash) { - if (inBrackets) { - if (ch == ']') - inBrackets = false; - } else { - if (ch == '/') - result.append('\\'); - else if (ch == '[') - inBrackets = true; - } - } - - // escape LineTerminator - if (Lexer<CharacterType>::isLineTerminator(ch)) { - if (!previousCharacterWasBackslash) - result.append('\\'); - - appendLineTerminatorEscape<CharacterType>(result, ch); - } else - result.append(ch); - - if (previousCharacterWasBackslash) - previousCharacterWasBackslash = false; - else - previousCharacterWasBackslash = ch == '\\'; - } - - return jsString(exec, result.toString()); -} - -EncodedJSValue JSC_HOST_CALL regExpProtoGetterSource(ExecState* exec) -{ - JSValue thisValue = exec->thisValue(); - if (!thisValue.inherits(RegExpObject::info())) - return throwVMTypeError(exec); - - String pattern = asRegExpObject(thisValue)->regExp()->pattern(); - if (pattern.is8Bit()) - return JSValue::encode(regExpProtoGetterSourceInternal(exec, pattern, pattern.characters8(), pattern.length())); - return JSValue::encode(regExpProtoGetterSourceInternal(exec, pattern, pattern.characters16(), pattern.length())); + char postfix[5] = { '/', 0, 0, 0, 0 }; + int index = 1; + if (thisObject->get(exec, exec->propertyNames().global).toBoolean(exec)) + postfix[index++] = 'g'; + if (thisObject->get(exec, exec->propertyNames().ignoreCase).toBoolean(exec)) + postfix[index++] = 'i'; + if (thisObject->get(exec, exec->propertyNames().multiline).toBoolean(exec)) + postfix[index] = 'm'; + String source = thisObject->get(exec, exec->propertyNames().source).toString(exec)->value(exec); + // If source is empty, use "/(?:)/" to avoid colliding with comment syntax + return JSValue::encode(jsMakeNontrivialString(exec, "/", source, postfix)); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/RegExpPrototype.h b/Source/JavaScriptCore/runtime/RegExpPrototype.h index cb6ee6974..e9fef179b 100644 --- a/Source/JavaScriptCore/runtime/RegExpPrototype.h +++ b/Source/JavaScriptCore/runtime/RegExpPrototype.h @@ -26,31 +26,31 @@ namespace JSC { -class RegExpPrototype : public RegExpObject { -public: - typedef RegExpObject Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; - - static RegExpPrototype* create(VM& vm, Structure* structure, RegExp* regExp) - { - RegExpPrototype* prototype = new (NotNull, allocateCell<RegExpPrototype>(vm.heap)) RegExpPrototype(vm, structure, regExp); - prototype->finishCreation(vm); - return prototype; - } - - DECLARE_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } - -protected: - RegExpPrototype(VM&, Structure*, RegExp*); - -private: - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); -}; + class RegExpPrototype : public RegExpObject { + public: + typedef RegExpObject Base; + + static RegExpPrototype* create(VM& vm, Structure* structure, RegExp* regExp) + { + RegExpPrototype* prototype = new (NotNull, allocateCell<RegExpPrototype>(vm.heap)) RegExpPrototype(vm, structure, regExp); + prototype->finishCreation(vm); + return prototype; + } + + DECLARE_INFO; + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } + + protected: + RegExpPrototype(VM&, Structure*, RegExp*); + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | RegExpObject::StructureFlags; + + private: + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/RegisterPreservationMode.h b/Source/JavaScriptCore/runtime/RegisterPreservationMode.h deleted file mode 100644 index 3351db4a3..000000000 --- a/Source/JavaScriptCore/runtime/RegisterPreservationMode.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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 RegisterPreservationMode_h -#define RegisterPreservationMode_h - -namespace JSC { - -enum RegisterPreservationMode { - RegisterPreservationNotRequired, - MustPreserveRegisters -}; - -} // namespace JSC - -#endif // RegisterPreservationMode_h - diff --git a/Source/JavaScriptCore/runtime/RuntimeFlags.h b/Source/JavaScriptCore/runtime/RuntimeFlags.h deleted file mode 100644 index 8cd30c6da..000000000 --- a/Source/JavaScriptCore/runtime/RuntimeFlags.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. - * - * 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 RuntimeFlags_h -#define RuntimeFlags_h - -#include <initializer_list> - -namespace JSC { - -// macro(name, isEnabledFlag) -#define JSC_RUNTIME_FLAG(macro) - -class RuntimeFlags { -private: - enum RuntimeFlagShiftValue : unsigned { -#define JSC_DECLARE_RUNTIME_FLAG_SHIFT_VALUE(name, isEnabledFlag) shiftValueFor##name, - JSC_RUNTIME_FLAG(JSC_DECLARE_RUNTIME_FLAG_SHIFT_VALUE) -#undef JSC_DECLARE_RUNTIME_FLAG_SHIFT_VALUE - }; - -public: - enum RuntimeFlag : unsigned { -#define JSC_DECLARE_RUNTIME_FLAG(name, isEnabledFlag) name = 1u << (shiftValueFor##name), - JSC_RUNTIME_FLAG(JSC_DECLARE_RUNTIME_FLAG) -#undef JSC_DECLARE_RUNTIME_FLAG - }; - -#define JSC_DECLARE_RUNTIME_FLAG_ACCESSOR(name, isEnabledFlag) \ - void set##name(bool value)\ - {\ - if (value)\ - m_flags |= name;\ - else\ - m_flags &= (~name);\ - }\ - bool is##name() const\ - {\ - return m_flags & name;\ - } - JSC_RUNTIME_FLAG(JSC_DECLARE_RUNTIME_FLAG_ACCESSOR) -#undef JSC_DECLARE_RUNTIME_FLAG_ACCESSOR - - RuntimeFlags() - : RuntimeFlags(0u) - { - } - - RuntimeFlags(std::initializer_list<RuntimeFlag> initializerList) - : RuntimeFlags() - { - for (RuntimeFlag flag : initializerList) - m_flags |= flag; - } - - explicit RuntimeFlags(unsigned flags) - : m_flags(flags) - { - } - - static RuntimeFlags createAllEnabled() - { - return RuntimeFlags( -#define JSC_USE_RUNTIME_FLAG(name, isEnabledFlag) ((isEnabledFlag) ? name : 0u) | - JSC_RUNTIME_FLAG(JSC_USE_RUNTIME_FLAG) -#undef JSC_USE_RUNTIME_FLAG - 0u - ); - } - -private: - unsigned m_flags; -}; - -} // namespace JSC - -#endif // RuntimeFlags_h diff --git a/Source/JavaScriptCore/runtime/RuntimeType.cpp b/Source/JavaScriptCore/runtime/RuntimeType.cpp deleted file mode 100644 index 4e7b3a7e1..000000000 --- a/Source/JavaScriptCore/runtime/RuntimeType.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2015 Apple Inc. All rights reserved. - * Copyright (C) Saam Barati <saambarati1@gmail.com>. 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 "RuntimeType.h" - -#include "JSCJSValue.h" -#include "JSCJSValueInlines.h" - -namespace JSC { - -RuntimeType runtimeTypeForValue(JSValue value) -{ - if (value.isUndefined()) - return TypeUndefined; - if (value.isNull()) - return TypeNull; - if (value.isMachineInt()) - return TypeMachineInt; - if (value.isNumber()) - return TypeNumber; - if (value.isString()) - return TypeString; - if (value.isBoolean()) - return TypeBoolean; - if (value.isObject()) - return TypeObject; - if (value.isFunction()) - return TypeFunction; - if (value.isSymbol()) - return TypeSymbol; - - return TypeNothing; -} - -String runtimeTypeAsString(RuntimeType type) -{ - if (type == TypeUndefined) - return ASCIILiteral("Undefined"); - if (type == TypeNull) - return ASCIILiteral("Null"); - if (type == TypeMachineInt) - return ASCIILiteral("Integer"); - if (type == TypeNumber) - return ASCIILiteral("Number"); - if (type == TypeString) - return ASCIILiteral("String"); - if (type == TypeObject) - return ASCIILiteral("Object"); - if (type == TypeBoolean) - return ASCIILiteral("Boolean"); - if (type == TypeFunction) - return ASCIILiteral("Function"); - if (type == TypeNothing) - return ASCIILiteral("(Nothing)"); - - RELEASE_ASSERT_NOT_REACHED(); - return emptyString(); -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/RuntimeType.h b/Source/JavaScriptCore/runtime/RuntimeType.h deleted file mode 100644 index d57b8fbf0..000000000 --- a/Source/JavaScriptCore/runtime/RuntimeType.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2015 Apple Inc. All rights reserved. - * Copyright (C) Saam Barati <saambarati1@gmail.com>. 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 RuntimeType_h -#define RuntimeType_h - -#include <wtf/text/WTFString.h> - -namespace JSC { - -enum RuntimeType : uint16_t { - TypeNothing = 0x0, - TypeFunction = 0x1, - TypeUndefined = 0x2, - TypeNull = 0x4, - TypeBoolean = 0x8, - TypeMachineInt = 0x10, - TypeNumber = 0x20, - TypeString = 0x40, - TypeObject = 0x80, - TypeSymbol = 0x100 -}; - -typedef uint16_t RuntimeTypeMask; - -class JSValue; -RuntimeType runtimeTypeForValue(JSValue); -String runtimeTypeAsString(RuntimeType); - -ALWAYS_INLINE bool runtimeTypeIsPrimitive(RuntimeTypeMask type) -{ - return type & ~(TypeFunction | TypeObject); -} - -} // namespace JSC - -#endif // RuntimeType_h diff --git a/Source/JavaScriptCore/runtime/SamplingCounter.cpp b/Source/JavaScriptCore/runtime/SamplingCounter.cpp index b5564b4f9..9826b88e4 100644 --- a/Source/JavaScriptCore/runtime/SamplingCounter.cpp +++ b/Source/JavaScriptCore/runtime/SamplingCounter.cpp @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * diff --git a/Source/JavaScriptCore/runtime/SamplingCounter.h b/Source/JavaScriptCore/runtime/SamplingCounter.h index d1acdcee5..8413b5458 100644 --- a/Source/JavaScriptCore/runtime/SamplingCounter.h +++ b/Source/JavaScriptCore/runtime/SamplingCounter.h @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * diff --git a/Source/JavaScriptCore/runtime/ScopeOffset.cpp b/Source/JavaScriptCore/runtime/ScopeOffset.cpp deleted file mode 100644 index 1753165e5..000000000 --- a/Source/JavaScriptCore/runtime/ScopeOffset.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2015 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 "ScopeOffset.h" - -namespace JSC { - -void ScopeOffset::dump(PrintStream& out) const -{ - if (!*this) { - out.print("scopeInvalid"); - return; - } - - out.print("scope", offset()); -} - -} // namespace JSC - diff --git a/Source/JavaScriptCore/runtime/ScopeOffset.h b/Source/JavaScriptCore/runtime/ScopeOffset.h deleted file mode 100644 index 4dbd18605..000000000 --- a/Source/JavaScriptCore/runtime/ScopeOffset.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2015 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 ScopeOffset_h -#define ScopeOffset_h - -#include "GenericOffset.h" -#include <wtf/PrintStream.h> - -namespace JSC { - -// This is an offset into a scope of some kind. It could be an activation scope or it could be a -// global object. -class ScopeOffset : public GenericOffset<ScopeOffset> { -public: - ScopeOffset() { } - - explicit ScopeOffset(unsigned offset) - : GenericOffset(offset) - { - } - - void dump(PrintStream&) const; -}; - -} // namespace JSC - -#endif // ScopeOffset_h - diff --git a/Source/JavaScriptCore/runtime/ScopedArguments.cpp b/Source/JavaScriptCore/runtime/ScopedArguments.cpp deleted file mode 100644 index a5a2fc75b..000000000 --- a/Source/JavaScriptCore/runtime/ScopedArguments.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2015 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 "ScopedArguments.h" - -#include "GenericArgumentsInlines.h" -#include "JSCInlines.h" - -namespace JSC { - -STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ScopedArguments); - -const ClassInfo ScopedArguments::s_info = { "Arguments", &Base::s_info, 0, CREATE_METHOD_TABLE(ScopedArguments) }; - -ScopedArguments::ScopedArguments(VM& vm, Structure* structure, unsigned totalLength) - : GenericArguments(vm, structure) - , m_overrodeThings(false) - , m_totalLength(totalLength) -{ -} - -void ScopedArguments::finishCreation(VM& vm, JSFunction* callee, ScopedArgumentsTable* table, JSLexicalEnvironment* scope) -{ - Base::finishCreation(vm); - m_callee.set(vm, this, callee); - m_table.set(vm, this, table); - m_scope.set(vm, this, scope); -} - -ScopedArguments* ScopedArguments::createUninitialized(VM& vm, Structure* structure, JSFunction* callee, ScopedArgumentsTable* table, JSLexicalEnvironment* scope, unsigned totalLength) -{ - unsigned overflowLength; - if (totalLength > table->length()) - overflowLength = totalLength - table->length(); - else - overflowLength = 0; - ScopedArguments* result = new ( - NotNull, - allocateCell<ScopedArguments>(vm.heap, allocationSize(overflowLength))) - ScopedArguments(vm, structure, totalLength); - result->finishCreation(vm, callee, table, scope); - return result; -} - -ScopedArguments* ScopedArguments::create(VM& vm, Structure* structure, JSFunction* callee, ScopedArgumentsTable* table, JSLexicalEnvironment* scope, unsigned totalLength) -{ - ScopedArguments* result = - createUninitialized(vm, structure, callee, table, scope, totalLength); - - unsigned namedLength = table->length(); - for (unsigned i = namedLength; i < totalLength; ++i) - result->overflowStorage()[i - namedLength].clear(); - - return result; -} - -ScopedArguments* ScopedArguments::createByCopying(ExecState* exec, ScopedArgumentsTable* table, JSLexicalEnvironment* scope) -{ - return createByCopyingFrom( - exec->vm(), exec->lexicalGlobalObject()->scopedArgumentsStructure(), - exec->registers() + CallFrame::argumentOffset(0), exec->argumentCount(), - jsCast<JSFunction*>(exec->callee()), table, scope); -} - -ScopedArguments* ScopedArguments::createByCopyingFrom(VM& vm, Structure* structure, Register* argumentsStart, unsigned totalLength, JSFunction* callee, ScopedArgumentsTable* table, JSLexicalEnvironment* scope) -{ - ScopedArguments* result = - createUninitialized(vm, structure, callee, table, scope, totalLength); - - unsigned namedLength = table->length(); - for (unsigned i = namedLength; i < totalLength; ++i) - result->overflowStorage()[i - namedLength].set(vm, result, argumentsStart[i].jsValue()); - - return result; -} - -void ScopedArguments::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - ScopedArguments* thisObject = static_cast<ScopedArguments*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - Base::visitChildren(thisObject, visitor); - - visitor.append(&thisObject->m_callee); - visitor.append(&thisObject->m_table); - visitor.append(&thisObject->m_scope); - - if (thisObject->m_totalLength > thisObject->m_table->length()) { - visitor.appendValues( - thisObject->overflowStorage(), thisObject->m_totalLength - thisObject->m_table->length()); - } -} - -Structure* ScopedArguments::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) -{ - return Structure::create(vm, globalObject, prototype, TypeInfo(ScopedArgumentsType, StructureFlags), info()); -} - -void ScopedArguments::overrideThings(VM& vm) -{ - RELEASE_ASSERT(!m_overrodeThings); - - putDirect(vm, vm.propertyNames->length, jsNumber(m_table->length()), DontEnum); - putDirect(vm, vm.propertyNames->callee, m_callee.get(), DontEnum); - putDirect(vm, vm.propertyNames->iteratorSymbol, globalObject()->arrayProtoValuesFunction(), DontEnum); - - m_overrodeThings = true; -} - -void ScopedArguments::overrideThingsIfNecessary(VM& vm) -{ - if (!m_overrodeThings) - overrideThings(vm); -} - -void ScopedArguments::overrideArgument(VM& vm, uint32_t i) -{ - ASSERT_WITH_SECURITY_IMPLICATION(i < m_totalLength); - unsigned namedLength = m_table->length(); - if (i < namedLength) - m_table.set(vm, this, m_table->set(vm, i, ScopeOffset())); - else - overflowStorage()[i - namedLength].clear(); -} - -void ScopedArguments::copyToArguments(ExecState* exec, VirtualRegister firstElementDest, unsigned offset, unsigned length) -{ - GenericArguments::copyToArguments(exec, firstElementDest, offset, length); -} - -} // namespace JSC - diff --git a/Source/JavaScriptCore/runtime/ScopedArguments.h b/Source/JavaScriptCore/runtime/ScopedArguments.h deleted file mode 100644 index 8d36a1bab..000000000 --- a/Source/JavaScriptCore/runtime/ScopedArguments.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2015 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 ScopedArguments_h -#define ScopedArguments_h - -#include "GenericArguments.h" -#include "JSLexicalEnvironment.h" - -namespace JSC { - -// This is an Arguments-class object that we create when you say "arguments" inside a function, -// and one or more of the arguments may be captured in the function's activation. The function -// will copy its formally declared arguments into the activation and then create this object. This -// object will store the overflow arguments, if there are any. This object will use the symbol -// table's ScopedArgumentsTable and the activation, or its overflow storage, to handle all indexed -// lookups. -class ScopedArguments : public GenericArguments<ScopedArguments> { -private: - ScopedArguments(VM&, Structure*, unsigned totalLength); - void finishCreation(VM&, JSFunction* callee, ScopedArgumentsTable*, JSLexicalEnvironment*); - -public: - // Creates an arguments object but leaves it uninitialized. This is dangerous if we GC right - // after allocation. - static ScopedArguments* createUninitialized(VM&, Structure*, JSFunction* callee, ScopedArgumentsTable*, JSLexicalEnvironment*, unsigned totalLength); - - // Creates an arguments object and initializes everything to the empty value. Use this if you - // cannot guarantee that you'll immediately initialize all of the elements. - static ScopedArguments* create(VM&, Structure*, JSFunction* callee, ScopedArgumentsTable*, JSLexicalEnvironment*, unsigned totalLength); - - // Creates an arguments object by copying the arguments from the stack. - static ScopedArguments* createByCopying(ExecState*, ScopedArgumentsTable*, JSLexicalEnvironment*); - - // Creates an arguments object by copying the arguments from a well-defined stack location. - static ScopedArguments* createByCopyingFrom(VM&, Structure*, Register* argumentsStart, unsigned totalLength, JSFunction* callee, ScopedArgumentsTable*, JSLexicalEnvironment*); - - static void visitChildren(JSCell*, SlotVisitor&); - - uint32_t internalLength() const - { - return m_totalLength; - } - - uint32_t length(ExecState* exec) const - { - if (UNLIKELY(m_overrodeThings)) - return get(exec, exec->propertyNames().length).toUInt32(exec); - return internalLength(); - } - - bool canAccessIndexQuickly(uint32_t i) const - { - if (i >= m_totalLength) - return false; - unsigned namedLength = m_table->length(); - if (i < namedLength) - return !!m_table->get(i); - return !!overflowStorage()[i - namedLength].get(); - } - - bool canAccessArgumentIndexQuicklyInDFG(uint32_t i) const - { - return canAccessIndexQuickly(i); - } - - JSValue getIndexQuickly(uint32_t i) const - { - ASSERT_WITH_SECURITY_IMPLICATION(canAccessIndexQuickly(i)); - unsigned namedLength = m_table->length(); - if (i < namedLength) - return m_scope->variableAt(m_table->get(i)).get(); - return overflowStorage()[i - namedLength].get(); - } - - void setIndexQuickly(VM& vm, uint32_t i, JSValue value) - { - ASSERT_WITH_SECURITY_IMPLICATION(canAccessIndexQuickly(i)); - unsigned namedLength = m_table->length(); - if (i < namedLength) - m_scope->variableAt(m_table->get(i)).set(vm, this, value); - else - overflowStorage()[i - namedLength].set(vm, this, value); - } - - WriteBarrier<JSFunction>& callee() - { - return m_callee; - } - - bool overrodeThings() const { return m_overrodeThings; } - void overrideThings(VM&); - void overrideThingsIfNecessary(VM&); - void overrideArgument(VM&, uint32_t index); - - void copyToArguments(ExecState*, VirtualRegister firstElementDest, unsigned offset, unsigned length); - - DECLARE_INFO; - - static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype); - - static ptrdiff_t offsetOfOverrodeThings() { return OBJECT_OFFSETOF(ScopedArguments, m_overrodeThings); } - static ptrdiff_t offsetOfTotalLength() { return OBJECT_OFFSETOF(ScopedArguments, m_totalLength); } - static ptrdiff_t offsetOfTable() { return OBJECT_OFFSETOF(ScopedArguments, m_table); } - static ptrdiff_t offsetOfScope() { return OBJECT_OFFSETOF(ScopedArguments, m_scope); } - - static size_t overflowStorageOffset() - { - return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(ScopedArguments)); - } - - static size_t allocationSize(unsigned overflowArgumentsLength) - { - return overflowStorageOffset() + sizeof(WriteBarrier<Unknown>) * overflowArgumentsLength; - } - -private: - WriteBarrier<Unknown>* overflowStorage() const - { - return bitwise_cast<WriteBarrier<Unknown>*>( - bitwise_cast<char*>(this) + overflowStorageOffset()); - } - - - bool m_overrodeThings; // True if length, callee, and caller are fully materialized in the object. - unsigned m_totalLength; // The length of declared plus overflow arguments. - WriteBarrier<JSFunction> m_callee; - WriteBarrier<ScopedArgumentsTable> m_table; - WriteBarrier<JSLexicalEnvironment> m_scope; -}; - -} // namespace JSC - -#endif // ScopedArguments_h - diff --git a/Source/JavaScriptCore/runtime/ScopedArgumentsTable.cpp b/Source/JavaScriptCore/runtime/ScopedArgumentsTable.cpp deleted file mode 100644 index 9be4797b0..000000000 --- a/Source/JavaScriptCore/runtime/ScopedArgumentsTable.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2015 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 "ScopedArgumentsTable.h" - -#include "JSCInlines.h" - -namespace JSC { - -const ClassInfo ScopedArgumentsTable::s_info = { "ScopedArgumentsTable", 0, 0, CREATE_METHOD_TABLE(ScopedArgumentsTable) }; - -ScopedArgumentsTable::ScopedArgumentsTable(VM& vm) - : Base(vm, vm.scopedArgumentsTableStructure.get()) - , m_length(0) - , m_locked(false) -{ -} - -ScopedArgumentsTable::~ScopedArgumentsTable() -{ -} - -void ScopedArgumentsTable::destroy(JSCell* cell) -{ - static_cast<ScopedArgumentsTable*>(cell)->ScopedArgumentsTable::~ScopedArgumentsTable(); -} - -ScopedArgumentsTable* ScopedArgumentsTable::create(VM& vm) -{ - ScopedArgumentsTable* result = - new (NotNull, allocateCell<ScopedArgumentsTable>(vm.heap)) ScopedArgumentsTable(vm); - result->finishCreation(vm); - return result; -} - -ScopedArgumentsTable* ScopedArgumentsTable::create(VM& vm, uint32_t length) -{ - ScopedArgumentsTable* result = create(vm); - result->m_length = length; - result->m_arguments = std::make_unique<ScopeOffset[]>(length); - return result; -} - -ScopedArgumentsTable* ScopedArgumentsTable::clone(VM& vm) -{ - ScopedArgumentsTable* result = create(vm, m_length); - for (unsigned i = m_length; i--;) - result->m_arguments[i] = m_arguments[i]; - return result; -} - -ScopedArgumentsTable* ScopedArgumentsTable::setLength(VM& vm, uint32_t newLength) -{ - if (LIKELY(!m_locked)) { - std::unique_ptr<ScopeOffset[]> newArguments = std::make_unique<ScopeOffset[]>(newLength); - for (unsigned i = std::min(m_length, newLength); i--;) - newArguments[i] = m_arguments[i]; - m_length = newLength; - m_arguments = WTF::move(newArguments); - return this; - } - - ScopedArgumentsTable* result = create(vm, newLength); - for (unsigned i = std::min(m_length, newLength); i--;) - result->m_arguments[i] = m_arguments[i]; - return result; -} - -ScopedArgumentsTable* ScopedArgumentsTable::set(VM& vm, uint32_t i, ScopeOffset value) -{ - ScopedArgumentsTable* result; - if (UNLIKELY(m_locked)) - result = clone(vm); - else - result = this; - result->at(i) = value; - return result; -} - -Structure* ScopedArgumentsTable::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) -{ - return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); -} - -} // namespace JSC - diff --git a/Source/JavaScriptCore/runtime/ScopedArgumentsTable.h b/Source/JavaScriptCore/runtime/ScopedArgumentsTable.h deleted file mode 100644 index b6d7ddc17..000000000 --- a/Source/JavaScriptCore/runtime/ScopedArgumentsTable.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2015 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 ScopedArgumentsTable_h -#define ScopedArgumentsTable_h - -#include "JSCell.h" -#include "ScopeOffset.h" -#include <wtf/Assertions.h> - -namespace JSC { - -// This class's only job is to hold onto the list of ScopeOffsets for each argument that a -// function has. Most of the time, the BytecodeGenerator will create one of these and it will -// never be modified subsequently. There is a rare case where a ScopedArguments object is created -// and aliases one of these and then decides to modify it; in that case we do copy-on-write. This -// makes sense because such modifications are so uncommon. You'd have to do something crazy like -// "delete arguments[i]" or some variant of defineOwnProperty. -class ScopedArgumentsTable final : public JSCell { -public: - typedef JSCell Base; - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; - -private: - ScopedArgumentsTable(VM&); - ~ScopedArgumentsTable(); - -public: - static ScopedArgumentsTable* create(VM&); - static ScopedArgumentsTable* create(VM&, uint32_t length); - - static const bool needsDestruction = true; - static void destroy(JSCell*); - - ScopedArgumentsTable* clone(VM&); - - uint32_t length() const { return m_length; } - ScopedArgumentsTable* setLength(VM&, uint32_t newLength); - - ScopeOffset get(uint32_t i) const - { - return const_cast<ScopedArgumentsTable*>(this)->at(i); - } - - void lock() - { - m_locked = true; - } - - ScopedArgumentsTable* set(VM&, uint32_t index, ScopeOffset); - - DECLARE_INFO; - - static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype); - - static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(ScopedArgumentsTable, m_length); } - static ptrdiff_t offsetOfArguments() { return OBJECT_OFFSETOF(ScopedArgumentsTable, m_arguments); } - -private: - ScopeOffset& at(uint32_t i) - { - ASSERT_WITH_SECURITY_IMPLICATION(i < m_length); - return m_arguments[i]; - } - - uint32_t m_length; - bool m_locked; // Being locked means that there are multiple references to this object and none of them expect to see the others' modifications. This means that modifications need to make a copy first. - std::unique_ptr<ScopeOffset[]> m_arguments; -}; - -} // namespace JSC - -#endif // ScopedArgumentsTable_h - diff --git a/Source/JavaScriptCore/runtime/SetConstructor.cpp b/Source/JavaScriptCore/runtime/SetConstructor.cpp index fb97b6d9f..b203888d3 100644 --- a/Source/JavaScriptCore/runtime/SetConstructor.cpp +++ b/Source/JavaScriptCore/runtime/SetConstructor.cpp @@ -27,18 +27,16 @@ #include "SetConstructor.h" #include "Error.h" -#include "IteratorOperations.h" #include "JSCJSValueInlines.h" #include "JSCellInlines.h" #include "JSGlobalObject.h" #include "JSSet.h" #include "MapData.h" #include "SetPrototype.h" -#include "StructureInlines.h" namespace JSC { -const ClassInfo SetConstructor::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(SetConstructor) }; +const ClassInfo SetConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(SetConstructor) }; void SetConstructor::finishCreation(VM& vm, SetPrototype* setPrototype) { @@ -47,67 +45,31 @@ void SetConstructor::finishCreation(VM& vm, SetPrototype* setPrototype) putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), ReadOnly | DontEnum | DontDelete); } -static EncodedJSValue JSC_HOST_CALL callSet(ExecState* exec) +static EncodedJSValue JSC_HOST_CALL callSet(CallFrame* callFrame) { - return JSValue::encode(throwTypeError(exec, ASCIILiteral("Set cannot be called as a function"))); + // Until we have iterators we throw if we've been given + // any arguments that could require us to throw. + if (!callFrame->argument(0).isUndefinedOrNull()) + return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Set does not accept arguments when called as a function"))); + if (!callFrame->argument(1).isUndefined()) + return throwVMError(callFrame, createRangeError(callFrame, WTF::ASCIILiteral("Invalid comparator function"))); + + JSGlobalObject* globalObject = asInternalFunction(callFrame->callee())->globalObject(); + Structure* setStructure = globalObject->setStructure(); + return JSValue::encode(JSSet::create(callFrame, setStructure)); } -static EncodedJSValue JSC_HOST_CALL constructSet(ExecState* exec) +static EncodedJSValue JSC_HOST_CALL constructSet(CallFrame* callFrame) { - JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject(); + JSGlobalObject* globalObject = asInternalFunction(callFrame->callee())->globalObject(); Structure* setStructure = globalObject->setStructure(); - JSSet* set = JSSet::create(exec, setStructure); - JSValue iterable = exec->argument(0); - if (iterable.isUndefinedOrNull()) - return JSValue::encode(set); - - JSValue adderFunction = set->get(exec, exec->propertyNames().add); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - CallData adderFunctionCallData; - CallType adderFunctionCallType = getCallData(adderFunction, adderFunctionCallData); - if (adderFunctionCallType == CallTypeNone) - return JSValue::encode(throwTypeError(exec)); - - JSValue iteratorFunction = iterable.get(exec, exec->propertyNames().iteratorSymbol); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - CallData iteratorFunctionCallData; - CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData); - if (iteratorFunctionCallType == CallTypeNone) - return JSValue::encode(throwTypeError(exec)); - - ArgList iteratorFunctionArguments; - JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - if (!iterator.isObject()) - return JSValue::encode(throwTypeError(exec)); - - while (true) { - JSValue next = iteratorStep(exec, iterator); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - if (next.isFalse()) - return JSValue::encode(set); - - JSValue nextValue = iteratorValue(exec, next); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - MarkedArgumentBuffer arguments; - arguments.append(nextValue); - call(exec, adderFunction, adderFunctionCallType, adderFunctionCallData, set, arguments); - if (exec->hadException()) { - iteratorClose(exec, iterator); - return JSValue::encode(jsUndefined()); - } + JSSet* set = JSSet::create(callFrame, setStructure); + MapData* mapData = set->mapData(); + size_t count = callFrame->argumentCount(); + for (size_t i = 0; i < count; i++) { + JSValue item = callFrame->uncheckedArgument(i); + mapData->set(callFrame, item, item); } - RELEASE_ASSERT_NOT_REACHED(); return JSValue::encode(set); } diff --git a/Source/JavaScriptCore/runtime/SetIteratorConstructor.cpp b/Source/JavaScriptCore/runtime/SetIteratorConstructor.cpp new file mode 100644 index 000000000..c16ff9bed --- /dev/null +++ b/Source/JavaScriptCore/runtime/SetIteratorConstructor.cpp @@ -0,0 +1,45 @@ +/* + * 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 "SetIteratorConstructor.h" + +#include "JSCJSValueInlines.h" +#include "JSCellInlines.h" +#include "JSGlobalObject.h" +#include "JSSetIterator.h" +#include "SetIteratorPrototype.h" + +namespace JSC { + +const ClassInfo SetIteratorConstructor::s_info = { "Set Iterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(SetIteratorConstructor) }; + +void SetIteratorConstructor::finishCreation(VM& vm, SetIteratorPrototype* prototype) +{ + Base::finishCreation(vm); + putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, DontEnum | DontDelete | ReadOnly); +} + +} diff --git a/Source/JavaScriptCore/runtime/ConsolePrototype.h b/Source/JavaScriptCore/runtime/SetIteratorConstructor.h index a27ad24ad..cfd954ee7 100644 --- a/Source/JavaScriptCore/runtime/ConsolePrototype.h +++ b/Source/JavaScriptCore/runtime/SetIteratorConstructor.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Apple Inc. All rights reserved. + * 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 @@ -20,42 +20,44 @@ * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ConsolePrototype_h -#define ConsolePrototype_h +#ifndef SetIteratorConstructor_h +#define SetIteratorConstructor_h #include "JSObject.h" namespace JSC { -class ConsolePrototype : public JSNonFinalObject { +class SetIteratorPrototype; + +class SetIteratorConstructor : public JSNonFinalObject { public: typedef JSNonFinalObject Base; - DECLARE_INFO; - - static ConsolePrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) + static SetIteratorConstructor* create(VM& vm, Structure* structure, SetIteratorPrototype* prototype) { - ConsolePrototype* prototype = new (NotNull, allocateCell<ConsolePrototype>(vm.heap)) ConsolePrototype(vm, structure); - prototype->finishCreation(vm, globalObject); - return prototype; + SetIteratorConstructor* constructor = new (NotNull, allocateCell<SetIteratorConstructor>(vm.heap)) SetIteratorConstructor(vm, structure); + constructor->finishCreation(vm, prototype); + return constructor; } + DECLARE_INFO; + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } private: - ConsolePrototype(VM& vm, Structure* structure) + SetIteratorConstructor(VM& vm, Structure* structure) : Base(vm, structure) { } - void finishCreation(VM&, JSGlobalObject*); + void finishCreation(VM&, SetIteratorPrototype*); }; } -#endif // !defined(ConsolePrototype_h) +#endif // !defined(SetConstructor_h) diff --git a/Source/JavaScriptCore/runtime/SetIteratorPrototype.cpp b/Source/JavaScriptCore/runtime/SetIteratorPrototype.cpp index ab8df4447..442d555ef 100644 --- a/Source/JavaScriptCore/runtime/SetIteratorPrototype.cpp +++ b/Source/JavaScriptCore/runtime/SetIteratorPrototype.cpp @@ -26,25 +26,31 @@ #include "config.h" #include "SetIteratorPrototype.h" -#include "IteratorOperations.h" #include "JSCJSValueInlines.h" #include "JSCellInlines.h" #include "JSSetIterator.h" -#include "StructureInlines.h" namespace JSC { -const ClassInfo SetIteratorPrototype::s_info = { "Set Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(SetIteratorPrototype) }; +const ClassInfo SetIteratorPrototype::s_info = { "Set Iterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(SetIteratorPrototype) }; +static EncodedJSValue JSC_HOST_CALL SetIteratorPrototypeFuncIterator(ExecState*); static EncodedJSValue JSC_HOST_CALL SetIteratorPrototypeFuncNext(ExecState*); + void SetIteratorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) { Base::finishCreation(vm); ASSERT(inherits(info())); vm.prototypeMap.addPrototype(this); - JSC_NATIVE_FUNCTION(vm.propertyNames->next, SetIteratorPrototypeFuncNext, DontEnum, 0); + JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorPrivateName, SetIteratorPrototypeFuncIterator, DontEnum, 0); + JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorNextPrivateName, SetIteratorPrototypeFuncNext, DontEnum, 0); +} + +EncodedJSValue JSC_HOST_CALL SetIteratorPrototypeFuncIterator(CallFrame* callFrame) +{ + return JSValue::encode(callFrame->thisValue()); } EncodedJSValue JSC_HOST_CALL SetIteratorPrototypeFuncNext(CallFrame* callFrame) @@ -55,9 +61,10 @@ EncodedJSValue JSC_HOST_CALL SetIteratorPrototypeFuncNext(CallFrame* callFrame) return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot call SetIterator.next() on a non-SetIterator object"))); if (iterator->next(callFrame, result)) - return JSValue::encode(createIteratorResultObject(callFrame, result, false)); + return JSValue::encode(result); iterator->finish(); - return JSValue::encode(createIteratorResultObject(callFrame, jsUndefined(), true)); + return JSValue::encode(callFrame->vm().iterationTerminator.get()); } + } diff --git a/Source/JavaScriptCore/runtime/SetPrototype.cpp b/Source/JavaScriptCore/runtime/SetPrototype.cpp index e83e38325..5eac51eee 100644 --- a/Source/JavaScriptCore/runtime/SetPrototype.cpp +++ b/Source/JavaScriptCore/runtime/SetPrototype.cpp @@ -34,18 +34,18 @@ #include "JSFunctionInlines.h" #include "JSSet.h" #include "JSSetIterator.h" -#include "MapDataInlines.h" -#include "StructureInlines.h" +#include "MapData.h" namespace JSC { -const ClassInfo SetPrototype::s_info = { "Set", &Base::s_info, 0, CREATE_METHOD_TABLE(SetPrototype) }; +const ClassInfo SetPrototype::s_info = { "Set", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(SetPrototype) }; static EncodedJSValue JSC_HOST_CALL setProtoFuncAdd(ExecState*); static EncodedJSValue JSC_HOST_CALL setProtoFuncClear(ExecState*); static EncodedJSValue JSC_HOST_CALL setProtoFuncDelete(ExecState*); static EncodedJSValue JSC_HOST_CALL setProtoFuncForEach(ExecState*); static EncodedJSValue JSC_HOST_CALL setProtoFuncHas(ExecState*); +static EncodedJSValue JSC_HOST_CALL setProtoFuncKeys(ExecState*); static EncodedJSValue JSC_HOST_CALL setProtoFuncValues(ExecState*); static EncodedJSValue JSC_HOST_CALL setProtoFuncEntries(ExecState*); @@ -63,64 +63,61 @@ void SetPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) JSC_NATIVE_FUNCTION(vm.propertyNames->deleteKeyword, setProtoFuncDelete, DontEnum, 1); JSC_NATIVE_FUNCTION(vm.propertyNames->forEach, setProtoFuncForEach, DontEnum, 1); JSC_NATIVE_FUNCTION(vm.propertyNames->has, setProtoFuncHas, DontEnum, 1); + JSC_NATIVE_FUNCTION(vm.propertyNames->keys, setProtoFuncKeys, DontEnum, 0); + JSC_NATIVE_FUNCTION(vm.propertyNames->values, setProtoFuncValues, DontEnum, 0); JSC_NATIVE_FUNCTION(vm.propertyNames->entries, setProtoFuncEntries, DontEnum, 0); + JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorPrivateName, setProtoFuncKeys, DontEnum, 0); - JSFunction* values = JSFunction::create(vm, globalObject, 0, vm.propertyNames->values.string(), setProtoFuncValues); - putDirectWithoutTransition(vm, vm.propertyNames->values, values, DontEnum); - putDirectWithoutTransition(vm, vm.propertyNames->keys, values, DontEnum); - putDirectWithoutTransition(vm, vm.propertyNames->iteratorSymbol, values, DontEnum); - - GetterSetter* accessor = GetterSetter::create(vm, globalObject); + GetterSetter* accessor = GetterSetter::create(vm); JSFunction* function = JSFunction::create(vm, globalObject, 0, vm.propertyNames->size.string(), setProtoFuncSize); - accessor->setGetter(vm, globalObject, function); + accessor->setGetter(vm, function); putDirectNonIndexAccessor(vm, vm.propertyNames->size, accessor, DontEnum | Accessor); } -ALWAYS_INLINE static JSSet* getSet(CallFrame* callFrame, JSValue thisValue) +ALWAYS_INLINE static MapData* getMapData(CallFrame* callFrame, JSValue thisValue) { if (!thisValue.isObject()) { throwVMError(callFrame, createNotAnObjectError(callFrame, thisValue)); - return nullptr; + return 0; } JSSet* set = jsDynamicCast<JSSet*>(thisValue); if (!set) { throwTypeError(callFrame, ASCIILiteral("Set operation called on non-Set object")); - return nullptr; + return 0; } - return set; + return set->mapData(); } EncodedJSValue JSC_HOST_CALL setProtoFuncAdd(CallFrame* callFrame) { - JSValue thisValue = callFrame->thisValue(); - JSSet* set = getSet(callFrame, thisValue); - if (!set) + MapData* data = getMapData(callFrame, callFrame->thisValue()); + if (!data) return JSValue::encode(jsUndefined()); - set->add(callFrame, callFrame->argument(0)); - return JSValue::encode(thisValue); + data->set(callFrame, callFrame->argument(0), callFrame->argument(0)); + return JSValue::encode(callFrame->thisValue()); } EncodedJSValue JSC_HOST_CALL setProtoFuncClear(CallFrame* callFrame) { - JSSet* set = getSet(callFrame, callFrame->thisValue()); - if (!set) + MapData* data = getMapData(callFrame, callFrame->thisValue()); + if (!data) return JSValue::encode(jsUndefined()); - set->clear(callFrame); + data->clear(); return JSValue::encode(jsUndefined()); } EncodedJSValue JSC_HOST_CALL setProtoFuncDelete(CallFrame* callFrame) { - JSSet* set = getSet(callFrame, callFrame->thisValue()); - if (!set) + MapData* data = getMapData(callFrame, callFrame->thisValue()); + if (!data) return JSValue::encode(jsUndefined()); - return JSValue::encode(jsBoolean(set->remove(callFrame, callFrame->argument(0)))); + return JSValue::encode(jsBoolean(data->remove(callFrame, callFrame->argument(0)))); } EncodedJSValue JSC_HOST_CALL setProtoFuncForEach(CallFrame* callFrame) { - JSSet* set = getSet(callFrame, callFrame->thisValue()); - if (!set) + MapData* data = getMapData(callFrame, callFrame->thisValue()); + if (!data) return JSValue::encode(jsUndefined()); JSValue callBack = callFrame->argument(0); CallData callData; @@ -129,53 +126,45 @@ EncodedJSValue JSC_HOST_CALL setProtoFuncForEach(CallFrame* callFrame) return JSValue::encode(throwTypeError(callFrame, WTF::ASCIILiteral("Set.prototype.forEach called without callback"))); JSValue thisValue = callFrame->argument(1); VM* vm = &callFrame->vm(); - JSSetIterator* iterator = JSSetIterator::create(*vm, callFrame->callee()->globalObject()->setIteratorStructure(), set, SetIterateKey); - JSValue key; if (callType == CallTypeJS) { JSFunction* function = jsCast<JSFunction*>(callBack); - CachedCall cachedCall(callFrame, function, 3); - while (iterator->next(callFrame, key) && !vm->exception()) { + CachedCall cachedCall(callFrame, function, 1); + for (auto ptr = data->begin(), end = data->end(); ptr != end && !vm->exception(); ++ptr) { cachedCall.setThis(thisValue); - cachedCall.setArgument(0, key); - cachedCall.setArgument(1, key); - cachedCall.setArgument(2, set); + cachedCall.setArgument(0, ptr.key()); cachedCall.call(); } - iterator->finish(); } else { - while (iterator->next(callFrame, key) && !vm->exception()) { + for (auto ptr = data->begin(), end = data->end(); ptr != end && !vm->exception(); ++ptr) { MarkedArgumentBuffer args; - args.append(key); - args.append(key); - args.append(set); + args.append(ptr.key()); JSC::call(callFrame, callBack, callType, callData, thisValue, args); } - iterator->finish(); } return JSValue::encode(jsUndefined()); } EncodedJSValue JSC_HOST_CALL setProtoFuncHas(CallFrame* callFrame) { - JSSet* set = getSet(callFrame, callFrame->thisValue()); - if (!set) + MapData* data = getMapData(callFrame, callFrame->thisValue()); + if (!data) return JSValue::encode(jsUndefined()); - return JSValue::encode(jsBoolean(set->has(callFrame, callFrame->argument(0)))); + return JSValue::encode(jsBoolean(data->contains(callFrame, callFrame->argument(0)))); } EncodedJSValue JSC_HOST_CALL setProtoFuncSize(CallFrame* callFrame) { - JSSet* set = getSet(callFrame, callFrame->thisValue()); - if (!set) + MapData* data = getMapData(callFrame, callFrame->thisValue()); + if (!data) return JSValue::encode(jsUndefined()); - return JSValue::encode(jsNumber(set->size(callFrame))); + return JSValue::encode(jsNumber(data->size(callFrame))); } EncodedJSValue JSC_HOST_CALL setProtoFuncValues(CallFrame* callFrame) { JSSet* thisObj = jsDynamicCast<JSSet*>(callFrame->thisValue()); if (!thisObj) - return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot create a Set value iterator for a non-Set object."))); + return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot create a Map value iterator for a non-Map object."))); return JSValue::encode(JSSetIterator::create(callFrame->vm(), callFrame->callee()->globalObject()->setIteratorStructure(), thisObj, SetIterateValue)); } @@ -183,8 +172,16 @@ EncodedJSValue JSC_HOST_CALL setProtoFuncEntries(CallFrame* callFrame) { JSSet* thisObj = jsDynamicCast<JSSet*>(callFrame->thisValue()); if (!thisObj) - return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot create a Set entry iterator for a non-Set object."))); + return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot create a Map key iterator for a non-Map object."))); return JSValue::encode(JSSetIterator::create(callFrame->vm(), callFrame->callee()->globalObject()->setIteratorStructure(), thisObj, SetIterateKeyValue)); } +EncodedJSValue JSC_HOST_CALL setProtoFuncKeys(CallFrame* callFrame) +{ + JSSet* thisObj = jsDynamicCast<JSSet*>(callFrame->thisValue()); + if (!thisObj) + return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot create a Map entry iterator for a non-Map object."))); + return JSValue::encode(JSSetIterator::create(callFrame->vm(), callFrame->callee()->globalObject()->setIteratorStructure(), thisObj, SetIterateKey)); +} + } diff --git a/Source/JavaScriptCore/runtime/SimpleTypedArrayController.cpp b/Source/JavaScriptCore/runtime/SimpleTypedArrayController.cpp index 9245c2c5d..dd68aac2a 100644 --- a/Source/JavaScriptCore/runtime/SimpleTypedArrayController.cpp +++ b/Source/JavaScriptCore/runtime/SimpleTypedArrayController.cpp @@ -28,7 +28,7 @@ #include "ArrayBuffer.h" #include "JSArrayBuffer.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { diff --git a/Source/JavaScriptCore/runtime/SmallStrings.cpp b/Source/JavaScriptCore/runtime/SmallStrings.cpp index 9c6a43ae2..ff304039c 100644 --- a/Source/JavaScriptCore/runtime/SmallStrings.cpp +++ b/Source/JavaScriptCore/runtime/SmallStrings.cpp @@ -29,8 +29,9 @@ #include "HeapRootVisitor.h" #include "JSGlobalObject.h" #include "JSString.h" -#include "JSCInlines.h" +#include "Operations.h" #include <wtf/Noncopyable.h> +#include <wtf/PassOwnPtr.h> #include <wtf/text/StringImpl.h> namespace JSC { @@ -57,7 +58,7 @@ SmallStringsStorage::SmallStringsStorage() RefPtr<StringImpl> baseString = StringImpl::createUninitialized(singleCharacterStringCount, characterBuffer); for (unsigned i = 0; i < singleCharacterStringCount; ++i) { characterBuffer[i] = i; - m_reps[i] = AtomicStringImpl::add(PassRefPtr<StringImpl>(StringImpl::createSubstringSharingImpl(baseString, i, 1)).get()); + m_reps[i] = StringImpl::create(baseString, i, 1); } } @@ -66,9 +67,6 @@ SmallStrings::SmallStrings() #define JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE(name) , m_##name(0) JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE) #undef JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE - , m_nullObjectString(nullptr) - , m_undefinedObjectString(nullptr) - , m_needsToBeVisited(true) { COMPILE_ASSERT(singleCharacterStringCount == sizeof(m_singleCharacterStrings) / sizeof(m_singleCharacterStrings[0]), IsNumCharactersConstInSyncWithClassUsage); @@ -84,21 +82,16 @@ void SmallStrings::initializeCommonStrings(VM& 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 - initialize(&vm, m_nullObjectString, "[object Null]"); - initialize(&vm, m_undefinedObjectString, "[object Undefined]"); } void SmallStrings::visitStrongReferences(SlotVisitor& visitor) { - m_needsToBeVisited = false; visitor.appendUnbarrieredPointer(&m_emptyString); for (unsigned i = 0; i <= maxSingleCharacterString; ++i) visitor.appendUnbarrieredPointer(m_singleCharacterStrings + i); #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 - visitor.appendUnbarrieredPointer(&m_nullObjectString); - visitor.appendUnbarrieredPointer(&m_undefinedObjectString); } SmallStrings::~SmallStrings() @@ -109,29 +102,26 @@ void SmallStrings::createEmptyString(VM* vm) { ASSERT(!m_emptyString); m_emptyString = JSString::createHasOtherOwner(*vm, StringImpl::empty()); - m_needsToBeVisited = true; } void SmallStrings::createSingleCharacterString(VM* vm, unsigned char character) { if (!m_storage) - m_storage = std::make_unique<SmallStringsStorage>(); + m_storage = adoptPtr(new SmallStringsStorage); ASSERT(!m_singleCharacterStrings[character]); m_singleCharacterStrings[character] = JSString::createHasOtherOwner(*vm, PassRefPtr<StringImpl>(m_storage->rep(character))); - m_needsToBeVisited = true; } StringImpl* SmallStrings::singleCharacterStringRep(unsigned char character) { if (!m_storage) - m_storage = std::make_unique<SmallStringsStorage>(); + m_storage = adoptPtr(new SmallStringsStorage); return m_storage->rep(character); } -void SmallStrings::initialize(VM* vm, JSString*& string, const char* value) +void SmallStrings::initialize(VM* vm, JSString*& string, const char* value) const { - string = JSString::create(*vm, Identifier::fromString(vm, value).impl()); - m_needsToBeVisited = true; + string = JSString::create(*vm, StringImpl::create(value)); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/SmallStrings.h b/Source/JavaScriptCore/runtime/SmallStrings.h index 909bae1de..0e8646a71 100644 --- a/Source/JavaScriptCore/runtime/SmallStrings.h +++ b/Source/JavaScriptCore/runtime/SmallStrings.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2015 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,9 +26,9 @@ #ifndef SmallStrings_h #define SmallStrings_h -#include "TypeofType.h" #include "WriteBarrier.h" #include <wtf/Noncopyable.h> +#include <wtf/OwnPtr.h> #define JSC_COMMON_STRINGS_EACH_NAME(macro) \ macro(boolean) \ @@ -39,7 +39,6 @@ macro(object) \ macro(undefined) \ macro(string) \ - macro(symbol) \ macro(true) namespace WTF { @@ -48,96 +47,60 @@ class StringImpl; namespace JSC { -class HeapRootVisitor; -class VM; -class JSString; -class SmallStringsStorage; -class SlotVisitor; + class HeapRootVisitor; + class VM; + class JSString; + class SmallStringsStorage; + class SlotVisitor; -static const unsigned maxSingleCharacterString = 0xFF; + static const unsigned maxSingleCharacterString = 0xFF; -class SmallStrings { - WTF_MAKE_NONCOPYABLE(SmallStrings); -public: - SmallStrings(); - ~SmallStrings(); + class SmallStrings { + WTF_MAKE_NONCOPYABLE(SmallStrings); + public: + SmallStrings(); + ~SmallStrings(); - JSString* emptyString() - { - return m_emptyString; - } + JSString* emptyString() + { + return m_emptyString; + } - JSString* singleCharacterString(unsigned char character) - { - return m_singleCharacterStrings[character]; - } + JSString* singleCharacterString(unsigned char character) + { + return m_singleCharacterStrings[character]; + } - JS_EXPORT_PRIVATE WTF::StringImpl* singleCharacterStringRep(unsigned char character); + JS_EXPORT_PRIVATE WTF::StringImpl* singleCharacterStringRep(unsigned char character); - JSString** singleCharacterStrings() { return &m_singleCharacterStrings[0]; } + JSString** singleCharacterStrings() { return &m_singleCharacterStrings[0]; } - void initializeCommonStrings(VM&); - void visitStrongReferences(SlotVisitor&); + void initializeCommonStrings(VM&); + void visitStrongReferences(SlotVisitor&); #define JSC_COMMON_STRINGS_ACCESSOR_DEFINITION(name) \ - JSString* name##String() const \ - { \ - return m_##name; \ - } - JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ACCESSOR_DEFINITION) -#undef JSC_COMMON_STRINGS_ACCESSOR_DEFINITION - - JSString* typeString(TypeofType type) const - { - switch (type) { - case TypeofType::Undefined: - return undefinedString(); - case TypeofType::Boolean: - return booleanString(); - case TypeofType::Number: - return numberString(); - case TypeofType::String: - return stringString(); - case TypeofType::Symbol: - return symbolString(); - case TypeofType::Object: - return objectString(); - case TypeofType::Function: - return functionString(); + JSString* name##String() const \ + { \ + return m_##name; \ } - - RELEASE_ASSERT_NOT_REACHED(); - return nullptr; - } - - JSString* nullObjectString() const { return m_nullObjectString; } - JSString* undefinedObjectString() const { return m_undefinedObjectString; } - - bool needsToBeVisited(HeapOperation collectionType) const - { - if (collectionType == FullCollection) - return true; - return m_needsToBeVisited; - } + JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ACCESSOR_DEFINITION) +#undef JSC_COMMON_STRINGS_ACCESSOR_DEFINITION -private: - static const unsigned singleCharacterStringCount = maxSingleCharacterString + 1; + private: + static const unsigned singleCharacterStringCount = maxSingleCharacterString + 1; - JS_EXPORT_PRIVATE void createEmptyString(VM*); - JS_EXPORT_PRIVATE void createSingleCharacterString(VM*, unsigned char); + JS_EXPORT_PRIVATE void createEmptyString(VM*); + JS_EXPORT_PRIVATE void createSingleCharacterString(VM*, unsigned char); - void initialize(VM*, JSString*&, const char* value); + void initialize(VM* vm, JSString*& string, const char* value) const; - JSString* m_emptyString; + JSString* m_emptyString; #define JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION(name) JSString* m_##name; - JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION) + JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION) #undef JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION - JSString* m_nullObjectString; - JSString* m_undefinedObjectString; - JSString* m_singleCharacterStrings[singleCharacterStringCount]; - std::unique_ptr<SmallStringsStorage> m_storage; - bool m_needsToBeVisited; -}; + JSString* m_singleCharacterStrings[singleCharacterStringCount]; + OwnPtr<SmallStringsStorage> m_storage; + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp b/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp index 62d34baaf..0db43b7b6 100644 --- a/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp +++ b/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp @@ -29,7 +29,7 @@ #include "ClassInfo.h" #include "GetterSetter.h" #include "JSObject.h" -#include "JSCInlines.h" +#include "Operations.h" #include "PropertySlot.h" #include "Reject.h" #include "SlotVisitor.h" @@ -37,7 +37,7 @@ namespace JSC { -const ClassInfo SparseArrayValueMap::s_info = { "SparseArrayValueMap", 0, 0, CREATE_METHOD_TABLE(SparseArrayValueMap) }; +const ClassInfo SparseArrayValueMap::s_info = { "SparseArrayValueMap", 0, 0, 0, CREATE_METHOD_TABLE(SparseArrayValueMap) }; SparseArrayValueMap::SparseArrayValueMap(VM& vm) : Base(vm, vm.sparseArrayValueMapStructure.get()) @@ -69,7 +69,7 @@ void SparseArrayValueMap::destroy(JSCell* cell) Structure* SparseArrayValueMap::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); + return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, StructureFlags), info()); } SparseArrayValueMap::AddResult SparseArrayValueMap::add(JSObject* array, unsigned i) @@ -80,9 +80,7 @@ SparseArrayValueMap::AddResult SparseArrayValueMap::add(JSObject* array, unsigne AddResult result = m_map.add(i, entry); size_t capacity = m_map.capacity(); if (capacity != m_reportedCapacity) { - // FIXME: Adopt reportExtraMemoryVisited, and switch to reportExtraMemoryAllocated. - // https://bugs.webkit.org/show_bug.cgi?id=142595 - Heap::heap(array)->deprecatedReportExtraMemory((capacity - m_reportedCapacity) * (sizeof(unsigned) + sizeof(WriteBarrier<Unknown>))); + Heap::heap(array)->reportExtraMemoryCost((capacity - m_reportedCapacity) * (sizeof(unsigned) + sizeof(WriteBarrier<Unknown>))); m_reportedCapacity = capacity; } return result; diff --git a/Source/JavaScriptCore/runtime/SparseArrayValueMap.h b/Source/JavaScriptCore/runtime/SparseArrayValueMap.h index ff36caa71..113beb350 100644 --- a/Source/JavaScriptCore/runtime/SparseArrayValueMap.h +++ b/Source/JavaScriptCore/runtime/SparseArrayValueMap.h @@ -32,6 +32,7 @@ #include "PutDirectIndexMode.h" #include "WriteBarrier.h" #include <wtf/HashMap.h> +#include <wtf/Platform.h> namespace JSC { @@ -51,10 +52,9 @@ struct SparseArrayEntry : public WriteBarrier<Unknown> { unsigned attributes; }; -class SparseArrayValueMap final : public JSCell { +class SparseArrayValueMap : public JSCell { public: typedef JSCell Base; - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; private: typedef HashMap<uint64_t, SparseArrayEntry, WTF::IntHash<uint64_t>, WTF::UnsignedWithZeroKeyHashTraits<uint64_t>> Map; @@ -70,6 +70,8 @@ private: void finishCreation(VM&); + static const unsigned StructureFlags = OverridesVisitChildren | JSCell::StructureFlags; + public: DECLARE_EXPORT_INFO; @@ -80,6 +82,7 @@ public: static SparseArrayValueMap* create(VM&); static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; static void destroy(JSCell*); static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype); diff --git a/Source/JavaScriptCore/runtime/StackAlignment.h b/Source/JavaScriptCore/runtime/StackAlignment.h index d29802b3f..b803e4ded 100644 --- a/Source/JavaScriptCore/runtime/StackAlignment.h +++ b/Source/JavaScriptCore/runtime/StackAlignment.h @@ -27,8 +27,6 @@ #define StackAlignment_h #include "JSCJSValue.h" -#include "JSStack.h" -#include <wtf/MathExtras.h> namespace JSC { @@ -40,25 +38,6 @@ inline unsigned stackAlignmentRegisters() return stackAlignmentBytes() / sizeof(EncodedJSValue); } -// Align argument count taking into account the CallFrameHeaderSize may be -// an "unaligned" count of registers. -inline unsigned roundArgumentCountToAlignFrame(unsigned argumentCount) -{ - return WTF::roundUpToMultipleOf(stackAlignmentRegisters(), argumentCount + JSStack::CallFrameHeaderSize) - JSStack::CallFrameHeaderSize; -} - -// Align local register count to make the last local end on a stack aligned address given the -// CallFrame is at an address that is stack aligned minus JSStack::CallerFrameAndPCSize -inline unsigned roundLocalRegisterCountForFramePointerOffset(unsigned localRegisterCount) -{ - return WTF::roundUpToMultipleOf(stackAlignmentRegisters(), localRegisterCount + JSStack::CallerFrameAndPCSize) - JSStack::CallerFrameAndPCSize; -} - -inline unsigned logStackAlignmentRegisters() -{ - return WTF::fastLog2(stackAlignmentRegisters()); -} - } // namespace JSC #endif // StackAlignment_h diff --git a/Source/JavaScriptCore/runtime/StrictEvalActivation.cpp b/Source/JavaScriptCore/runtime/StrictEvalActivation.cpp index 4260e10b9..e2ff9acd7 100644 --- a/Source/JavaScriptCore/runtime/StrictEvalActivation.cpp +++ b/Source/JavaScriptCore/runtime/StrictEvalActivation.cpp @@ -27,19 +27,19 @@ #include "StrictEvalActivation.h" #include "JSGlobalObject.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(StrictEvalActivation); -const ClassInfo StrictEvalActivation::s_info = { "Object", &Base::s_info, 0, CREATE_METHOD_TABLE(StrictEvalActivation) }; +const ClassInfo StrictEvalActivation::s_info = { "Object", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(StrictEvalActivation) }; -StrictEvalActivation::StrictEvalActivation(ExecState* exec, JSScope* currentScope) +StrictEvalActivation::StrictEvalActivation(ExecState* exec) : Base( exec->vm(), exec->lexicalGlobalObject()->strictEvalActivationStructure(), - currentScope + exec->scope() ) { } diff --git a/Source/JavaScriptCore/runtime/StrictEvalActivation.h b/Source/JavaScriptCore/runtime/StrictEvalActivation.h index 13157f68a..e02bb615d 100644 --- a/Source/JavaScriptCore/runtime/StrictEvalActivation.h +++ b/Source/JavaScriptCore/runtime/StrictEvalActivation.h @@ -33,13 +33,12 @@ namespace JSC { class StrictEvalActivation : public JSScope { public: typedef JSScope Base; - static const unsigned StructureFlags = Base::StructureFlags | IsEnvironmentRecord; - static StrictEvalActivation* create(ExecState* exec, JSScope* currentScope) + static StrictEvalActivation* create(ExecState* exec) { - StrictEvalActivation* lexicalEnvironment = new (NotNull, allocateCell<StrictEvalActivation>(*exec->heap())) StrictEvalActivation(exec, currentScope); - lexicalEnvironment->finishCreation(exec->vm()); - return lexicalEnvironment; + StrictEvalActivation* activation = new (NotNull, allocateCell<StrictEvalActivation>(*exec->heap())) StrictEvalActivation(exec); + activation->finishCreation(exec->vm()); + return activation; } static bool deleteProperty(JSCell*, ExecState*, PropertyName); @@ -52,8 +51,11 @@ public: DECLARE_INFO; +protected: + static const unsigned StructureFlags = IsEnvironmentRecord | Base::StructureFlags; + private: - StrictEvalActivation(ExecState*, JSScope*); + StrictEvalActivation(ExecState*); }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/StringConstructor.cpp b/Source/JavaScriptCore/runtime/StringConstructor.cpp index e8d396970..207d8585a 100644 --- a/Source/JavaScriptCore/runtime/StringConstructor.cpp +++ b/Source/JavaScriptCore/runtime/StringConstructor.cpp @@ -21,18 +21,16 @@ #include "config.h" #include "StringConstructor.h" -#include "Error.h" #include "Executable.h" #include "JITCode.h" #include "JSFunction.h" #include "JSGlobalObject.h" -#include "JSCInlines.h" +#include "Operations.h" #include "StringPrototype.h" namespace JSC { static EncodedJSValue JSC_HOST_CALL stringFromCharCode(ExecState*); -static EncodedJSValue JSC_HOST_CALL stringFromCodePoint(ExecState*); } @@ -40,13 +38,11 @@ static EncodedJSValue JSC_HOST_CALL stringFromCodePoint(ExecState*); namespace JSC { -const ClassInfo StringConstructor::s_info = { "Function", &InternalFunction::s_info, &stringConstructorTable, CREATE_METHOD_TABLE(StringConstructor) }; +const ClassInfo StringConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::stringConstructorTable, CREATE_METHOD_TABLE(StringConstructor) }; /* Source for StringConstructor.lut.h @begin stringConstructorTable fromCharCode stringFromCharCode DontEnum|Function 1 - fromCodePoint stringFromCodePoint DontEnum|Function 1 - raw stringRaw DontEnum|Function 1 @end */ @@ -66,7 +62,7 @@ void StringConstructor::finishCreation(VM& vm, StringPrototype* stringPrototype) bool StringConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot) { - return getStaticFunctionSlot<InternalFunction>(exec, stringConstructorTable, jsCast<StringConstructor*>(object), propertyName, slot); + return getStaticFunctionSlot<InternalFunction>(exec, ExecState::stringConstructorTable(exec->vm()), jsCast<StringConstructor*>(object), propertyName, slot); } // ------------------------------ Functions -------------------------------- @@ -93,33 +89,6 @@ JSCell* JSC_HOST_CALL stringFromCharCode(ExecState* exec, int32_t arg) return jsSingleCharacterString(exec, arg); } -static EncodedJSValue JSC_HOST_CALL stringFromCodePoint(ExecState* exec) -{ - unsigned length = exec->argumentCount(); - StringBuilder builder; - builder.reserveCapacity(length); - - for (unsigned i = 0; i < length; ++i) { - double codePointAsDouble = exec->uncheckedArgument(i).toNumber(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - uint32_t codePoint = static_cast<uint32_t>(codePointAsDouble); - - if (codePoint != codePointAsDouble || codePoint > UCHAR_MAX_VALUE) - return throwVMError(exec, createRangeError(exec, ASCIILiteral("Arguments contain a value that is out of range of code points"))); - - if (U_IS_BMP(codePoint)) - builder.append(static_cast<UChar>(codePoint)); - else { - builder.append(U16_LEAD(codePoint)); - builder.append(U16_TRAIL(codePoint)); - } - } - - return JSValue::encode(jsString(exec, builder.toString())); -} - static EncodedJSValue JSC_HOST_CALL constructWithStringConstructor(ExecState* exec) { JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject(); @@ -127,7 +96,7 @@ static EncodedJSValue JSC_HOST_CALL constructWithStringConstructor(ExecState* ex if (!exec->argumentCount()) return JSValue::encode(StringObject::create(vm, globalObject->stringObjectStructure())); - + return JSValue::encode(StringObject::create(vm, globalObject->stringObjectStructure(), exec->uncheckedArgument(0).toString(exec))); } @@ -137,18 +106,11 @@ ConstructType StringConstructor::getConstructData(JSCell*, ConstructData& constr return ConstructTypeHost; } -JSCell* stringConstructor(ExecState* exec, JSValue argument) -{ - if (argument.isSymbol()) - return jsNontrivialString(exec, asSymbol(argument)->descriptiveString()); - return argument.toString(exec); -} - static EncodedJSValue JSC_HOST_CALL callStringConstructor(ExecState* exec) { if (!exec->argumentCount()) return JSValue::encode(jsEmptyString(exec)); - return JSValue::encode(stringConstructor(exec, exec->uncheckedArgument(0))); + return JSValue::encode(exec->uncheckedArgument(0).toString(exec)); } CallType StringConstructor::getCallData(JSCell*, CallData& callData) diff --git a/Source/JavaScriptCore/runtime/StringConstructor.h b/Source/JavaScriptCore/runtime/StringConstructor.h index 357511a57..a2c08231e 100644 --- a/Source/JavaScriptCore/runtime/StringConstructor.h +++ b/Source/JavaScriptCore/runtime/StringConstructor.h @@ -25,38 +25,39 @@ namespace JSC { -class StringPrototype; - -class StringConstructor : public InternalFunction { -public: - typedef InternalFunction Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; - - static StringConstructor* create(VM& vm, Structure* structure, StringPrototype* stringPrototype) - { - StringConstructor* constructor = new (NotNull, allocateCell<StringConstructor>(vm.heap)) StringConstructor(vm, structure); - constructor->finishCreation(vm, stringPrototype); - return constructor; - } - - DECLARE_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } - -private: - StringConstructor(VM&, Structure*); - void finishCreation(VM&, StringPrototype*); - static ConstructType getConstructData(JSCell*, ConstructData&); - static CallType getCallData(JSCell*, CallData&); - - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); -}; - -JSCell* JSC_HOST_CALL stringFromCharCode(ExecState*, int32_t); -JSCell* stringConstructor(ExecState*, JSValue); + class StringPrototype; + + class StringConstructor : public InternalFunction { + public: + typedef InternalFunction Base; + + static StringConstructor* create(VM& vm, Structure* structure, StringPrototype* stringPrototype) + { + StringConstructor* constructor = new (NotNull, allocateCell<StringConstructor>(vm.heap)) StringConstructor(vm, structure); + constructor->finishCreation(vm, stringPrototype); + return constructor; + } + + DECLARE_INFO; + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } + + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags; + + private: + StringConstructor(VM&, Structure*); + void finishCreation(VM&, StringPrototype*); + static ConstructType getConstructData(JSCell*, ConstructData&); + static CallType getCallData(JSCell*, CallData&); + + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + }; + + JSCell* JSC_HOST_CALL stringFromCharCode(ExecState*, int32_t); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/StringIteratorPrototype.h b/Source/JavaScriptCore/runtime/StringIteratorPrototype.h deleted file mode 100644 index 393af560f..000000000 --- a/Source/JavaScriptCore/runtime/StringIteratorPrototype.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2013 Apple, Inc. All rights reserved. - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. - * - * 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 StringIteratorPrototype_h -#define StringIteratorPrototype_h - -#include "JSObject.h" - -namespace JSC { - -class StringIteratorPrototype : public JSNonFinalObject { -public: - typedef JSNonFinalObject Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot; - - static StringIteratorPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) - { - StringIteratorPrototype* prototype = new (NotNull, allocateCell<StringIteratorPrototype>(vm.heap)) StringIteratorPrototype(vm, structure); - prototype->finishCreation(vm, globalObject); - return prototype; - } - - DECLARE_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } - -private: - StringIteratorPrototype(VM& vm, Structure* structure) - : Base(vm, structure) - { - } - void finishCreation(VM&, JSGlobalObject*); - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); -}; - -} - -#endif // !defined(StringIteratorPrototype_h) diff --git a/Source/JavaScriptCore/runtime/StringObject.cpp b/Source/JavaScriptCore/runtime/StringObject.cpp index b5aa3f72d..440a60942 100644 --- a/Source/JavaScriptCore/runtime/StringObject.cpp +++ b/Source/JavaScriptCore/runtime/StringObject.cpp @@ -23,14 +23,14 @@ #include "Error.h" #include "JSGlobalObject.h" -#include "JSCInlines.h" +#include "Operations.h" #include "PropertyNameArray.h" namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(StringObject); -const ClassInfo StringObject::s_info = { "String", &JSWrapperObject::s_info, 0, CREATE_METHOD_TABLE(StringObject) }; +const ClassInfo StringObject::s_info = { "String", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(StringObject) }; StringObject::StringObject(VM& vm, Structure* structure) : JSWrapperObject(vm, structure) @@ -93,7 +93,7 @@ bool StringObject::defineOwnProperty(JSObject* object, ExecState* exec, Property } if (descriptor.configurablePresent() && descriptor.configurable()) { if (throwException) - exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change configurable attribute of unconfigurable property."))); + exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to configurable attribute of unconfigurable property."))); return false; } if (descriptor.enumerablePresent() && descriptor.enumerable()) { @@ -128,8 +128,9 @@ bool StringObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName pr StringObject* thisObject = jsCast<StringObject*>(cell); if (propertyName == exec->propertyNames().length) return false; - Optional<uint32_t> index = parseIndex(propertyName); - if (index && thisObject->internalValue()->canGetIndex(index.value())) { + unsigned i = propertyName.asIndex(); + if (thisObject->internalValue()->canGetIndex(i)) { + ASSERT(i != PropertyName::NotAnIndex); // No need for an explicit check, the above test would always fail! return false; } return JSObject::deleteProperty(thisObject, exec, propertyName); @@ -146,12 +147,10 @@ bool StringObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned void StringObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { StringObject* thisObject = jsCast<StringObject*>(object); - if (propertyNames.includeStringProperties()) { - int size = thisObject->internalValue()->length(); - for (int i = 0; i < size; ++i) - propertyNames.add(Identifier::from(exec, i)); - } - if (mode.includeDontEnumProperties()) + int size = thisObject->internalValue()->length(); + for (int i = 0; i < size; ++i) + propertyNames.add(Identifier::from(exec, i)); + if (mode == IncludeDontEnumProperties) propertyNames.add(exec->propertyNames().length); return JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode); } diff --git a/Source/JavaScriptCore/runtime/StringObject.h b/Source/JavaScriptCore/runtime/StringObject.h index 90e6e5cca..df6361474 100644 --- a/Source/JavaScriptCore/runtime/StringObject.h +++ b/Source/JavaScriptCore/runtime/StringObject.h @@ -26,60 +26,60 @@ namespace JSC { -class StringObject : public JSWrapperObject { -public: - typedef JSWrapperObject Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames; - - static StringObject* create(VM& vm, Structure* structure) - { - JSString* string = jsEmptyString(&vm); - StringObject* object = new (NotNull, allocateCell<StringObject>(vm.heap)) StringObject(vm, structure); - object->finishCreation(vm, string); - return object; - } - static StringObject* create(VM& vm, Structure* structure, JSString* string) - { - StringObject* object = new (NotNull, allocateCell<StringObject>(vm.heap)) StringObject(vm, structure); - object->finishCreation(vm, string); - return object; - } - static StringObject* create(VM&, JSGlobalObject*, JSString*); - - JS_EXPORT_PRIVATE static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); - JS_EXPORT_PRIVATE static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&); - - JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); - JS_EXPORT_PRIVATE static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); - - JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName); - JS_EXPORT_PRIVATE static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); - JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow); - - DECLARE_EXPORT_INFO; - - JSString* internalValue() const { return asString(JSWrapperObject::internalValue());} - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + class StringObject : public JSWrapperObject { + public: + typedef JSWrapperObject Base; + + static StringObject* create(VM& vm, Structure* structure) + { + JSString* string = jsEmptyString(&vm); + StringObject* object = new (NotNull, allocateCell<StringObject>(vm.heap)) StringObject(vm, structure); + object->finishCreation(vm, string); + return object; + } + static StringObject* create(VM& vm, Structure* structure, JSString* string) + { + StringObject* object = new (NotNull, allocateCell<StringObject>(vm.heap)) StringObject(vm, structure); + object->finishCreation(vm, string); + return object; + } + static StringObject* create(VM&, JSGlobalObject*, JSString*); + + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&); + + static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); + static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); + + static bool deleteProperty(JSCell*, ExecState*, PropertyName); + static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); + static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow); + + DECLARE_EXPORT_INFO; + + JSString* internalValue() const { return asString(JSWrapperObject::internalValue());} + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } + + protected: + JS_EXPORT_PRIVATE void finishCreation(VM&, JSString*); + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames | JSWrapperObject::StructureFlags; + JS_EXPORT_PRIVATE StringObject(VM&, Structure*); + }; + + StringObject* asStringObject(JSValue); + + inline StringObject* asStringObject(JSValue value) { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + ASSERT(asObject(value)->inherits(StringObject::info())); + return static_cast<StringObject*>(asObject(value)); } -protected: - JS_EXPORT_PRIVATE void finishCreation(VM&, JSString*); - JS_EXPORT_PRIVATE StringObject(VM&, Structure*); -}; - -StringObject* asStringObject(JSValue); - -inline StringObject* asStringObject(JSValue value) -{ - ASSERT(asObject(value)->inherits(StringObject::info())); - return static_cast<StringObject*>(asObject(value)); -} - -JS_EXPORT_PRIVATE StringObject* constructString(VM&, JSGlobalObject*, JSValue); + JS_EXPORT_PRIVATE StringObject* constructString(VM&, JSGlobalObject*, JSValue); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/StringPrototype.cpp b/Source/JavaScriptCore/runtime/StringPrototype.cpp index 2edbf42c7..83306a0eb 100644 --- a/Source/JavaScriptCore/runtime/StringPrototype.cpp +++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp @@ -2,7 +2,6 @@ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013 Apple Inc. All rights reserved. * Copyright (C) 2009 Torch Mobile, Inc. - * Copyright (C) 2015 Jordan Harband (ljharb@gmail.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -34,17 +33,14 @@ #include "JSStringBuilder.h" #include "Lookup.h" #include "ObjectPrototype.h" -#include "JSCInlines.h" -#include "JSStringIterator.h" +#include "Operations.h" #include "PropertyNameArray.h" #include "RegExpCache.h" #include "RegExpConstructor.h" #include "RegExpMatchesArray.h" #include "RegExpObject.h" -#include <algorithm> #include <wtf/ASCIICType.h> #include <wtf/MathExtras.h> -#include <wtf/text/StringView.h> #include <wtf/unicode/Collator.h> using namespace WTF; @@ -53,46 +49,40 @@ namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(StringPrototype); -EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncCodePointAt(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncRepeat(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncBig(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncBold(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncSub(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncSup(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncStartsWith(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncEndsWith(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncIncludes(ExecState*); -EncodedJSValue JSC_HOST_CALL stringProtoFuncIterator(ExecState*); - -const ClassInfo StringPrototype::s_info = { "String", &StringObject::s_info, 0, CREATE_METHOD_TABLE(StringPrototype) }; +static EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncBig(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncBold(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncSub(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncSup(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState*); +static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState*); + +const ClassInfo StringPrototype::s_info = { "String", &StringObject::s_info, 0, 0, CREATE_METHOD_TABLE(StringPrototype) }; // ECMA 15.5.4 StringPrototype::StringPrototype(VM& vm, Structure* structure) @@ -109,12 +99,10 @@ void StringPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject, JSStr 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("codePointAt", stringProtoFuncCodePointAt, DontEnum, 1); 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("repeat", stringProtoFuncRepeat, DontEnum, 1); JSC_NATIVE_FUNCTION("replace", stringProtoFuncReplace, DontEnum, 2); JSC_NATIVE_FUNCTION("search", stringProtoFuncSearch, DontEnum, 1); JSC_NATIVE_FUNCTION("slice", stringProtoFuncSlice, DontEnum, 2); @@ -142,12 +130,6 @@ void StringPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject, JSStr JSC_NATIVE_FUNCTION("trim", stringProtoFuncTrim, DontEnum, 0); JSC_NATIVE_FUNCTION("trimLeft", stringProtoFuncTrimLeft, DontEnum, 0); JSC_NATIVE_FUNCTION("trimRight", stringProtoFuncTrimRight, DontEnum, 0); - JSC_NATIVE_FUNCTION("startsWith", stringProtoFuncStartsWith, DontEnum, 1); - JSC_NATIVE_FUNCTION("endsWith", stringProtoFuncEndsWith, DontEnum, 1); - JSC_NATIVE_FUNCTION("includes", stringProtoFuncIncludes, DontEnum, 1); - JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorSymbol, stringProtoFuncIterator, DontEnum, 0); - - JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->charCodeAtPrivateName, stringProtoFuncCharCodeAt, DontEnum, 1, CharCodeAtIntrinsic); // The constructor will be added later, after StringConstructor has been built putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), DontDelete | ReadOnly | DontEnum); @@ -175,19 +157,10 @@ static inline JSString* jsStringWithReuse(ExecState* exec, JSValue originalValue return jsString(exec, string); } -// Helper that tries to use the JSString substring sharing mechanism if 'originalValue' is a JSString. -static inline JSString* jsSubstring(ExecState* exec, JSValue originalValue, const String& string, unsigned offset, unsigned length) -{ - if (originalValue.isString()) { - ASSERT(asString(originalValue)->value(exec) == string); - return jsSubstring(exec, asString(originalValue), offset, length); - } - return jsSubstring(exec, string, offset, length); -} - -static NEVER_INLINE String substituteBackreferencesSlow(StringView replacement, StringView source, const int* ovector, RegExp* reg, size_t i) +template <typename CharType> +static NEVER_INLINE String substituteBackreferencesSlow(const String& replacement, const String& source, const int* ovector, RegExp* reg, size_t i) { - StringBuilder substitutedReplacement; + Vector<CharType> substitutedReplacement; int offset = 0; do { if (i + 1 == replacement.length()) @@ -197,7 +170,7 @@ static NEVER_INLINE String substituteBackreferencesSlow(StringView replacement, if (ref == '$') { // "$$" -> "$" ++i; - substitutedReplacement.append(replacement.substring(offset, i - offset)); + substitutedReplacement.append(replacement.getCharactersWithUpconvert<CharType>() + offset, i - offset); offset = i + 1; continue; } @@ -237,29 +210,38 @@ static NEVER_INLINE String substituteBackreferencesSlow(StringView replacement, continue; if (i - offset) - substitutedReplacement.append(replacement.substring(offset, i - offset)); + substitutedReplacement.append(replacement.getCharactersWithUpconvert<CharType>() + offset, i - offset); i += 1 + advance; offset = i + 1; if (backrefStart >= 0) - substitutedReplacement.append(source.substring(backrefStart, backrefLength)); + substitutedReplacement.append(source.getCharactersWithUpconvert<CharType>() + backrefStart, backrefLength); } while ((i = replacement.find('$', i + 1)) != notFound); if (replacement.length() - offset) - substitutedReplacement.append(replacement.substring(offset)); + substitutedReplacement.append(replacement.getCharactersWithUpconvert<CharType>() + offset, replacement.length() - offset); - return substitutedReplacement.toString(); + substitutedReplacement.shrinkToFit(); + return String::adopt(substitutedReplacement); } -static inline String substituteBackreferences(const String& replacement, StringView source, const int* ovector, RegExp* reg) +static inline String substituteBackreferences(const String& replacement, const String& source, const int* ovector, RegExp* reg) { size_t i = replacement.find('$'); - if (UNLIKELY(i != notFound)) - return substituteBackreferencesSlow(replacement, source, ovector, reg, i); - + if (UNLIKELY(i != notFound)) { + if (replacement.is8Bit() && source.is8Bit()) + return substituteBackreferencesSlow<LChar>(replacement, source, ovector, reg, i); + return substituteBackreferencesSlow<UChar>(replacement, source, ovector, reg, i); + } return replacement; } +static inline int localeCompare(const String& a, const String& b) +{ + return Collator::userDefault()->collate(reinterpret_cast<const ::UChar*>(a.deprecatedCharacters()), a.length(), reinterpret_cast<const ::UChar*>(b.deprecatedCharacters()), b.length()); +} + struct StringRange { +public: StringRange(int pos, int len) : position(pos) , length(len) @@ -283,7 +265,7 @@ static ALWAYS_INLINE JSValue jsSpliceSubstrings(ExecState* exec, JSString* sourc if (position <= 0 && length >= sourceSize) return sourceVal; // We could call String::substringSharingImpl(), but this would result in redundant checks. - return jsString(exec, StringImpl::createSubstringSharingImpl(source.impl(), std::max(0, position), std::min(sourceSize, length))); + return jsString(exec, StringImpl::create(source.impl(), std::max(0, position), std::min(sourceSize, length))); } int totalLength = 0; @@ -338,7 +320,7 @@ static ALWAYS_INLINE JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, J if (position <= 0 && length >= sourceSize) return sourceVal; // We could call String::substringSharingImpl(), but this would result in redundant checks. - return jsString(exec, StringImpl::createSubstringSharingImpl(source.impl(), std::max(0, position), std::min(sourceSize, length))); + return jsString(exec, StringImpl::create(source.impl(), std::max(0, position), std::min(sourceSize, length))); } Checked<int, RecordOverflow> totalLength = 0; @@ -668,14 +650,14 @@ static inline EncodedJSValue replaceUsingStringSearch(ExecState* exec, JSString* return JSValue::encode(jsUndefined()); StringImpl* stringImpl = string.impl(); - String leftPart(StringImpl::createSubstringSharingImpl(stringImpl, 0, matchStart)); + String leftPart(StringImpl::create(stringImpl, 0, matchStart)); size_t matchEnd = matchStart + searchString.impl()->length(); int ovector[2] = { static_cast<int>(matchStart), static_cast<int>(matchEnd)}; String middlePart = substituteBackreferences(replaceString, string, ovector, 0); size_t leftLength = stringImpl->length() - matchEnd; - String rightPart(StringImpl::createSubstringSharingImpl(stringImpl, matchEnd, leftLength)); + String rightPart(StringImpl::create(stringImpl, matchEnd, leftLength)); return JSValue::encode(JSC::jsString(exec, leftPart, middlePart, rightPart)); } @@ -693,69 +675,9 @@ static inline bool checkObjectCoercible(JSValue thisValue) return true; } -template <typename CharacterType> -static inline JSValue repeatCharacter(ExecState* exec, CharacterType character, unsigned repeatCount) -{ - CharacterType* buffer = nullptr; - RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(repeatCount, buffer); - if (!impl) - return throwOutOfMemoryError(exec); - - std::fill_n(buffer, repeatCount, character); - - return jsString(exec, impl.release()); -} - -EncodedJSValue JSC_HOST_CALL stringProtoFuncRepeat(ExecState* exec) -{ - JSValue thisValue = exec->thisValue(); - if (!checkObjectCoercible(thisValue)) - return throwVMTypeError(exec); - - JSString* string = thisValue.toString(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - double repeatCountDouble = exec->argument(0).toInteger(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - if (repeatCountDouble < 0 || std::isinf(repeatCountDouble)) - return throwVMError(exec, createRangeError(exec, ASCIILiteral("repeat() argument must be greater than or equal to 0 and not be infinity"))); - - VM& vm = exec->vm(); - - if (!string->length() || !repeatCountDouble) - return JSValue::encode(jsEmptyString(&vm)); - - if (repeatCountDouble == 1) - return JSValue::encode(string); - - // JSString requires the limitation that its length is in the range of int32_t. - if (repeatCountDouble > std::numeric_limits<int32_t>::max() / string->length()) - return JSValue::encode(throwOutOfMemoryError(exec)); - unsigned repeatCount = static_cast<unsigned>(repeatCountDouble); - - // For a string which length is small, instead of creating ropes, - // allocating a sequential buffer and fill with the repeated string for efficiency. - if (string->length() == 1) { - String repeatedString = string->value(exec); - UChar character = repeatedString.at(0); - if (!(character & ~0xff)) - return JSValue::encode(repeatCharacter(exec, static_cast<LChar>(character), repeatCount)); - return JSValue::encode(repeatCharacter(exec, character, repeatCount)); - } - - JSRopeString::RopeBuilder ropeBuilder(vm); - for (unsigned i = 0; i < repeatCount; ++i) { - if (!ropeBuilder.append(string)) - return JSValue::encode(throwOutOfMemoryError(exec)); - } - return JSValue::encode(ropeBuilder.release()); -} - EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); JSString* string = thisValue.toString(exec); @@ -768,7 +690,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); // Also used for valueOf. if (thisValue.isString()) @@ -782,81 +704,50 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); - StringView string = thisValue.toString(exec)->view(exec); + String s = thisValue.toString(exec)->value(exec); + unsigned len = s.length(); JSValue a0 = exec->argument(0); if (a0.isUInt32()) { uint32_t i = a0.asUInt32(); - if (i < string.length()) - return JSValue::encode(jsSingleCharacterString(exec, string[i])); + if (i < len) + return JSValue::encode(jsSingleCharacterSubstring(exec, s, i)); return JSValue::encode(jsEmptyString(exec)); } double dpos = a0.toInteger(exec); - if (dpos >= 0 && dpos < string.length()) - return JSValue::encode(jsSingleCharacterString(exec, string[static_cast<unsigned>(dpos)])); + if (dpos >= 0 && dpos < len) + return JSValue::encode(jsSingleCharacterSubstring(exec, s, static_cast<unsigned>(dpos))); return JSValue::encode(jsEmptyString(exec)); } EncodedJSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); - StringView string = thisValue.toString(exec)->view(exec); + String s = thisValue.toString(exec)->value(exec); + unsigned len = s.length(); JSValue a0 = exec->argument(0); if (a0.isUInt32()) { uint32_t i = a0.asUInt32(); - if (i < string.length()) - return JSValue::encode(jsNumber(string[i])); + if (i < len) { + if (s.is8Bit()) + return JSValue::encode(jsNumber(s.characters8()[i])); + return JSValue::encode(jsNumber(s.characters16()[i])); + } return JSValue::encode(jsNaN()); } double dpos = a0.toInteger(exec); - if (dpos >= 0 && dpos < string.length()) - return JSValue::encode(jsNumber(string[static_cast<int>(dpos)])); + if (dpos >= 0 && dpos < len) + return JSValue::encode(jsNumber(s[static_cast<int>(dpos)])); return JSValue::encode(jsNaN()); } -static inline UChar32 codePointAt(const String& string, unsigned position, unsigned length) -{ - RELEASE_ASSERT(position < length); - if (string.is8Bit()) - return string.characters8()[position]; - UChar32 character; - U16_NEXT(string.characters16(), position, length, character); - return character; -} - -EncodedJSValue JSC_HOST_CALL stringProtoFuncCodePointAt(ExecState* exec) -{ - JSValue thisValue = exec->thisValue(); - if (!checkObjectCoercible(thisValue)) - return throwVMTypeError(exec); - - String string = thisValue.toWTFString(exec); - unsigned length = string.length(); - - JSValue argument0 = exec->argument(0); - if (argument0.isUInt32()) { - unsigned position = argument0.asUInt32(); - if (position < length) - return JSValue::encode(jsNumber(codePointAt(string, position, length))); - return JSValue::encode(jsUndefined()); - } - - if (UNLIKELY(exec->hadException())) - return JSValue::encode(jsUndefined()); - - double doublePosition = argument0.toInteger(exec); - if (doublePosition >= 0 && doublePosition < length) - return JSValue::encode(jsNumber(codePointAt(string, static_cast<unsigned>(doublePosition), length))); - return JSValue::encode(jsUndefined()); -} - EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (thisValue.isString() && exec->argumentCount() == 1) return JSValue::encode(jsString(exec, asString(thisValue), exec->uncheckedArgument(0).toString(exec))); @@ -867,19 +758,21 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); + String s = thisValue.toString(exec)->value(exec); JSValue a0 = exec->argument(0); JSValue a1 = exec->argument(1); + String u2 = a0.toString(exec)->value(exec); - JSString* thisJSString = thisValue.toString(exec); - JSString* otherJSString = a0.toString(exec); - - unsigned pos = 0; - if (!a1.isUndefined()) { - int len = thisJSString->length(); + size_t result; + if (a1.isUndefined()) + result = s.find(u2); + else { + unsigned pos; + int len = s.length(); RELEASE_ASSERT(len >= 0); if (a1.isUInt32()) pos = std::min<uint32_t>(a1.asUInt32(), len); @@ -891,12 +784,9 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec) dpos = len; pos = static_cast<unsigned>(dpos); } + result = s.find(u2, pos); } - if (thisJSString->length() < otherJSString->length() + pos) - return JSValue::encode(jsNumber(-1)); - - size_t result = thisJSString->view(exec).get().find(otherJSString->view(exec), pos); if (result == notFound) return JSValue::encode(jsNumber(-1)); return JSValue::encode(jsNumber(result)); @@ -904,36 +794,28 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); + String s = thisValue.toString(exec)->value(exec); + int len = s.length(); JSValue a0 = exec->argument(0); JSValue a1 = exec->argument(1); - JSString* thisJSString = thisValue.toString(exec); - unsigned len = thisJSString->length(); - JSString* otherJSString = a0.toString(exec); - + String u2 = a0.toString(exec)->value(exec); double dpos = a1.toIntegerPreserveNaN(exec); - unsigned startPosition; if (dpos < 0) - startPosition = 0; + dpos = 0; else if (!(dpos <= len)) // true for NaN - startPosition = len; - else - startPosition = static_cast<unsigned>(dpos); - - if (len < otherJSString->length()) - return JSValue::encode(jsNumber(-1)); + dpos = len; - String thisString = thisJSString->value(exec); - String otherString = otherJSString->value(exec); size_t result; + unsigned startPosition = static_cast<unsigned>(dpos); if (!startPosition) - result = thisString.startsWith(otherString) ? 0 : notFound; + result = s.startsWith(u2) ? 0 : notFound; else - result = thisString.reverseFind(otherString, startPosition); + result = s.reverseFind(u2, startPosition); if (result == notFound) return JSValue::encode(jsNumber(-1)); return JSValue::encode(jsNumber(result)); @@ -941,7 +823,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); JSString* string = thisValue.toString(exec); @@ -976,7 +858,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec) 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 ? createRegExpMatchesArray(exec, string, regExp, result) : jsNull()); + return JSValue::encode(result ? RegExpMatchesArray::create(exec, string, regExp, result) : jsNull()); // return array of matches MarkedArgumentBuffer list; @@ -1000,7 +882,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); JSString* string = thisValue.toString(exec); @@ -1030,7 +912,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); String s = thisValue.toString(exec)->value(exec); @@ -1058,11 +940,11 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState* exec) // Return true in case of early return (resultLength got to limitLength). template<typename CharacterType> -static ALWAYS_INLINE bool splitStringByOneCharacterImpl(ExecState* exec, JSArray* result, JSValue originalValue, const String& input, StringImpl* string, UChar separatorCharacter, size_t& position, unsigned& resultLength, unsigned limitLength) +static ALWAYS_INLINE bool splitStringByOneCharacterImpl(ExecState* exec, JSArray* result, const String& input, StringImpl* string, UChar separatorCharacter, size_t& position, unsigned& resultLength, unsigned limitLength) { // 12. Let q = p. size_t matchPosition; - const CharacterType* characters = string->characters<CharacterType>(); + const CharacterType* characters = string->getCharacters<CharacterType>(); // 13. Repeat, while q != s // a. Call SplitMatch(S, q, R) and let z be its MatchResult result. // b. If z is failure, then let q = q+1. @@ -1072,7 +954,7 @@ static ALWAYS_INLINE bool splitStringByOneCharacterImpl(ExecState* exec, JSArray // through q (exclusive). // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA), // Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false. - result->putDirectIndex(exec, resultLength, jsSubstring(exec, originalValue, input, position, matchPosition - position)); + result->putDirectIndex(exec, resultLength, jsSubstring(exec, input, position, matchPosition - position)); // 3. Increment lengthA by 1. // 4. If lengthA == lim, return A. if (++resultLength == limitLength) @@ -1089,7 +971,7 @@ static ALWAYS_INLINE bool splitStringByOneCharacterImpl(ExecState* exec, JSArray EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec) { // 1. Call CheckObjectCoercible passing the this value as its argument. - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); @@ -1150,16 +1032,11 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec) // a. Call SplitMatch(S, q, R) and let z be its MatchResult result. Vector<int, 32> ovector; int mpos = reg->match(*vm, input, matchPosition, ovector); - - // b. If z is a failure then we can break because there are no matches + // b. If z is failure, then let q = q + 1. if (mpos < 0) break; matchPosition = mpos; - // if the match is the empty match at the end, break. - if (matchPosition >= input.length()) - break; - // c. Else, z is not failure // i. z must be a State. Let e be z's endIndex and let cap be z's captures array. size_t matchEnd = ovector[1]; @@ -1169,17 +1046,13 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec) ++matchPosition; continue; } - // iii. if matchEnd == 0 then position should also be zero and thus matchEnd should equal position. - ASSERT(matchEnd); - // iii. Else, e != p // 1. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive) // through q (exclusive). // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA), // Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false. - result->putDirectIndex(exec, resultLength, jsSubstring(exec, thisValue, input, position, matchPosition - position)); - + result->putDirectIndex(exec, resultLength, jsSubstring(exec, input, position, matchPosition - position)); // 3. Increment lengthA by 1. // 4. If lengthA == lim, return A. if (++resultLength == limit) @@ -1198,7 +1071,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec) // ToString(lengthA), Property Descriptor {[[Value]]: cap[i], [[Writable]]: // true, [[Enumerable]]: true, [[Configurable]]: true}, and false. int sub = ovector[i * 2]; - result->putDirectIndex(exec, resultLength, sub < 0 ? jsUndefined() : jsSubstring(exec, thisValue, input, sub, ovector[i * 2 + 1] - sub)); + result->putDirectIndex(exec, resultLength, sub < 0 ? jsUndefined() : jsSubstring(exec, input, sub, ovector[i * 2 + 1] - sub)); // c Increment lengthA by 1. // d If lengthA == lim, return A. if (++resultLength == limit) @@ -1241,7 +1114,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec) ASSERT(limit); do { - result->putDirectIndex(exec, position, jsSingleCharacterString(exec, input[position])); + result->putDirectIndex(exec, position, jsSingleCharacterSubstring(exec, input, position)); } while (++position < limit); return JSValue::encode(result); @@ -1263,10 +1136,10 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec) separatorCharacter = separatorImpl->characters16()[0]; if (stringImpl->is8Bit()) { - if (splitStringByOneCharacterImpl<LChar>(exec, result, thisValue, input, stringImpl, separatorCharacter, position, resultLength, limit)) + if (splitStringByOneCharacterImpl<LChar>(exec, result, input, stringImpl, separatorCharacter, position, resultLength, limit)) return JSValue::encode(result); } else { - if (splitStringByOneCharacterImpl<UChar>(exec, result, thisValue, input, stringImpl, separatorCharacter, position, resultLength, limit)) + if (splitStringByOneCharacterImpl<UChar>(exec, result, input, stringImpl, separatorCharacter, position, resultLength, limit)) return JSValue::encode(result); } } else { @@ -1281,7 +1154,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec) // through q (exclusive). // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA), // Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false. - result->putDirectIndex(exec, resultLength, jsSubstring(exec, thisValue, input, position, matchPosition - position)); + result->putDirectIndex(exec, resultLength, jsSubstring(exec, input, position, matchPosition - position)); // 3. Increment lengthA by 1. // 4. If lengthA == lim, return A. if (++resultLength == limit) @@ -1298,7 +1171,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec) // through s (exclusive). // 15. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA), Property Descriptor // {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false. - result->putDirectIndex(exec, resultLength++, jsSubstring(exec, thisValue, input, position, input.length() - position)); + result->putDirectIndex(exec, resultLength++, jsSubstring(exec, input, position, input.length() - position)); // 16. Return A. return JSValue::encode(result); @@ -1306,7 +1179,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); unsigned len; @@ -1345,8 +1218,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec) { - SamplingRegion samplingRegion("Doing substringing"); - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); @@ -1386,7 +1258,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); JSString* sVal = thisValue.toString(exec); @@ -1406,7 +1278,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); JSString* sVal = thisValue.toString(exec); @@ -1425,18 +1297,18 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); String s = thisValue.toString(exec)->value(exec); JSValue a0 = exec->argument(0); - return JSValue::encode(jsNumber(Collator().collate(s, a0.toString(exec)->value(exec)))); + return JSValue::encode(jsNumber(localeCompare(s, a0.toString(exec)->value(exec)))); } EncodedJSValue JSC_HOST_CALL stringProtoFuncBig(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); String s = thisValue.toString(exec)->value(exec); @@ -1445,7 +1317,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncBig(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); String s = thisValue.toString(exec)->value(exec); @@ -1454,7 +1326,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); String s = thisValue.toString(exec)->value(exec); @@ -1463,7 +1335,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncBold(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); String s = thisValue.toString(exec)->value(exec); @@ -1472,7 +1344,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncBold(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); String s = thisValue.toString(exec)->value(exec); @@ -1481,7 +1353,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); String s = thisValue.toString(exec)->value(exec); @@ -1490,7 +1362,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); String s = thisValue.toString(exec)->value(exec); @@ -1499,7 +1371,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncSub(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); String s = thisValue.toString(exec)->value(exec); @@ -1508,7 +1380,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSub(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncSup(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); String s = thisValue.toString(exec)->value(exec); @@ -1517,7 +1389,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSup(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); String s = thisValue.toString(exec)->value(exec); @@ -1530,7 +1402,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); String s = thisValue.toString(exec)->value(exec); @@ -1540,7 +1412,6 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec) if (a0.getUInt32(smallInteger) && smallInteger <= 9) { unsigned stringSize = s.length(); unsigned bufferSize = 22 + stringSize; - // FIXME: Should we have an 8-bit version of this code path too? Or maybe only an 8-bit version? UChar* buffer; PassRefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(bufferSize, buffer); if (!impl) @@ -1560,7 +1431,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec) buffer[12] = '0' + smallInteger; buffer[13] = '"'; buffer[14] = '>'; - StringView(s).getCharactersWithUpconvert(&buffer[15]); + memcpy(&buffer[15], s.deprecatedCharacters(), stringSize * sizeof(UChar)); buffer[15 + stringSize] = '<'; buffer[16 + stringSize] = '/'; buffer[17 + stringSize] = 'f'; @@ -1579,7 +1450,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); String s = thisValue.toString(exec)->value(exec); @@ -1592,7 +1463,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); if (!checkObjectCoercible(thisValue)) return throwVMTypeError(exec); String s = thisValue.toString(exec)->value(exec); @@ -1603,7 +1474,6 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec) unsigned linkTextSize = linkText.length(); unsigned stringSize = s.length(); unsigned bufferSize = 15 + linkTextSize + stringSize; - // FIXME: Should we have an 8-bit version of this code path too? Or maybe only an 8-bit version? UChar* buffer; PassRefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(bufferSize, buffer); if (!impl) @@ -1617,10 +1487,10 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec) buffer[6] = 'f'; buffer[7] = '='; buffer[8] = '"'; - StringView(linkText).getCharactersWithUpconvert(&buffer[9]); + memcpy(&buffer[9], linkText.deprecatedCharacters(), linkTextSize * sizeof(UChar)); buffer[9 + linkTextSize] = '"'; buffer[10 + linkTextSize] = '>'; - StringView(s).getCharactersWithUpconvert(&buffer[11 + linkTextSize]); + memcpy(&buffer[11 + linkTextSize], s.deprecatedCharacters(), stringSize * sizeof(UChar)); buffer[11 + linkTextSize + stringSize] = '<'; buffer[12 + linkTextSize + stringSize] = '/'; buffer[13 + linkTextSize + stringSize] = 'a'; @@ -1633,6 +1503,11 @@ enum { TrimRight = 2 }; +static inline bool isTrimWhitespace(UChar c) +{ + return isStrWhiteSpace(c) || c == 0x200b; +} + static inline JSValue trimString(ExecState* exec, JSValue thisValue, int trimKind) { if (!checkObjectCoercible(thisValue)) @@ -1640,12 +1515,12 @@ static inline JSValue trimString(ExecState* exec, JSValue thisValue, int trimKin String str = thisValue.toString(exec)->value(exec); unsigned left = 0; if (trimKind & TrimLeft) { - while (left < str.length() && isStrWhiteSpace(str[left])) + while (left < str.length() && isTrimWhitespace(str[left])) left++; } unsigned right = str.length(); if (trimKind & TrimRight) { - while (right > left && isStrWhiteSpace(str[right - 1])) + while (right > left && isTrimWhitespace(str[right - 1])) right--; } @@ -1658,135 +1533,21 @@ static inline JSValue trimString(ExecState* exec, JSValue thisValue, int trimKin EncodedJSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); return JSValue::encode(trimString(exec, thisValue, TrimLeft | TrimRight)); } EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); return JSValue::encode(trimString(exec, thisValue, TrimLeft)); } EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState* exec) { - JSValue thisValue = exec->thisValue(); + JSValue thisValue = exec->hostThisValue(); return JSValue::encode(trimString(exec, thisValue, TrimRight)); } - -static inline unsigned clampAndTruncateToUnsigned(double value, unsigned min, unsigned max) -{ - if (value < min) - return min; - if (value > max) - return max; - return static_cast<unsigned>(value); -} - -EncodedJSValue JSC_HOST_CALL stringProtoFuncStartsWith(ExecState* exec) -{ - JSValue thisValue = exec->thisValue(); - if (!checkObjectCoercible(thisValue)) - return throwVMTypeError(exec); - - String stringToSearchIn = thisValue.toString(exec)->value(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - JSValue a0 = exec->argument(0); - if (jsDynamicCast<RegExpObject*>(a0)) - return throwVMTypeError(exec); - - String searchString = a0.toString(exec)->value(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - JSValue positionArg = exec->argument(1); - unsigned start = 0; - if (positionArg.isInt32()) - start = std::max(0, positionArg.asInt32()); - else { - unsigned length = stringToSearchIn.length(); - start = clampAndTruncateToUnsigned(positionArg.toInteger(exec), 0, length); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - } - - return JSValue::encode(jsBoolean(stringToSearchIn.hasInfixStartingAt(searchString, start))); -} - -EncodedJSValue JSC_HOST_CALL stringProtoFuncEndsWith(ExecState* exec) -{ - JSValue thisValue = exec->thisValue(); - if (!checkObjectCoercible(thisValue)) - return throwVMTypeError(exec); - - String stringToSearchIn = thisValue.toString(exec)->value(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - JSValue a0 = exec->argument(0); - if (jsDynamicCast<RegExpObject*>(a0)) - return throwVMTypeError(exec); - - String searchString = a0.toString(exec)->value(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - unsigned length = stringToSearchIn.length(); - - JSValue endPositionArg = exec->argument(1); - unsigned end = length; - if (endPositionArg.isInt32()) - end = std::max(0, endPositionArg.asInt32()); - else if (!endPositionArg.isUndefined()) { - end = clampAndTruncateToUnsigned(endPositionArg.toInteger(exec), 0, length); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - } - - return JSValue::encode(jsBoolean(stringToSearchIn.hasInfixEndingAt(searchString, std::min(end, length)))); -} - -EncodedJSValue JSC_HOST_CALL stringProtoFuncIncludes(ExecState* exec) -{ - JSValue thisValue = exec->thisValue(); - if (!checkObjectCoercible(thisValue)) - return throwVMTypeError(exec); - - String stringToSearchIn = thisValue.toString(exec)->value(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - JSValue a0 = exec->argument(0); - if (jsDynamicCast<RegExpObject*>(a0)) - return throwVMTypeError(exec); - - String searchString = a0.toString(exec)->value(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - JSValue positionArg = exec->argument(1); - unsigned start = 0; - if (positionArg.isInt32()) - start = std::max(0, positionArg.asInt32()); - else { - unsigned length = stringToSearchIn.length(); - start = clampAndTruncateToUnsigned(positionArg.toInteger(exec), 0, length); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - } - - return JSValue::encode(jsBoolean(stringToSearchIn.contains(searchString, true, start))); -} - -EncodedJSValue JSC_HOST_CALL stringProtoFuncIterator(ExecState* exec) -{ - JSValue thisValue = exec->thisValue(); - if (!checkObjectCoercible(thisValue)) - return throwVMTypeError(exec); - JSString* string = thisValue.toString(exec); - return JSValue::encode(JSStringIterator::create(exec, exec->callee()->globalObject()->stringIteratorStructure(), string)); -} - + + } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/StringPrototype.h b/Source/JavaScriptCore/runtime/StringPrototype.h index bd4f02a61..fe22453ad 100644 --- a/Source/JavaScriptCore/runtime/StringPrototype.h +++ b/Source/JavaScriptCore/runtime/StringPrototype.h @@ -25,28 +25,29 @@ namespace JSC { -class ObjectPrototype; + class ObjectPrototype; -class StringPrototype : public StringObject { -private: - StringPrototype(VM&, Structure*); + class StringPrototype : public StringObject { + private: + StringPrototype(VM&, Structure*); -public: - typedef StringObject Base; - static const unsigned StructureFlags = Base::StructureFlags; + public: + typedef StringObject Base; - static StringPrototype* create(VM&, JSGlobalObject*, Structure*); + static StringPrototype* create(VM&, JSGlobalObject*, Structure*); - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } - DECLARE_INFO; + DECLARE_INFO; + + protected: + void finishCreation(VM&, JSGlobalObject*, JSString*); + static const unsigned StructureFlags = StringObject::StructureFlags; -protected: - void finishCreation(VM&, JSGlobalObject*, JSString*); -}; + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/StringRecursionChecker.cpp b/Source/JavaScriptCore/runtime/StringRecursionChecker.cpp index 638310787..1f204231e 100644 --- a/Source/JavaScriptCore/runtime/StringRecursionChecker.cpp +++ b/Source/JavaScriptCore/runtime/StringRecursionChecker.cpp @@ -22,13 +22,13 @@ #include "Error.h" #include "ExceptionHelpers.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { JSValue StringRecursionChecker::throwStackOverflowError() { - return JSC::throwStackOverflowError(m_exec); + return m_exec->vm().throwException(m_exec, createStackOverflowError(m_exec)); } JSValue StringRecursionChecker::emptyString() diff --git a/Source/JavaScriptCore/runtime/StringRecursionChecker.h b/Source/JavaScriptCore/runtime/StringRecursionChecker.h index 0f1990e76..c99dd4ff1 100644 --- a/Source/JavaScriptCore/runtime/StringRecursionChecker.h +++ b/Source/JavaScriptCore/runtime/StringRecursionChecker.h @@ -52,15 +52,7 @@ inline JSValue StringRecursionChecker::performCheck() VM& vm = m_exec->vm(); if (!vm.isSafeToRecurse()) return throwStackOverflowError(); - - bool alreadyVisited = false; - if (!vm.stringRecursionCheckFirstObject) - vm.stringRecursionCheckFirstObject = m_thisObject; - else if (vm.stringRecursionCheckFirstObject == m_thisObject) - alreadyVisited = true; - else - alreadyVisited = !vm.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. @@ -82,14 +74,8 @@ inline StringRecursionChecker::~StringRecursionChecker() { if (m_earlyReturnValue) return; - - VM& vm = m_exec->vm(); - if (vm.stringRecursionCheckFirstObject == m_thisObject) - vm.stringRecursionCheckFirstObject = nullptr; - else { - ASSERT(vm.stringRecursionCheckVisitedObjects.contains(m_thisObject)); - vm.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 28f8d4803..8781ab007 100644 --- a/Source/JavaScriptCore/runtime/Structure.cpp +++ b/Source/JavaScriptCore/runtime/Structure.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2013-2015 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 @@ -10,10 +10,10 @@ * 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 + * 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 INC. OR + * 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 @@ -28,18 +28,13 @@ #include "CodeBlock.h" #include "DumpContext.h" -#include "JSCInlines.h" #include "JSObject.h" -#include "JSPropertyNameEnumerator.h" +#include "JSPropertyNameIterator.h" #include "Lookup.h" -#include "PropertyMapHashTable.h" #include "PropertyNameArray.h" #include "StructureChain.h" #include "StructureRareDataInlines.h" -#include "WeakGCMapInlines.h" #include <wtf/CommaPrinter.h> -#include <wtf/NeverDestroyed.h> -#include <wtf/ProcessID.h> #include <wtf/RefCountedLeakCounter.h> #include <wtf/RefPtr.h> #include <wtf/Threading.h> @@ -55,79 +50,53 @@ using namespace std; using namespace WTF; +#if DUMP_PROPERTYMAP_STATS + +int numProbes; +int numCollisions; +int numRehashes; +int numRemoves; + +#endif + namespace JSC { #if DUMP_STRUCTURE_ID_STATISTICS static HashSet<Structure*>& liveStructureSet = *(new HashSet<Structure*>); #endif -class SingleSlotTransitionWeakOwner final : public WeakHandleOwner { - void finalize(Handle<Unknown>, void* context) override - { - StructureTransitionTable* table = reinterpret_cast<StructureTransitionTable*>(context); - ASSERT(table->isUsingSingleSlot()); - WeakSet::deallocate(table->weakImpl()); - table->m_data = StructureTransitionTable::UsingSingleSlotFlag; - } -}; - -static SingleSlotTransitionWeakOwner& singleSlotTransitionWeakOwner() -{ - static NeverDestroyed<SingleSlotTransitionWeakOwner> owner; - return owner; -} - -inline Structure* StructureTransitionTable::singleTransition() const -{ - ASSERT(isUsingSingleSlot()); - if (WeakImpl* impl = this->weakImpl()) { - if (impl->state() == WeakImpl::Live) - return jsCast<Structure*>(impl->jsValue().asCell()); - } - return nullptr; -} - -inline void StructureTransitionTable::setSingleTransition(Structure* structure) -{ - ASSERT(isUsingSingleSlot()); - if (WeakImpl* impl = this->weakImpl()) - WeakSet::deallocate(impl); - WeakImpl* impl = WeakSet::allocate(structure, &singleSlotTransitionWeakOwner(), this); - m_data = reinterpret_cast<intptr_t>(impl) | UsingSingleSlotFlag; -} - -bool StructureTransitionTable::contains(UniquedStringImpl* rep, unsigned attributes) const +bool StructureTransitionTable::contains(StringImpl* rep, unsigned attributes) const { if (isUsingSingleSlot()) { Structure* transition = singleTransition(); - return transition && transition->m_nameInPrevious == rep && transition->attributesInPrevious() == attributes; + return transition && transition->m_nameInPrevious == rep && transition->m_attributesInPrevious == attributes; } return map()->get(std::make_pair(rep, attributes)); } -Structure* StructureTransitionTable::get(UniquedStringImpl* rep, unsigned attributes) const +inline Structure* StructureTransitionTable::get(StringImpl* rep, unsigned attributes) const { if (isUsingSingleSlot()) { Structure* transition = singleTransition(); - return (transition && transition->m_nameInPrevious == rep && transition->attributesInPrevious() == attributes) ? transition : 0; + return (transition && transition->m_nameInPrevious == rep && transition->m_attributesInPrevious == attributes) ? transition : 0; } return map()->get(std::make_pair(rep, attributes)); } -void StructureTransitionTable::add(VM& vm, 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(structure); + setSingleTransition(vm, structure); return; } // This handles the second transition being added // (or the first transition being despecified!) - setMap(new TransitionMap(vm)); + setMap(new TransitionMap()); add(vm, existingTransition); } @@ -136,7 +105,7 @@ void StructureTransitionTable::add(VM& vm, 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 - map()->set(std::make_pair(structure->m_nameInPrevious.get(), +structure->attributesInPrevious()), structure); + map()->set(std::make_pair(structure->m_nameInPrevious.get(), +structure->m_attributesInPrevious), structure); } void Structure::dumpStatistics() @@ -186,37 +155,33 @@ void Structure::dumpStatistics() Structure::Structure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, unsigned inlineCapacity) : JSCell(vm, vm.structureStructure.get()) - , m_blob(vm.heap.structureIDTable().allocateID(this), indexingType, typeInfo) - , m_outOfLineTypeFlags(typeInfo.outOfLineTypeFlags()) , m_globalObject(vm, this, globalObject, WriteBarrier<JSGlobalObject>::MayBeNull) , m_prototype(vm, this, prototype) , m_classInfo(classInfo) , m_transitionWatchpointSet(IsWatched) , m_offset(invalidOffset) + , m_typeInfo(typeInfo) + , m_indexingType(indexingType) , m_inlineCapacity(inlineCapacity) - , m_bitField(0) + , m_dictionaryKind(NoneDictionaryKind) + , m_isPinnedPropertyTable(false) + , m_hasGetterSetterProperties(classInfo->hasStaticSetterOrReadonlyProperties(vm)) + , m_hasReadOnlyOrGetterSetterPropertiesExcludingProto(classInfo->hasStaticSetterOrReadonlyProperties(vm)) + , m_hasNonEnumerableProperties(false) + , m_attributesInPrevious(0) + , m_specificFunctionThrashCount(0) + , m_preventExtensions(false) + , m_didTransition(false) + , m_staticFunctionReified(false) { - setDictionaryKind(NoneDictionaryKind); - setIsPinnedPropertyTable(false); - setHasGetterSetterProperties(classInfo->hasStaticSetterOrReadonlyProperties()); - setHasCustomGetterSetterProperties(false); - setHasReadOnlyOrGetterSetterPropertiesExcludingProto(classInfo->hasStaticSetterOrReadonlyProperties()); - setHasNonEnumerableProperties(false); - setAttributesInPrevious(0); - setPreventExtensions(false); - setDidTransition(false); - setStaticFunctionsReified(false); - setHasRareData(false); - setTransitionWatchpointIsLikelyToBeFired(false); - ASSERT(inlineCapacity <= JSFinalObject::maxInlineCapacity()); ASSERT(static_cast<PropertyOffset>(inlineCapacity) < firstOutOfLineOffset); - ASSERT(!hasRareData()); - ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !m_classInfo->hasStaticSetterOrReadonlyProperties()); - ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties()); + ASSERT(!typeInfo.structureHasRareData()); + ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !m_classInfo->hasStaticSetterOrReadonlyProperties(vm)); + ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties(vm)); } -const ClassInfo Structure::s_info = { "Structure", 0, 0, CREATE_METHOD_TABLE(Structure) }; +const ClassInfo Structure::s_info = { "Structure", 0, 0, 0, CREATE_METHOD_TABLE(Structure) }; Structure::Structure(VM& vm) : JSCell(CreatingEarlyCell) @@ -224,74 +189,54 @@ Structure::Structure(VM& vm) , m_classInfo(info()) , m_transitionWatchpointSet(IsWatched) , m_offset(invalidOffset) + , m_typeInfo(CompoundType, OverridesVisitChildren) + , m_indexingType(0) , m_inlineCapacity(0) - , m_bitField(0) -{ - setDictionaryKind(NoneDictionaryKind); - setIsPinnedPropertyTable(false); - setHasGetterSetterProperties(m_classInfo->hasStaticSetterOrReadonlyProperties()); - setHasCustomGetterSetterProperties(false); - setHasReadOnlyOrGetterSetterPropertiesExcludingProto(m_classInfo->hasStaticSetterOrReadonlyProperties()); - setHasNonEnumerableProperties(false); - setAttributesInPrevious(0); - setPreventExtensions(false); - setDidTransition(false); - setStaticFunctionsReified(false); - setHasRareData(false); - setTransitionWatchpointIsLikelyToBeFired(false); - - TypeInfo typeInfo = TypeInfo(CellType, StructureFlags); - m_blob = StructureIDBlob(vm.heap.structureIDTable().allocateID(this), 0, typeInfo); - m_outOfLineTypeFlags = typeInfo.outOfLineTypeFlags(); - - ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !m_classInfo->hasStaticSetterOrReadonlyProperties()); - ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties()); -} - -Structure::Structure(VM& vm, Structure* previous, DeferredStructureTransitionWatchpointFire* deferred) + , m_dictionaryKind(NoneDictionaryKind) + , m_isPinnedPropertyTable(false) + , m_hasGetterSetterProperties(m_classInfo->hasStaticSetterOrReadonlyProperties(vm)) + , m_hasReadOnlyOrGetterSetterPropertiesExcludingProto(m_classInfo->hasStaticSetterOrReadonlyProperties(vm)) + , m_hasNonEnumerableProperties(false) + , m_attributesInPrevious(0) + , m_specificFunctionThrashCount(0) + , m_preventExtensions(false) + , m_didTransition(false) + , m_staticFunctionReified(false) +{ + ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !m_classInfo->hasStaticSetterOrReadonlyProperties(vm)); + ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties(vm)); +} + +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(IsWatched) , m_offset(invalidOffset) + , m_typeInfo(previous->typeInfo().type(), previous->typeInfo().flags() & ~StructureHasRareData) + , m_indexingType(previous->indexingTypeIncludingHistory()) , m_inlineCapacity(previous->m_inlineCapacity) - , m_bitField(0) -{ - setDictionaryKind(previous->dictionaryKind()); - setIsPinnedPropertyTable(previous->hasBeenFlattenedBefore()); - setHasGetterSetterProperties(previous->hasGetterSetterProperties()); - setHasCustomGetterSetterProperties(previous->hasCustomGetterSetterProperties()); - setHasReadOnlyOrGetterSetterPropertiesExcludingProto(previous->hasReadOnlyOrGetterSetterPropertiesExcludingProto()); - setHasNonEnumerableProperties(previous->hasNonEnumerableProperties()); - setAttributesInPrevious(0); - setPreventExtensions(previous->preventExtensions()); - setDidTransition(true); - setStaticFunctionsReified(previous->staticFunctionsReified()); - setHasRareData(false); - - TypeInfo typeInfo = previous->typeInfo(); - m_blob = StructureIDBlob(vm.heap.structureIDTable().allocateID(this), previous->indexingTypeIncludingHistory(), typeInfo); - m_outOfLineTypeFlags = typeInfo.outOfLineTypeFlags(); - - ASSERT(!previous->typeInfo().structureIsImmortal()); - setPreviousID(vm, previous); - - previous->didTransitionFromThisStructure(deferred); - - // Copy this bit now, in case previous was being watched. - setTransitionWatchpointIsLikelyToBeFired(previous->transitionWatchpointIsLikelyToBeFired()); - + , m_dictionaryKind(previous->m_dictionaryKind) + , m_isPinnedPropertyTable(false) + , m_hasGetterSetterProperties(previous->m_hasGetterSetterProperties) + , m_hasReadOnlyOrGetterSetterPropertiesExcludingProto(previous->m_hasReadOnlyOrGetterSetterPropertiesExcludingProto) + , m_hasNonEnumerableProperties(previous->m_hasNonEnumerableProperties) + , m_attributesInPrevious(0) + , m_specificFunctionThrashCount(previous->m_specificFunctionThrashCount) + , m_preventExtensions(previous->m_preventExtensions) + , 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(vm, this, previous->m_globalObject.get()); - ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !m_classInfo->hasStaticSetterOrReadonlyProperties()); - ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties()); -} - -Structure::~Structure() -{ - if (typeInfo().structureIsImmortal()) - return; - Heap::heap(this)->structureIDTable().deallocateID(this, m_blob.structureID()); + ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !m_classInfo->hasStaticSetterOrReadonlyProperties(vm)); + ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties(vm)); } void Structure::destroy(JSCell* cell) @@ -334,7 +279,7 @@ void Structure::materializePropertyMap(VM& vm) findStructuresAndMapForMaterialization(structures, structure, table); if (table) { - table = table->copy(vm, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity)); + table = table->copy(vm, structure, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity)); structure->m_lock.unlock(); } @@ -351,19 +296,49 @@ void Structure::materializePropertyMap(VM& vm) structure = structures[i]; if (!structure->m_nameInPrevious) continue; - PropertyMapEntry entry(structure->m_nameInPrevious.get(), structure->m_offset, structure->attributesInPrevious()); + 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(); } -Structure* Structure::addPropertyTransitionToExistingStructureImpl(Structure* structure, UniquedStringImpl* uid, unsigned attributes, PropertyOffset& offset) +inline size_t nextOutOfLineStorageCapacity(size_t currentCapacity) +{ + if (!currentCapacity) + return initialOutOfLineCapacity; + return currentCapacity * outOfLineGrowthFactor; +} + +size_t Structure::suggestedNewOutOfLineStorageCapacity() +{ + return nextOutOfLineStorageCapacity(outOfLineCapacity()); +} + +void Structure::despecifyDictionaryFunction(VM& vm, PropertyName propertyName) +{ + StringImpl* rep = propertyName.uid(); + + DeferGC deferGC(vm.heap); + materializePropertyMapIfNecessary(vm, deferGC); + + ASSERT(isDictionary()); + ASSERT(propertyTable()); + + PropertyMapEntry* entry = propertyTable()->find(rep).first; + ASSERT(entry); + entry->specificValue.clear(); +} + +Structure* Structure::addPropertyTransitionToExistingStructureImpl(Structure* structure, StringImpl* uid, unsigned attributes, JSCell* specificValue, PropertyOffset& offset) { ASSERT(!structure->isDictionary()); ASSERT(structure->isObject()); if (Structure* existingTransition = structure->m_transitionTable.get(uid, attributes)) { + JSCell* specificValueInPrevious = existingTransition->m_specificValueInPrevious.get(); + if (specificValueInPrevious && specificValueInPrevious != specificValue) + return 0; validateOffset(existingTransition->m_offset, existingTransition->inlineCapacity()); offset = existingTransition->m_offset; return existingTransition; @@ -372,16 +347,16 @@ Structure* Structure::addPropertyTransitionToExistingStructureImpl(Structure* st return 0; } -Structure* Structure::addPropertyTransitionToExistingStructure(Structure* structure, PropertyName propertyName, unsigned attributes, PropertyOffset& offset) +Structure* Structure::addPropertyTransitionToExistingStructure(Structure* structure, PropertyName propertyName, unsigned attributes, JSCell* specificValue, PropertyOffset& offset) { ASSERT(!isCompilationThread()); - return addPropertyTransitionToExistingStructureImpl(structure, propertyName.uid(), attributes, offset); + return addPropertyTransitionToExistingStructureImpl(structure, propertyName.uid(), attributes, specificValue, offset); } -Structure* Structure::addPropertyTransitionToExistingStructureConcurrently(Structure* structure, UniquedStringImpl* uid, unsigned attributes, PropertyOffset& offset) +Structure* Structure::addPropertyTransitionToExistingStructureConcurrently(Structure* structure, StringImpl* uid, unsigned attributes, JSCell* specificValue, PropertyOffset& offset) { ConcurrentJITLocker locker(structure->m_lock); - return addPropertyTransitionToExistingStructureImpl(structure, uid, attributes, offset); + return addPropertyTransitionToExistingStructureImpl(structure, uid, attributes, specificValue, offset); } bool Structure::anyObjectInChainMayInterceptIndexedAccesses() const @@ -398,30 +373,6 @@ bool Structure::anyObjectInChainMayInterceptIndexedAccesses() const } } -bool Structure::holesMustForwardToPrototype(VM& vm) const -{ - if (this->mayInterceptIndexedAccesses()) - return true; - - JSValue prototype = this->storedPrototype(); - if (!prototype.isObject()) - return false; - JSObject* object = asObject(prototype); - - while (true) { - Structure& structure = *object->structure(vm); - if (hasIndexedProperties(object->indexingType()) || structure.mayInterceptIndexedAccesses()) - return true; - prototype = structure.storedPrototype(); - if (!prototype.isObject()) - return false; - object = asObject(prototype); - } - - RELEASE_ASSERT_NOT_REACHED(); - return false; -} - bool Structure::needsSlowPutIndexing() const { return anyObjectInChainMayInterceptIndexedAccesses() @@ -436,33 +387,48 @@ NonPropertyTransition Structure::suggestedArrayStorageTransition() const return AllocateArrayStorage; } -Structure* Structure::addPropertyTransition(VM& vm, Structure* structure, PropertyName propertyName, unsigned attributes, PropertyOffset& offset, PutPropertySlot::Context context, DeferredStructureTransitionWatchpointFire* deferred) +Structure* Structure::addPropertyTransition(VM& vm, Structure* structure, PropertyName propertyName, unsigned attributes, JSCell* specificValue, PropertyOffset& offset, PutPropertySlot::Context context) { + // If we have a specific function, we may have got to this point if there is + // already a transition with the correct property name and attributes, but + // specialized to a different function. In this case we just want to give up + // and despecialize the transition. + // In this case we clear the value of specificFunction which will result + // in us adding a non-specific transition, and any subsequent lookup in + // Structure::addPropertyTransitionToExistingStructure will just use that. + if (specificValue && structure->m_transitionTable.contains(propertyName.uid(), attributes)) + specificValue = 0; + ASSERT(!structure->isDictionary()); ASSERT(structure->isObject()); - ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, offset)); + ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, specificValue, offset)); + if (structure->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount) + specificValue = 0; + int maxTransitionLength; if (context == PutPropertySlot::PutById) maxTransitionLength = s_maxTransitionLengthForNonEvalPutById; else maxTransitionLength = s_maxTransitionLength; if (structure->transitionCount() > maxTransitionLength) { - Structure* transition = toCacheableDictionaryTransition(vm, structure, deferred); + Structure* transition = toCacheableDictionaryTransition(vm, structure); ASSERT(structure != transition); - offset = transition->add(vm, propertyName, attributes); + offset = transition->putSpecificValue(vm, propertyName, attributes, specificValue); return transition; } - Structure* transition = create(vm, structure, deferred); + Structure* transition = create(vm, structure); transition->m_cachedPrototypeChain.setMayBeNull(vm, transition, structure->m_cachedPrototypeChain.get()); + transition->setPreviousID(vm, transition, structure); transition->m_nameInPrevious = propertyName.uid(); - transition->setAttributesInPrevious(attributes); - transition->propertyTable().set(vm, transition, structure->takePropertyTableOrCloneIfPinned(vm)); + transition->m_attributesInPrevious = attributes; + transition->m_specificValueInPrevious.setMayBeNull(vm, transition, specificValue); + transition->propertyTable().set(vm, transition, structure->takePropertyTableOrCloneIfPinned(vm, transition)); transition->m_offset = structure->m_offset; - offset = transition->add(vm, propertyName, attributes); + offset = transition->putSpecificValue(vm, propertyName, attributes, specificValue); checkOffset(transition->m_offset, transition->inlineCapacity()); { @@ -494,10 +460,34 @@ Structure* Structure::changePrototypeTransition(VM& vm, Structure* structure, JS DeferGC deferGC(vm.heap); structure->materializePropertyMapIfNecessary(vm, deferGC); - transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(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(VM& vm, Structure* structure, PropertyName replaceFunction) +{ + ASSERT(structure->m_specificFunctionThrashCount < maxSpecificFunctionThrashCount); + Structure* transition = create(vm, structure); + + ++transition->m_specificFunctionThrashCount; + + DeferGC deferGC(vm.heap); + structure->materializePropertyMapIfNecessary(vm, deferGC); + transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition)); transition->m_offset = structure->m_offset; transition->pin(); + if (transition->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount) + transition->despecifyAllFunctions(vm); + else { + bool removed = transition->despecifyFunction(vm, replaceFunction); + ASSERT_UNUSED(removed, removed); + } + transition->checkOffsetConsistency(); return transition; } @@ -509,7 +499,7 @@ Structure* Structure::attributeChangeTransition(VM& vm, Structure* structure, Pr Structure* transition = create(vm, structure); structure->materializePropertyMapIfNecessary(vm, deferGC); - transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm)); + transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition)); transition->m_offset = structure->m_offset; transition->pin(); @@ -517,7 +507,7 @@ Structure* Structure::attributeChangeTransition(VM& vm, Structure* structure, Pr } ASSERT(structure->propertyTable()); - PropertyMapEntry* entry = structure->propertyTable()->get(propertyName.uid()); + PropertyMapEntry* entry = structure->propertyTable()->find(propertyName.uid()).first; ASSERT(entry); entry->attributes = attributes; @@ -525,27 +515,26 @@ Structure* Structure::attributeChangeTransition(VM& vm, Structure* structure, Pr return structure; } -Structure* Structure::toDictionaryTransition(VM& vm, Structure* structure, DictionaryKind kind, DeferredStructureTransitionWatchpointFire* deferred) +Structure* Structure::toDictionaryTransition(VM& vm, Structure* structure, DictionaryKind kind) { ASSERT(!structure->isUncacheableDictionary()); - Structure* transition = create(vm, structure, deferred); + Structure* transition = create(vm, structure); DeferGC deferGC(vm.heap); structure->materializePropertyMapIfNecessary(vm, deferGC); - transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm)); + transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition)); transition->m_offset = structure->m_offset; - transition->setDictionaryKind(kind); + transition->m_dictionaryKind = kind; transition->pin(); - transition->setTransitionWatchpointIsLikelyToBeFired(true); transition->checkOffsetConsistency(); return transition; } -Structure* Structure::toCacheableDictionaryTransition(VM& vm, Structure* structure, DeferredStructureTransitionWatchpointFire* deferred) +Structure* Structure::toCacheableDictionaryTransition(VM& vm, Structure* structure) { - return toDictionaryTransition(vm, structure, CachedDictionaryKind, deferred); + return toDictionaryTransition(vm, structure, CachedDictionaryKind); } Structure* Structure::toUncacheableDictionaryTransition(VM& vm, Structure* structure) @@ -577,13 +566,13 @@ Structure* Structure::freezeTransition(VM& vm, Structure* structure) PropertyTable::iterator iter = transition->propertyTable()->begin(); PropertyTable::iterator end = transition->propertyTable()->end(); if (iter != end) - transition->setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true); + transition->m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true; for (; iter != end; ++iter) iter->attributes |= iter->attributes & Accessor ? DontDelete : (DontDelete | ReadOnly); } - ASSERT(transition->hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !transition->classInfo()->hasStaticSetterOrReadonlyProperties()); - ASSERT(transition->hasGetterSetterProperties() || !transition->classInfo()->hasStaticSetterOrReadonlyProperties()); + ASSERT(transition->hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !transition->classInfo()->hasStaticSetterOrReadonlyProperties(vm)); + ASSERT(transition->hasGetterSetterProperties() || !transition->classInfo()->hasStaticSetterOrReadonlyProperties(vm)); transition->checkOffsetConsistency(); return transition; } @@ -597,22 +586,22 @@ Structure* Structure::preventExtensionsTransition(VM& vm, Structure* structure) DeferGC deferGC(vm.heap); structure->materializePropertyMapIfNecessary(vm, deferGC); - transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm)); + transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition)); transition->m_offset = structure->m_offset; - transition->setPreventExtensions(true); + transition->m_preventExtensions = true; transition->pin(); transition->checkOffsetConsistency(); return transition; } -PropertyTable* Structure::takePropertyTableOrCloneIfPinned(VM& vm) +PropertyTable* Structure::takePropertyTableOrCloneIfPinned(VM& vm, Structure* owner) { DeferGC deferGC(vm.heap); materializePropertyMapIfNecessaryForPinning(vm, deferGC); - if (isPinnedPropertyTable()) - return propertyTable()->copy(vm, propertyTable()->size() + 1); + if (m_isPinnedPropertyTable) + return propertyTable()->copy(vm, owner, propertyTable()->size() + 1); // Hold the lock while stealing the table - so that getConcurrently() on another thread // will either have to bypass this structure, or will get to use the property table @@ -632,29 +621,27 @@ Structure* Structure::nonPropertyTransition(VM& vm, Structure* structure, NonPro if (globalObject->isOriginalArrayStructure(structure)) { Structure* result = globalObject->originalArrayStructureForIndexingType(indexingType); if (result->indexingTypeIncludingHistory() == indexingType) { - structure->didTransitionFromThisStructure(); + structure->notifyTransitionFromThisStructure(); return result; } } } - Structure* existingTransition; - if (!structure->isDictionary() && (existingTransition = structure->m_transitionTable.get(0, attributes))) { - ASSERT(existingTransition->attributesInPrevious() == attributes); + if (Structure* existingTransition = structure->m_transitionTable.get(0, attributes)) { + ASSERT(existingTransition->m_attributesInPrevious == attributes); ASSERT(existingTransition->indexingTypeIncludingHistory() == indexingType); return existingTransition; } Structure* transition = create(vm, structure); - transition->setAttributesInPrevious(attributes); - transition->m_blob.setIndexingType(indexingType); - transition->propertyTable().set(vm, transition, structure->takePropertyTableOrCloneIfPinned(vm)); + 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->isDictionary()) - transition->pin(); - else { + { ConcurrentJITLocker locker(structure->m_lock); structure->m_transitionTable.add(vm, transition); } @@ -706,8 +693,6 @@ Structure* Structure::flattenDictionaryStructure(VM& vm, JSObject* object) { checkOffsetConsistency(); ASSERT(isDictionary()); - - size_t beforeOutOfLineCapacity = this->outOfLineCapacity(); if (isUncacheableDictionary()) { ASSERT(propertyTable()); @@ -733,40 +718,35 @@ Structure* Structure::flattenDictionaryStructure(VM& vm, JSObject* object) checkOffsetConsistency(); } - setDictionaryKind(NoneDictionaryKind); - setHasBeenFlattenedBefore(true); - - size_t afterOutOfLineCapacity = this->outOfLineCapacity(); - - if (beforeOutOfLineCapacity != afterOutOfLineCapacity) { - ASSERT(beforeOutOfLineCapacity > afterOutOfLineCapacity); - // If the object had a Butterfly but after flattening/compacting we no longer have need of it, - // we need to zero it out because the collector depends on the Structure to know the size for copying. - if (object->butterfly() && !afterOutOfLineCapacity && !this->hasIndexingHeader(object)) - object->setStructureAndButterfly(vm, this, 0); - // If the object was down-sized to the point where the base of the Butterfly is no longer within the - // first CopiedBlock::blockSize bytes, we'll get the wrong answer if we try to mask the base back to - // the CopiedBlock header. To prevent this case we need to memmove the Butterfly down. - else if (object->butterfly()) - object->shiftButterflyAfterFlattening(vm, beforeOutOfLineCapacity, afterOutOfLineCapacity); - } + m_dictionaryKind = NoneDictionaryKind; + + // If the object had a Butterfly but after flattening/compacting we no longer have need of it, + // we need to zero it out because the collector depends on the Structure to know the size for copying. + if (object->butterfly() && !this->outOfLineCapacity() && !this->hasIndexingHeader(object)) + object->setStructureAndButterfly(vm, this, 0); return this; } -PropertyOffset Structure::addPropertyWithoutTransition(VM& vm, PropertyName propertyName, unsigned attributes) +PropertyOffset Structure::addPropertyWithoutTransition(VM& vm, PropertyName propertyName, unsigned attributes, JSCell* specificValue) { + ASSERT(!enumerationCache()); + + if (m_specificFunctionThrashCount == maxSpecificFunctionThrashCount) + specificValue = 0; + DeferGC deferGC(vm.heap); materializePropertyMapIfNecessaryForPinning(vm, deferGC); pin(); - return add(vm, propertyName, attributes); + return putSpecificValue(vm, propertyName, attributes, specificValue); } PropertyOffset Structure::removePropertyWithoutTransition(VM& vm, PropertyName propertyName) { ASSERT(isUncacheableDictionary()); + ASSERT(!enumerationCache()); DeferGC deferGC(vm.heap); materializePropertyMapIfNecessaryForPinning(vm, deferGC); @@ -778,144 +758,150 @@ PropertyOffset Structure::removePropertyWithoutTransition(VM& vm, PropertyName p void Structure::pin() { ASSERT(propertyTable()); - setIsPinnedPropertyTable(true); + m_isPinnedPropertyTable = true; clearPreviousID(); - m_nameInPrevious = nullptr; + m_nameInPrevious.clear(); } void Structure::allocateRareData(VM& vm) { - ASSERT(!hasRareData()); + ASSERT(!typeInfo().structureHasRareData()); StructureRareData* rareData = StructureRareData::create(vm, previous()); - WTF::storeStoreFence(); + m_typeInfo = TypeInfo(typeInfo().type(), typeInfo().flags() | StructureHasRareData); m_previousOrRareData.set(vm, this, rareData); - WTF::storeStoreFence(); - setHasRareData(true); - ASSERT(hasRareData()); } -WatchpointSet* Structure::ensurePropertyReplacementWatchpointSet(VM& vm, PropertyOffset offset) +void Structure::cloneRareDataFrom(VM& vm, const Structure* other) { - ASSERT(!isUncacheableDictionary()); - - // In some places it's convenient to call this with an invalid offset. So, we do the check here. - if (!isValidOffset(offset)) - return nullptr; - - if (!hasRareData()) - allocateRareData(vm); - ConcurrentJITLocker locker(m_lock); - StructureRareData* rareData = this->rareData(); - if (!rareData->m_replacementWatchpointSets) { - rareData->m_replacementWatchpointSets = - std::make_unique<StructureRareData::PropertyWatchpointMap>(); - WTF::storeStoreFence(); - } - auto result = rareData->m_replacementWatchpointSets->add(offset, nullptr); - if (result.isNewEntry) - result.iterator->value = adoptRef(new WatchpointSet(IsWatched)); - return result.iterator->value.get(); -} - -void Structure::startWatchingPropertyForReplacements(VM& vm, PropertyName propertyName) -{ - ASSERT(!isUncacheableDictionary()); - - startWatchingPropertyForReplacements(vm, get(vm, propertyName)); -} - -void Structure::didCachePropertyReplacement(VM& vm, PropertyOffset offset) -{ - ensurePropertyReplacementWatchpointSet(vm, offset)->fireAll("Did cache property replacement"); -} - -void Structure::startWatchingInternalProperties(VM& vm) -{ - if (!isUncacheableDictionary()) { - startWatchingPropertyForReplacements(vm, vm.propertyNames->toString); - startWatchingPropertyForReplacements(vm, vm.propertyNames->valueOf); - } - setDidWatchInternalProperties(true); + 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 -PropertyMapHashTableStats* propertyMapHashTableStats = 0; - struct PropertyMapStatisticsExitLogger { - PropertyMapStatisticsExitLogger(); ~PropertyMapStatisticsExitLogger(); }; -DEFINE_GLOBAL_FOR_LOGGING(PropertyMapStatisticsExitLogger, logger, ); +static PropertyMapStatisticsExitLogger logger; -PropertyMapStatisticsExitLogger::PropertyMapStatisticsExitLogger() +PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger() { - propertyMapHashTableStats = adoptPtr(new PropertyMapHashTableStats()).leakPtr(); + dataLogF("\nJSC::PropertyMap statistics\n\n"); + dataLogF("%d probes\n", numProbes); + dataLogF("%d collisions (%.1f%%)\n", numCollisions, 100.0 * numCollisions / numProbes); + dataLogF("%d rehashes\n", numRehashes); + dataLogF("%d removes\n", numRemoves); } -PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger() +#endif + +#if !DO_PROPERTYMAP_CONSTENCY_CHECK + +inline void Structure::checkConsistency() { - unsigned finds = propertyMapHashTableStats->numFinds; - unsigned collisions = propertyMapHashTableStats->numCollisions; - dataLogF("\nJSC::PropertyMap statistics for process %d\n\n", getCurrentProcessID()); - dataLogF("%d finds\n", finds); - dataLogF("%d collisions (%.1f%%)\n", collisions, 100.0 * collisions / finds); - dataLogF("%d lookups\n", propertyMapHashTableStats->numLookups.load()); - dataLogF("%d lookup probings\n", propertyMapHashTableStats->numLookupProbing.load()); - dataLogF("%d adds\n", propertyMapHashTableStats->numAdds.load()); - dataLogF("%d removes\n", propertyMapHashTableStats->numRemoves.load()); - dataLogF("%d rehashes\n", propertyMapHashTableStats->numRehashes.load()); - dataLogF("%d reinserts\n", propertyMapHashTableStats->numReinserts.load()); + checkOffsetConsistency(); } #endif -PropertyTable* Structure::copyPropertyTable(VM& vm) +PropertyTable* Structure::copyPropertyTable(VM& vm, Structure* owner) { if (!propertyTable()) return 0; - return PropertyTable::clone(vm, *propertyTable().get()); + return PropertyTable::clone(vm, owner, *propertyTable().get()); } -PropertyTable* Structure::copyPropertyTableForPinning(VM& vm) +PropertyTable* Structure::copyPropertyTableForPinning(VM& vm, Structure* owner) { if (propertyTable()) - return PropertyTable::clone(vm, *propertyTable().get()); + return PropertyTable::clone(vm, owner, *propertyTable().get()); return PropertyTable::create(vm, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity)); } -PropertyOffset Structure::getConcurrently(UniquedStringImpl* uid, unsigned& attributes) +PropertyOffset Structure::getConcurrently(VM&, StringImpl* uid, unsigned& attributes, JSCell*& specificValue) { - PropertyOffset result = invalidOffset; + Vector<Structure*, 8> structures; + Structure* structure; + PropertyTable* table; - forEachPropertyConcurrently( - [&] (const PropertyMapEntry& candidate) -> bool { - if (candidate.key != uid) - return true; - - result = candidate.offset; - attributes = candidate.attributes; - return false; - }); + findStructuresAndMapForMaterialization(structures, structure, table); - return result; + if (table) { + PropertyMapEntry* entry = table->find(uid).first; + if (entry) { + attributes = entry->attributes; + specificValue = entry->specificValue.get(); + PropertyOffset result = entry->offset; + structure->m_lock.unlock(); + return result; + } + structure->m_lock.unlock(); + } + + for (unsigned i = structures.size(); i--;) { + structure = structures[i]; + if (structure->m_nameInPrevious.get() != uid) + continue; + + attributes = structure->m_attributesInPrevious; + specificValue = structure->m_specificValueInPrevious.get(); + return structure->m_offset; + } + + return invalidOffset; } -Vector<PropertyMapEntry> Structure::getPropertiesConcurrently() +PropertyOffset Structure::get(VM& vm, PropertyName propertyName, unsigned& attributes, JSCell*& specificValue) { - Vector<PropertyMapEntry> result; + ASSERT(!isCompilationThread()); + ASSERT(structure()->classInfo() == info()); - forEachPropertyConcurrently( - [&] (const PropertyMapEntry& entry) -> bool { - result.append(entry); - return true; - }); - - return result; + DeferGC deferGC(vm.heap); + materializePropertyMapIfNecessary(vm, deferGC); + if (!propertyTable()) + return invalidOffset; + + PropertyMapEntry* entry = propertyTable()->find(propertyName.uid()).first; + if (!entry) + return invalidOffset; + + attributes = entry->attributes; + specificValue = entry->specificValue.get(); + return entry->offset; +} + +bool Structure::despecifyFunction(VM& vm, PropertyName propertyName) +{ + DeferGC deferGC(vm.heap); + materializePropertyMapIfNecessary(vm, deferGC); + if (!propertyTable()) + return false; + + PropertyMapEntry* entry = propertyTable()->find(propertyName.uid()).first; + if (!entry) + return false; + + ASSERT(entry->specificValue); + entry->specificValue.clear(); + return true; } -PropertyOffset Structure::add(VM& vm, PropertyName propertyName, unsigned attributes) +void Structure::despecifyAllFunctions(VM& vm) +{ + DeferGC deferGC(vm.heap); + materializePropertyMapIfNecessary(vm, deferGC); + if (!propertyTable()) + return; + + PropertyTable::iterator end = propertyTable()->end(); + for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) + iter->specificValue.clear(); +} + +PropertyOffset Structure::putSpecificValue(VM& vm, PropertyName propertyName, unsigned attributes, JSCell* specificValue) { GCSafeConcurrentJITLocker locker(m_lock, vm.heap); @@ -923,16 +909,16 @@ PropertyOffset Structure::add(VM& vm, PropertyName propertyName, unsigned attrib checkConsistency(); if (attributes & DontEnum) - setHasNonEnumerableProperties(true); + m_hasNonEnumerableProperties = true; - auto rep = propertyName.uid(); + StringImpl* rep = propertyName.uid(); if (!propertyTable()) createPropertyMap(locker, vm); PropertyOffset newOffset = propertyTable()->nextOffset(m_inlineCapacity); - propertyTable()->add(PropertyMapEntry(rep, newOffset, attributes), m_offset, PropertyTable::PropertyOffsetMayChange); + propertyTable()->add(PropertyMapEntry(vm, this, rep, newOffset, attributes, specificValue), m_offset, PropertyTable::PropertyOffsetMayChange); checkConsistency(); return newOffset; @@ -944,7 +930,7 @@ PropertyOffset Structure::remove(PropertyName propertyName) checkConsistency(); - auto rep = propertyName.uid(); + StringImpl* rep = propertyName.uid(); if (!propertyTable()) return invalidOffset; @@ -977,14 +963,12 @@ void Structure::getPropertyNamesFromStructure(VM& vm, PropertyNameArray& propert if (!propertyTable()) return; - bool knownUnique = propertyNames.canAddKnownUniqueForStructure(); + bool knownUnique = !propertyNames.size(); PropertyTable::iterator end = propertyTable()->end(); for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) { - ASSERT(hasNonEnumerableProperties() || !(iter->attributes & DontEnum)); - if (!(iter->attributes & DontEnum) || mode.includeDontEnumProperties()) { - if (iter->key->isSymbol() && !propertyNames.includeSymbolProperties()) - continue; + ASSERT(m_hasNonEnumerableProperties || !(iter->attributes & DontEnum)); + if (iter->key->isIdentifier() && (!(iter->attributes & DontEnum) || mode == IncludeDontEnumProperties)) { if (knownUnique) propertyNames.addKnownUnique(iter->key); else @@ -993,43 +977,6 @@ void Structure::getPropertyNamesFromStructure(VM& vm, PropertyNameArray& propert } } -void StructureFireDetail::dump(PrintStream& out) const -{ - out.print("Structure transition from ", *m_structure); -} - -DeferredStructureTransitionWatchpointFire::DeferredStructureTransitionWatchpointFire() - : m_structure(nullptr) -{ -} - -DeferredStructureTransitionWatchpointFire::~DeferredStructureTransitionWatchpointFire() -{ - if (m_structure) - m_structure->transitionWatchpointSet().fireAll(StructureFireDetail(m_structure)); -} - -void DeferredStructureTransitionWatchpointFire::add(const Structure* structure) -{ - RELEASE_ASSERT(!m_structure); - RELEASE_ASSERT(structure); - m_structure = structure; -} - -void Structure::didTransitionFromThisStructure(DeferredStructureTransitionWatchpointFire* deferred) const -{ - // If the structure is being watched, and this is the kind of structure that the DFG would - // like to watch, then make sure to note for all future versions of this structure that it's - // unwise to watch it. - if (m_transitionWatchpointSet.isBeingWatched()) - const_cast<Structure*>(this)->setTransitionWatchpointIsLikelyToBeFired(true); - - if (deferred) - deferred->add(this); - else - m_transitionWatchpointSet.fireAll(StructureFireDetail(this)); -} - JSValue Structure::prototypeForLookup(CodeBlock* codeBlock) const { return prototypeForLookup(codeBlock->globalObject()); @@ -1039,6 +986,7 @@ void Structure::visitChildren(JSCell* cell, SlotVisitor& visitor) { Structure* thisObject = jsCast<Structure*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); JSCell::visitChildren(thisObject, visitor); visitor.append(&thisObject->m_globalObject); @@ -1049,8 +997,9 @@ void Structure::visitChildren(JSCell* cell, SlotVisitor& visitor) visitor.append(&thisObject->m_cachedPrototypeChain); } visitor.append(&thisObject->m_previousOrRareData); + visitor.append(&thisObject->m_specificValueInPrevious); - if (thisObject->isPinnedPropertyTable()) { + if (thisObject->m_isPinnedPropertyTable) { ASSERT(thisObject->m_propertyTableUnsafe); visitor.append(&thisObject->m_propertyTableUnsafe); } else if (thisObject->m_propertyTableUnsafe) @@ -1059,7 +1008,8 @@ void Structure::visitChildren(JSCell* cell, SlotVisitor& visitor) bool Structure::prototypeChainMayInterceptStoreTo(VM& vm, PropertyName propertyName) { - if (parseIndex(propertyName)) + unsigned i = propertyName.asIndex(); + if (i != PropertyName::NotAnIndex) return anyObjectInChainMayInterceptIndexedAccesses(); for (Structure* current = this; ;) { @@ -1067,10 +1017,11 @@ bool Structure::prototypeChainMayInterceptStoreTo(VM& vm, PropertyName propertyN if (prototype.isNull()) return false; - current = prototype.asCell()->structure(vm); + current = prototype.asCell()->structure(); unsigned attributes; - PropertyOffset offset = current->get(vm, propertyName, attributes); + JSCell* specificValue; + PropertyOffset offset = current->get(vm, propertyName, attributes, specificValue); if (!JSC::isValidOffset(offset)) continue; @@ -1081,89 +1032,39 @@ bool Structure::prototypeChainMayInterceptStoreTo(VM& vm, PropertyName propertyN } } -PassRefPtr<StructureShape> Structure::toStructureShape(JSValue value) -{ - RefPtr<StructureShape> baseShape = StructureShape::create(); - RefPtr<StructureShape> curShape = baseShape; - Structure* curStructure = this; - JSValue curValue = value; - while (curStructure) { - Vector<Structure*, 8> structures; - Structure* structure; - PropertyTable* table; - - curStructure->findStructuresAndMapForMaterialization(structures, structure, table); - if (table) { - PropertyTable::iterator iter = table->begin(); - PropertyTable::iterator end = table->end(); - for (; iter != end; ++iter) - curShape->addProperty(*iter->key); - - structure->m_lock.unlock(); - } - for (unsigned i = structures.size(); i--;) { - Structure* structure = structures[i]; - if (structure->m_nameInPrevious) - curShape->addProperty(*structure->m_nameInPrevious); - } - - if (JSObject* curObject = curValue.getObject()) - curShape->setConstructorName(JSObject::calculatedClassName(curObject)); - else - curShape->setConstructorName(curStructure->classInfo()->className); - - if (curStructure->isDictionary()) - curShape->enterDictionaryMode(); - - curShape->markAsFinal(); - - if (curStructure->storedPrototypeStructure()) { - RefPtr<StructureShape> newShape = StructureShape::create(); - curShape->setProto(newShape); - curShape = newShape.release(); - curValue = curStructure->storedPrototype(); - } - - curStructure = curStructure->storedPrototypeStructure(); - } - - return baseShape.release(); -} - -bool Structure::canUseForAllocationsOf(Structure* other) -{ - return inlineCapacity() == other->inlineCapacity() - && storedPrototype() == other->storedPrototype() - && objectInitializationBlob() == other->objectInitializationBlob(); -} - void Structure::dump(PrintStream& out) const { out.print(RawPointer(this), ":[", classInfo()->className, ", {"); + Vector<Structure*, 8> structures; + Structure* structure; + PropertyTable* table; + + const_cast<Structure*>(this)->findStructuresAndMapForMaterialization( + structures, structure, table); + CommaPrinter comma; - const_cast<Structure*>(this)->forEachPropertyConcurrently( - [&] (const PropertyMapEntry& entry) -> bool { - out.print(comma, entry.key, ":", static_cast<int>(entry.offset)); - return true; - }); + if (table) { + PropertyTable::iterator iter = table->begin(); + PropertyTable::iterator end = table->end(); + for (; iter != end; ++iter) + out.print(comma, iter->key, ":", static_cast<int>(iter->offset)); + + structure->m_lock.unlock(); + } + + for (unsigned i = structures.size(); i--;) { + Structure* structure = structures[i]; + if (!structure->m_nameInPrevious) + continue; + out.print(comma, structure->m_nameInPrevious.get(), ":", static_cast<int>(structure->m_offset)); + } out.print("}, ", IndexingTypeDump(indexingType())); if (m_prototype.get().isCell()) out.print(", Proto:", RawPointer(m_prototype.get().asCell())); - - switch (dictionaryKind()) { - case NoneDictionaryKind: - break; - case CachedDictionaryKind: - out.print(", Dictionary"); - break; - case UncachedDictionaryKind: - out.print(", UncacheableDictionary"); - break; - } out.print("]"); } @@ -1190,6 +1091,7 @@ void Structure::dumpContextHeader(PrintStream& out) void PropertyTable::checkConsistency() { + checkOffsetConsistency(); ASSERT(m_indexSize >= PropertyTable::MinimumTableSize); ASSERT(m_indexMask); ASSERT(m_indexSize == m_indexMask + 1); @@ -1227,7 +1129,7 @@ void PropertyTable::checkConsistency() if (rep == PROPERTY_MAP_DELETED_ENTRY_KEY) continue; ++nonEmptyEntryCount; - unsigned i = IdentifierRepHash::hash(rep); + unsigned i = rep->existingHash(); unsigned k = 0; unsigned entryIndex; while (1) { @@ -1236,7 +1138,7 @@ void PropertyTable::checkConsistency() if (rep == table()[entryIndex - 1].key) break; if (k == 0) - k = 1 | doubleHash(IdentifierRepHash::hash(rep)); + k = 1 | doubleHash(rep->existingHash()); i += k; } ASSERT(entryIndex == c + 1); @@ -1247,12 +1149,10 @@ void PropertyTable::checkConsistency() void Structure::checkConsistency() { - checkOffsetConsistency(); - if (!propertyTable()) return; - if (!hasNonEnumerableProperties()) { + if (!m_hasNonEnumerableProperties) { PropertyTable::iterator end = propertyTable()->end(); for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) { ASSERT(!(iter->attributes & DontEnum)); @@ -1262,19 +1162,12 @@ void Structure::checkConsistency() propertyTable()->checkConsistency(); } -#else - -inline void Structure::checkConsistency() -{ - checkOffsetConsistency(); -} - #endif // DO_PROPERTYMAP_CONSTENCY_CHECK -bool ClassInfo::hasStaticSetterOrReadonlyProperties() const +bool ClassInfo::hasStaticSetterOrReadonlyProperties(VM& vm) const { for (const ClassInfo* ci = this; ci; ci = ci->parentClass) { - if (const HashTable* table = ci->staticPropHashTable) { + if (const HashTable* table = ci->propHashTable(vm)) { if (table->hasSetterOrReadonlyProperties) return true; } @@ -1282,55 +1175,4 @@ bool ClassInfo::hasStaticSetterOrReadonlyProperties() const return false; } -void Structure::setCachedPropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator) -{ - ASSERT(!isDictionary()); - if (!hasRareData()) - allocateRareData(vm); - rareData()->setCachedPropertyNameEnumerator(vm, enumerator); -} - -JSPropertyNameEnumerator* Structure::cachedPropertyNameEnumerator() const -{ - if (!hasRareData()) - return nullptr; - return rareData()->cachedPropertyNameEnumerator(); -} - -bool Structure::canCachePropertyNameEnumerator() const -{ - if (isDictionary()) - return false; - - if (hasIndexedProperties(indexingType())) - return false; - - if (typeInfo().overridesGetPropertyNames()) - return false; - - StructureChain* structureChain = m_cachedPrototypeChain.get(); - ASSERT(structureChain); - WriteBarrier<Structure>* structure = structureChain->head(); - while (true) { - if (!structure->get()) - break; - if (structure->get()->typeInfo().overridesGetPropertyNames()) - return false; - structure++; - } - - return true; -} - -bool Structure::canAccessPropertiesQuickly() const -{ - if (hasNonEnumerableProperties()) - return false; - if (hasGetterSetterProperties()) - return false; - if (isUncacheableDictionary()) - return false; - return true; -} - } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h index 22838c70d..c73e8cb96 100644 --- a/Source/JavaScriptCore/runtime/Structure.h +++ b/Source/JavaScriptCore/runtime/Structure.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2012-2015 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 @@ -10,10 +10,10 @@ * 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 + * 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 INC. OR + * 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 @@ -37,23 +37,17 @@ #include "PropertyOffset.h" #include "Protect.h" #include "PutPropertySlot.h" -#include "StructureIDBlob.h" #include "StructureRareData.h" #include "StructureTransitionTable.h" #include "JSTypeInfo.h" #include "Watchpoint.h" #include "Weak.h" -#include "WriteBarrierInlines.h" #include <wtf/CompilationThread.h> #include <wtf/PassRefPtr.h> #include <wtf/PrintStream.h> #include <wtf/RefCounted.h> +#include <wtf/text/StringImpl.h> -namespace WTF { - -class UniquedStringImpl; - -} // namespace WTF namespace JSC { @@ -63,7 +57,6 @@ class PropertyNameArray; class PropertyNameArrayData; class PropertyTable; class StructureChain; -class StructureShape; class SlotVisitor; class JSString; struct DumpContext; @@ -77,62 +70,14 @@ static const unsigned initialOutOfLineCapacity = 4; // initial allocation. static const unsigned outOfLineGrowthFactor = 2; -struct PropertyMapEntry { - UniquedStringImpl* key; - PropertyOffset offset; - unsigned attributes; - - PropertyMapEntry() - : key(nullptr) - , offset(invalidOffset) - , attributes(0) - { - } - - PropertyMapEntry(UniquedStringImpl* key, PropertyOffset offset, unsigned attributes) - : key(key) - , offset(offset) - , attributes(attributes) - { - } -}; - -class StructureFireDetail : public FireDetail { -public: - StructureFireDetail(const Structure* structure) - : m_structure(structure) - { - } - - virtual void dump(PrintStream& out) const override; - -private: - const Structure* m_structure; -}; - -class DeferredStructureTransitionWatchpointFire { - WTF_MAKE_NONCOPYABLE(DeferredStructureTransitionWatchpointFire); -public: - JS_EXPORT_PRIVATE DeferredStructureTransitionWatchpointFire(); - JS_EXPORT_PRIVATE ~DeferredStructureTransitionWatchpointFire(); - - void add(const Structure*); - -private: - const Structure* m_structure; -}; - -class Structure final : public JSCell { +class Structure : public JSCell { public: friend class StructureTransitionTable; typedef JSCell Base; - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; static Structure* create(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, unsigned inlineCapacity = 0); - ~Structure(); - protected: void finishCreation(VM& vm) { @@ -150,77 +95,59 @@ protected: } public: - StructureID id() const { return m_blob.structureID(); } - int32_t objectInitializationBlob() const { return m_blob.blobExcludingStructureID(); } - int64_t idBlob() const { return m_blob.blob(); } - - bool isProxy() const - { - JSType type = m_blob.type(); - return type == ImpureProxyType || type == PureForwardingProxyType; - } - static void dumpStatistics(); - JS_EXPORT_PRIVATE static Structure* addPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, PropertyOffset&, PutPropertySlot::Context = PutPropertySlot::UnknownContext, DeferredStructureTransitionWatchpointFire* = nullptr); - static Structure* addPropertyTransitionToExistingStructureConcurrently(Structure*, UniquedStringImpl* uid, unsigned attributes, PropertyOffset&); - JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, PropertyOffset&); + JS_EXPORT_PRIVATE static Structure* addPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&, PutPropertySlot::Context = PutPropertySlot::UnknownContext); + static Structure* addPropertyTransitionToExistingStructureConcurrently(Structure*, StringImpl* uid, 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* attributeChangeTransition(VM&, Structure*, PropertyName, unsigned attributes); - JS_EXPORT_PRIVATE static Structure* toCacheableDictionaryTransition(VM&, Structure*, DeferredStructureTransitionWatchpointFire* = nullptr); + 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*); - JS_EXPORT_PRIVATE static Structure* sealTransition(VM&, Structure*); - JS_EXPORT_PRIVATE static Structure* freezeTransition(VM&, Structure*); + static Structure* sealTransition(VM&, Structure*); + static Structure* freezeTransition(VM&, Structure*); static Structure* preventExtensionsTransition(VM&, Structure*); - JS_EXPORT_PRIVATE static Structure* nonPropertyTransition(VM&, Structure*, NonPropertyTransition); + static Structure* nonPropertyTransition(VM&, Structure*, NonPropertyTransition); - JS_EXPORT_PRIVATE bool isSealed(VM&); - JS_EXPORT_PRIVATE bool isFrozen(VM&); - bool isExtensible() const { return !preventExtensions(); } + bool isSealed(VM&); + bool isFrozen(VM&); + bool isExtensible() const { return !m_preventExtensions; } + bool didTransition() const { return m_didTransition; } bool putWillGrowOutOfLineStorage(); - size_t suggestedNewOutOfLineStorageCapacity(); + JS_EXPORT_PRIVATE size_t suggestedNewOutOfLineStorageCapacity(); - JS_EXPORT_PRIVATE Structure* flattenDictionaryStructure(VM&, JSObject*); + 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); + 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); } - bool isDictionary() const { return dictionaryKind() != NoneDictionaryKind; } - bool isUncacheableDictionary() const { return dictionaryKind() == UncachedDictionaryKind; } - - bool propertyAccessesAreCacheable() - { - return dictionaryKind() != UncachedDictionaryKind - && !typeInfo().prohibitsPropertyCaching() - && !(typeInfo().hasImpureGetOwnPropertySlot() && !typeInfo().newImpurePropertyFiresWatchpoints()); - } - - bool needImpurePropertyWatchpoint() - { - return propertyAccessesAreCacheable() - && typeInfo().hasImpureGetOwnPropertySlot() - && typeInfo().newImpurePropertyFiresWatchpoints(); - } + bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; } + bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; } + + bool propertyAccessesAreCacheable() { return m_dictionaryKind != UncachedDictionaryKind && !typeInfo().prohibitsPropertyCaching(); } // We use SlowPath in GetByIdStatus for structures that may get new impure properties later to prevent // DFG from inlining property accesses since structures don't transition when a new impure property appears. bool takesSlowPathInDFGForImpureProperty() { + ASSERT(!typeInfo().hasImpureGetOwnPropertySlot() || typeInfo().newImpurePropertyFiresWatchpoints()); return typeInfo().hasImpureGetOwnPropertySlot(); } - + // Type accessors. - TypeInfo typeInfo() const { ASSERT(structure()->classInfo() == info()); return m_blob.typeInfo(m_outOfLineTypeFlags); } + const TypeInfo& typeInfo() const { ASSERT(structure()->classInfo() == info()); return m_typeInfo; } bool isObject() const { return typeInfo().isObject(); } - IndexingType indexingType() const { return m_blob.indexingType() & AllArrayTypes; } - IndexingType indexingTypeIncludingHistory() const { return m_blob.indexingType(); } + IndexingType indexingType() const { return m_indexingType & AllArrayTypes; } + IndexingType indexingTypeIncludingHistory() const { return m_indexingType; } bool mayInterceptIndexedAccesses() const { @@ -228,7 +155,6 @@ public: } bool anyObjectInChainMayInterceptIndexedAccesses() const; - bool holesMustForwardToPrototype(VM&) const; bool needsSlowPutIndexing() const; NonPropertyTransition suggestedArrayStorageTransition() const; @@ -249,10 +175,12 @@ public: // Will just the prototype chain intercept this property access? bool prototypeChainMayInterceptStoreTo(VM&, PropertyName); + bool transitionDidInvolveSpecificValue() const { return !!m_specificValueInPrevious; } + Structure* previousID() const { ASSERT(structure()->classInfo() == info()); - if (hasRareData()) + if (typeInfo().structureHasRareData()) return rareData()->previousID(); return previous(); } @@ -321,70 +249,66 @@ public: bool masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject); PropertyOffset get(VM&, PropertyName); - PropertyOffset get(VM&, PropertyName, unsigned& attributes); - - // This is a somewhat internalish method. It will call your functor while possibly holding the - // Structure's lock. There is no guarantee whether the lock is held or not in any particular - // call. So, you have to assume the worst. Also, the functor returns true if it wishes for you - // to continue or false if it's done. - template<typename Functor> - void forEachPropertyConcurrently(const Functor&); - - PropertyOffset getConcurrently(UniquedStringImpl* uid); - PropertyOffset getConcurrently(UniquedStringImpl* uid, unsigned& attributes); - - Vector<PropertyMapEntry> getPropertiesConcurrently(); - - void setHasGetterSetterPropertiesWithProtoCheck(bool is__proto__) + PropertyOffset get(VM&, const WTF::String& name); + JS_EXPORT_PRIVATE PropertyOffset get(VM&, PropertyName, unsigned& attributes, JSCell*& specificValue); + + PropertyOffset getConcurrently(VM&, StringImpl* uid); + PropertyOffset getConcurrently(VM&, StringImpl* uid, unsigned& attributes, JSCell*& specificValue); + + bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; } + bool hasReadOnlyOrGetterSetterPropertiesExcludingProto() const { return m_hasReadOnlyOrGetterSetterPropertiesExcludingProto; } + void setHasGetterSetterProperties(bool is__proto__) { - setHasGetterSetterProperties(true); + m_hasGetterSetterProperties = true; if (!is__proto__) - setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true); + m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true; } - - void setContainsReadOnlyProperties() { setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true); } - - void setHasCustomGetterSetterPropertiesWithProtoCheck(bool is__proto__) + void setContainsReadOnlyProperties() { - setHasCustomGetterSetterProperties(true); - if (!is__proto__) - setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true); + m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true; } - + + bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; } + bool isEmpty() const { ASSERT(checkOffsetConsistency()); return !JSC::isValidOffset(m_offset); } - void setCachedPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*); - JSPropertyNameEnumerator* cachedPropertyNameEnumerator() const; - bool canCachePropertyNameEnumerator() const; - bool canAccessPropertiesQuickly() 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 (!hasRareData()) + if (!typeInfo().structureHasRareData()) return 0; return rareData()->objectToStringValue(); } - void setObjectToStringValue(VM& vm, JSString* value) + void setObjectToStringValue(VM& vm, const JSCell* owner, JSString* value) { - if (!hasRareData()) + if (!typeInfo().structureHasRareData()) allocateRareData(vm); - rareData()->setObjectToStringValue(vm, value); + rareData()->setObjectToStringValue(vm, owner, value); } - const ClassInfo* classInfo() const { return m_classInfo; } + bool staticFunctionsReified() + { + return m_staticFunctionReified; + } - static ptrdiff_t structureIDOffset() + void setStaticFunctionsReified() { - return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::structureIDOffset(); + m_staticFunctionReified = true; } + const ClassInfo* classInfo() const { return m_classInfo; } + static ptrdiff_t prototypeOffset() { return OBJECT_OFFSETOF(Structure, m_prototype); @@ -395,6 +319,16 @@ public: 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); @@ -402,7 +336,7 @@ public: static ptrdiff_t indexingTypeOffset() { - return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::indexingTypeOffset(); + return OBJECT_OFFSETOF(Structure, m_indexingType); } static Structure* createStructure(VM&); @@ -416,72 +350,23 @@ public: { return m_transitionWatchpointSet.isStillValid(); } - - bool dfgShouldWatchIfPossible() const - { - // FIXME: We would like to not watch things that are unprofitable to watch, like - // dictionaries. Unfortunately, we can't do such things: a dictionary could get flattened, - // in which case it will start to appear watchable and so the DFG will think that it is - // watching it. We should come up with a comprehensive story for not watching things that - // aren't profitable to watch. - // https://bugs.webkit.org/show_bug.cgi?id=133625 - - // - We don't watch Structures that either decided not to be watched, or whose predecessors - // decided not to be watched. This happens either when a transition is fired while being - // watched, or if a dictionary transition occurs. - if (transitionWatchpointIsLikelyToBeFired()) - return false; - - return true; - } - - bool dfgShouldWatch() const - { - return dfgShouldWatchIfPossible() && transitionWatchpointSetIsStillValid(); - } void addTransitionWatchpoint(Watchpoint* watchpoint) const { ASSERT(transitionWatchpointSetIsStillValid()); m_transitionWatchpointSet.add(watchpoint); } - - void didTransitionFromThisStructure(DeferredStructureTransitionWatchpointFire* = nullptr) const; - - InlineWatchpointSet& transitionWatchpointSet() const - { - return m_transitionWatchpointSet; - } - - WatchpointSet* ensurePropertyReplacementWatchpointSet(VM&, PropertyOffset); - void startWatchingPropertyForReplacements(VM& vm, PropertyOffset offset) + + void notifyTransitionFromThisStructure() const { - ensurePropertyReplacementWatchpointSet(vm, offset); + m_transitionWatchpointSet.fireAll(); } - void startWatchingPropertyForReplacements(VM&, PropertyName); - WatchpointSet* propertyReplacementWatchpointSet(PropertyOffset); - void didReplaceProperty(PropertyOffset); - void didCachePropertyReplacement(VM&, PropertyOffset); - void startWatchingInternalPropertiesIfNecessary(VM& vm) + InlineWatchpointSet& transitionWatchpointSet() const { - if (LIKELY(didWatchInternalProperties())) - return; - startWatchingInternalProperties(vm); + return m_transitionWatchpointSet; } - void startWatchingInternalPropertiesIfNecessaryForEntireChain(VM& vm) - { - for (Structure* structure = this; structure; structure = structure->storedPrototypeStructure()) - structure->startWatchingInternalPropertiesIfNecessary(vm); - } - - PassRefPtr<StructureShape> toStructureShape(JSValue); - - // Determines if the two structures match enough that this one could be used for allocations - // of the other one. - bool canUseForAllocationsOf(Structure*); - void dump(PrintStream&) const; void dumpInContext(PrintStream&, DumpContext*) const; void dumpBrief(PrintStream&, const CString&) const; @@ -491,48 +376,15 @@ public: DECLARE_EXPORT_INFO; private: - typedef enum { - NoneDictionaryKind = 0, - CachedDictionaryKind = 1, - UncachedDictionaryKind = 2 - } DictionaryKind; - -public: -#define DEFINE_BITFIELD(type, lowerName, upperName, width, offset) \ - static const uint32_t s_##lowerName##Shift = offset;\ - static const uint32_t s_##lowerName##Mask = ((1 << (width - 1)) | ((1 << (width - 1)) - 1));\ - type lowerName() const { return static_cast<type>((m_bitField >> offset) & s_##lowerName##Mask); }\ - void set##upperName(type newValue) \ - {\ - m_bitField &= ~(s_##lowerName##Mask << offset);\ - m_bitField |= (newValue & s_##lowerName##Mask) << offset;\ - } - - DEFINE_BITFIELD(DictionaryKind, dictionaryKind, DictionaryKind, 2, 0); - DEFINE_BITFIELD(bool, isPinnedPropertyTable, IsPinnedPropertyTable, 1, 2); - DEFINE_BITFIELD(bool, hasGetterSetterProperties, HasGetterSetterProperties, 1, 3); - DEFINE_BITFIELD(bool, hasReadOnlyOrGetterSetterPropertiesExcludingProto, HasReadOnlyOrGetterSetterPropertiesExcludingProto, 1, 4); - DEFINE_BITFIELD(bool, hasNonEnumerableProperties, HasNonEnumerableProperties, 1, 5); - DEFINE_BITFIELD(unsigned, attributesInPrevious, AttributesInPrevious, 14, 6); - DEFINE_BITFIELD(bool, preventExtensions, PreventExtensions, 1, 20); - DEFINE_BITFIELD(bool, didTransition, DidTransition, 1, 21); - DEFINE_BITFIELD(bool, staticFunctionsReified, StaticFunctionsReified, 1, 22); - DEFINE_BITFIELD(bool, hasRareData, HasRareData, 1, 23); - DEFINE_BITFIELD(bool, hasBeenFlattenedBefore, HasBeenFlattenedBefore, 1, 24); - DEFINE_BITFIELD(bool, hasCustomGetterSetterProperties, HasCustomGetterSetterProperties, 1, 25); - DEFINE_BITFIELD(bool, didWatchInternalProperties, DidWatchInternalProperties, 1, 26); - DEFINE_BITFIELD(bool, transitionWatchpointIsLikelyToBeFired, TransitionWatchpointIsLikelyToBeFired, 1, 27); - -private: friend class LLIntOffsetsExtractor; JS_EXPORT_PRIVATE Structure(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType, unsigned inlineCapacity); Structure(VM&); - Structure(VM&, Structure*, DeferredStructureTransitionWatchpointFire*); + Structure(VM&, const Structure*); - static Structure* create(VM&, Structure*, DeferredStructureTransitionWatchpointFire* = nullptr); + static Structure* create(VM&, const Structure*); - static Structure* addPropertyTransitionToExistingStructureImpl(Structure*, UniquedStringImpl* uid, unsigned attributes, PropertyOffset&); + static Structure* addPropertyTransitionToExistingStructureImpl(Structure*, StringImpl* uid, unsigned attributes, JSCell* specificValue, PropertyOffset&); // This will return the structure that has a usable property table, that property table, // and the list of structures that we visited before we got to it. If it returns a @@ -540,20 +392,28 @@ private: // to unlock it. void findStructuresAndMapForMaterialization(Vector<Structure*, 8>& structures, Structure*&, PropertyTable*&); - static Structure* toDictionaryTransition(VM&, Structure*, DictionaryKind, DeferredStructureTransitionWatchpointFire* = nullptr); + typedef enum { + NoneDictionaryKind = 0, + CachedDictionaryKind = 1, + UncachedDictionaryKind = 2 + } DictionaryKind; + static Structure* toDictionaryTransition(VM&, Structure*, DictionaryKind); - PropertyOffset add(VM&, PropertyName, unsigned attributes); + PropertyOffset putSpecificValue(VM&, PropertyName, unsigned attributes, JSCell* specificValue); PropertyOffset remove(PropertyName); void createPropertyMap(const GCSafeConcurrentJITLocker&, VM&, unsigned keyCount = 0); void checkConsistency(); + bool despecifyFunction(VM&, PropertyName); + void despecifyAllFunctions(VM&); + WriteBarrier<PropertyTable>& propertyTable(); - PropertyTable* takePropertyTableOrCloneIfPinned(VM&); - PropertyTable* copyPropertyTable(VM&); - PropertyTable* copyPropertyTableForPinning(VM&); + PropertyTable* takePropertyTableOrCloneIfPinned(VM&, Structure* owner); + PropertyTable* copyPropertyTable(VM&, Structure* owner); + PropertyTable* copyPropertyTableForPinning(VM&, Structure* owner); JS_EXPORT_PRIVATE void materializePropertyMap(VM&); - ALWAYS_INLINE void materializePropertyMapIfNecessary(VM& vm, DeferGC&) + void materializePropertyMapIfNecessary(VM& vm, DeferGC&) { ASSERT(!isCompilationThread()); ASSERT(structure()->classInfo() == info()); @@ -561,18 +421,6 @@ private: if (!propertyTable() && previousID()) materializePropertyMap(vm); } - ALWAYS_INLINE void materializePropertyMapIfNecessary(VM& vm, PropertyTable*& table) - { - ASSERT(!isCompilationThread()); - ASSERT(structure()->classInfo() == info()); - ASSERT(checkOffsetConsistency()); - table = propertyTable().get(); - if (!table && previousID()) { - DeferGC deferGC(vm.heap); - materializePropertyMap(vm); - table = propertyTable().get(); - } - } void materializePropertyMapIfNecessaryForPinning(VM& vm, DeferGC&) { ASSERT(structure()->classInfo() == info()); @@ -581,17 +429,17 @@ private: materializePropertyMap(vm); } - void setPreviousID(VM& vm, Structure* structure) + void setPreviousID(VM& vm, Structure* transition, Structure* structure) { - if (hasRareData()) - rareData()->setPreviousID(vm, structure); + if (typeInfo().structureHasRareData()) + rareData()->setPreviousID(vm, transition, structure); else - m_previousOrRareData.set(vm, this, structure); + m_previousOrRareData.set(vm, transition, structure); } void clearPreviousID() { - if (hasRareData()) + if (typeInfo().structureHasRareData()) rareData()->clearPreviousID(); else m_previousOrRareData.clear(); @@ -610,37 +458,34 @@ private: Structure* previous() const { - ASSERT(!hasRareData()); + ASSERT(!typeInfo().structureHasRareData()); return static_cast<Structure*>(m_previousOrRareData.get()); } StructureRareData* rareData() const { - ASSERT(hasRareData()); + ASSERT(typeInfo().structureHasRareData()); return static_cast<StructureRareData*>(m_previousOrRareData.get()); } bool checkOffsetConsistency() const; - JS_EXPORT_PRIVATE void allocateRareData(VM&); - - void startWatchingInternalProperties(VM&); + void allocateRareData(VM&); + void cloneRareDataFrom(VM&, const Structure*); static const int s_maxTransitionLength = 64; static const int s_maxTransitionLengthForNonEvalPutById = 512; - // These need to be properly aligned at the beginning of the 'Structure' - // part of the object. - StructureIDBlob m_blob; - TypeInfo::OutOfLineTypeFlags m_outOfLineTypeFlags; - + static const unsigned maxSpecificFunctionThrashCount = 3; + WriteBarrier<JSGlobalObject> m_globalObject; WriteBarrier<Unknown> m_prototype; mutable WriteBarrier<StructureChain> m_cachedPrototypeChain; WriteBarrier<JSCell> m_previousOrRareData; - RefPtr<UniquedStringImpl> m_nameInPrevious; + RefPtr<StringImpl> m_nameInPrevious; + WriteBarrier<JSCell> m_specificValueInPrevious; const ClassInfo* m_classInfo; @@ -656,11 +501,22 @@ private: // m_offset does not account for anonymous slots PropertyOffset m_offset; + TypeInfo m_typeInfo; + IndexingType m_indexingType; uint8_t m_inlineCapacity; ConcurrentJITLock m_lock; - uint32_t m_bitField; + 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 : 1; }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/StructureChain.cpp b/Source/JavaScriptCore/runtime/StructureChain.cpp index 9a8568b69..d18a715c3 100644 --- a/Source/JavaScriptCore/runtime/StructureChain.cpp +++ b/Source/JavaScriptCore/runtime/StructureChain.cpp @@ -10,10 +10,10 @@ * 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 + * 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 INC. OR + * 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 @@ -27,13 +27,13 @@ #include "StructureChain.h" #include "JSObject.h" -#include "JSCInlines.h" +#include "Operations.h" #include "Structure.h" #include <wtf/RefPtr.h> namespace JSC { -const ClassInfo StructureChain::s_info = { "StructureChain", 0, 0, CREATE_METHOD_TABLE(StructureChain) }; +const ClassInfo StructureChain::s_info = { "StructureChain", 0, 0, 0, CREATE_METHOD_TABLE(StructureChain) }; StructureChain::StructureChain(VM& vm, Structure* structure) : JSCell(vm, structure) @@ -49,6 +49,7 @@ void StructureChain::visitChildren(JSCell* cell, SlotVisitor& visitor) { StructureChain* thisObject = jsCast<StructureChain*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); size_t i = 0; while (thisObject->m_vector[i]) visitor.append(&thisObject->m_vector[i++]); diff --git a/Source/JavaScriptCore/runtime/StructureChain.h b/Source/JavaScriptCore/runtime/StructureChain.h index 0fbd1e207..a992d89fe 100644 --- a/Source/JavaScriptCore/runtime/StructureChain.h +++ b/Source/JavaScriptCore/runtime/StructureChain.h @@ -10,10 +10,10 @@ * 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 + * 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 INC. OR + * 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 @@ -37,56 +37,53 @@ namespace JSC { -class LLIntOffsetsExtractor; -class Structure; - -class StructureChain final : public JSCell { - friend class JIT; - -public: - typedef JSCell Base; - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; - - static StructureChain* create(VM& vm, Structure* 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(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); - } - - DECLARE_INFO; - - static const bool needsDestruction = true; - static void destroy(JSCell*); - -protected: - void finishCreation(VM& vm, Structure* head) - { - Base::finishCreation(vm); - size_t size = 0; - for (Structure* current = head; current; current = current->storedPrototype().isNull() ? 0 : asObject(current->storedPrototype())->structure()) - ++size; - - m_vector = std::make_unique<WriteBarrier<Structure>[]>(size + 1); - - size_t i = 0; - for (Structure* current = head; current; current = current->storedPrototype().isNull() ? 0 : asObject(current->storedPrototype())->structure()) - m_vector[i++].set(vm, this, current); - } - -private: - friend class LLIntOffsetsExtractor; - - StructureChain(VM&, Structure*); - std::unique_ptr<WriteBarrier<Structure>[]> m_vector; -}; + class LLIntOffsetsExtractor; + class Structure; + + class StructureChain : public JSCell { + friend class JIT; + + public: + typedef JSCell Base; + + static StructureChain* create(VM& vm, Structure* 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(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, OverridesVisitChildren), info()); } + + DECLARE_INFO; + + static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; + static void destroy(JSCell*); + + protected: + void finishCreation(VM& vm, Structure* head) + { + Base::finishCreation(vm); + size_t size = 0; + for (Structure* current = head; current; current = current->storedPrototype().isNull() ? 0 : asObject(current->storedPrototype())->structure()) + ++size; + + m_vector = std::make_unique<WriteBarrier<Structure>[]>(size + 1); + + size_t i = 0; + for (Structure* current = head; current; current = current->storedPrototype().isNull() ? 0 : asObject(current->storedPrototype())->structure()) + m_vector[i++].set(vm, this, current); + } + + private: + friend class LLIntOffsetsExtractor; + + StructureChain(VM&, Structure*); + std::unique_ptr<WriteBarrier<Structure>[]> m_vector; + }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/StructureIDBlob.h b/Source/JavaScriptCore/runtime/StructureIDBlob.h deleted file mode 100644 index d101ed95c..000000000 --- a/Source/JavaScriptCore/runtime/StructureIDBlob.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2014 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 StructureIDBlob_h -#define StructureIDBlob_h - -#include "IndexingType.h" -#include "JSTypeInfo.h" -#include "StructureIDTable.h" - -namespace JSC { - -class StructureIDBlob { - friend class LLIntOffsetsExtractor; -public: - StructureIDBlob() - { - u.doubleWord = 0xbbadbeef; - } - - StructureIDBlob(StructureID structureID, IndexingType indexingType, const TypeInfo& typeInfo) - { - u.fields.structureID = structureID; - u.fields.indexingType = indexingType; - u.fields.type = typeInfo.type(); - u.fields.inlineTypeFlags = typeInfo.inlineTypeFlags(); - u.fields.defaultGCData = JSCell::NotMarked; - } - - void operator=(const StructureIDBlob& other) { u.doubleWord = other.u.doubleWord; } - - StructureID structureID() const { return u.fields.structureID; } - IndexingType indexingType() const { return u.fields.indexingType; } - void setIndexingType(IndexingType indexingType) { u.fields.indexingType = indexingType; } - JSType type() const { return u.fields.type; } - TypeInfo::InlineTypeFlags inlineTypeFlags() const { return u.fields.inlineTypeFlags; } - - TypeInfo typeInfo(TypeInfo::OutOfLineTypeFlags outOfLineTypeFlags) const { return TypeInfo(type(), inlineTypeFlags(), outOfLineTypeFlags); } - - int32_t blobExcludingStructureID() const { return u.words.word2; } - int64_t blob() const { return u.doubleWord; } - - static ptrdiff_t structureIDOffset() - { - return OBJECT_OFFSETOF(StructureIDBlob, u.fields.structureID); - } - - static ptrdiff_t indexingTypeOffset() - { - return OBJECT_OFFSETOF(StructureIDBlob, u.fields.indexingType); - } - -private: - union { - struct { - StructureID structureID; - IndexingType indexingType; - JSType type; - TypeInfo::InlineTypeFlags inlineTypeFlags; - JSCell::GCData defaultGCData; - } fields; - struct { - int32_t word1; - int32_t word2; - } words; - int64_t doubleWord; - } u; -}; - -} // namespace JSC - -#endif // StructureIDBlob_h diff --git a/Source/JavaScriptCore/runtime/StructureIDTable.cpp b/Source/JavaScriptCore/runtime/StructureIDTable.cpp deleted file mode 100644 index 8aa89b066..000000000 --- a/Source/JavaScriptCore/runtime/StructureIDTable.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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 "StructureIDTable.h" - -#include <limits.h> -#include <wtf/Atomics.h> -#include <wtf/DataLog.h> - -namespace JSC { - -StructureIDTable::StructureIDTable() - : m_firstFreeOffset(0) - , m_table(std::make_unique<StructureOrOffset[]>(s_initialSize)) - , m_size(0) - , m_capacity(s_initialSize) -{ - // We pre-allocate the first offset so that the null Structure - // can still be represented as the StructureID '0'. - allocateID(0); -} - -void StructureIDTable::resize(size_t newCapacity) -{ - // Create the new table. - auto newTable = std::make_unique<StructureOrOffset[]>(newCapacity); - - // Copy the contents of the old table to the new table. - memcpy(newTable.get(), table(), m_capacity * sizeof(StructureOrOffset)); - - // Store fence to make sure we've copied everything before doing the swap. - WTF::storeStoreFence(); - - // Swap the old and new tables. - swap(m_table, newTable); - - // Put the old table (now labeled as new) into the list of old tables. - m_oldTables.append(WTF::move(newTable)); - - // Update the capacity. - m_capacity = newCapacity; -} - -void StructureIDTable::flushOldTables() -{ - m_oldTables.clear(); -} - -StructureID StructureIDTable::allocateID(Structure* structure) -{ -#if USE(JSVALUE64) - if (!m_firstFreeOffset) { - RELEASE_ASSERT(m_capacity <= UINT_MAX); - if (m_size == m_capacity) - resize(m_capacity * 2); - ASSERT(m_size < m_capacity); - - StructureOrOffset newEntry; - newEntry.structure = structure; - - if (m_size == s_unusedID) { - m_size++; - return allocateID(structure); - } - - StructureID result = m_size; - table()[result] = newEntry; - m_size++; - return result; - } - - ASSERT(m_firstFreeOffset != s_unusedID); - - StructureID result = m_firstFreeOffset; - m_firstFreeOffset = table()[m_firstFreeOffset].offset; - table()[result].structure = structure; - return result; -#else - return structure; -#endif -} - -void StructureIDTable::deallocateID(Structure* structure, StructureID structureID) -{ -#if USE(JSVALUE64) - ASSERT(structureID != s_unusedID); - RELEASE_ASSERT(table()[structureID].structure == structure); - table()[structureID].offset = m_firstFreeOffset; - m_firstFreeOffset = structureID; -#else - UNUSED_PARAM(structure); - UNUSED_PARAM(structureID); -#endif -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/StructureIDTable.h b/Source/JavaScriptCore/runtime/StructureIDTable.h deleted file mode 100644 index 630333f0c..000000000 --- a/Source/JavaScriptCore/runtime/StructureIDTable.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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 StructureIDTable_h -#define StructureIDTable_h - -#include "UnusedPointer.h" -#include <wtf/Vector.h> - -namespace JSC { - -class Structure; - -#if USE(JSVALUE64) -typedef uint32_t StructureID; -#else -typedef Structure* StructureID; -#endif - -class StructureIDTable { - friend class LLIntOffsetsExtractor; -public: - StructureIDTable(); - - void** base() { return reinterpret_cast<void**>(&m_table); } - - Structure* get(StructureID); - void deallocateID(Structure*, StructureID); - StructureID allocateID(Structure*); - - void flushOldTables(); - -private: - void resize(size_t newCapacity); - - union StructureOrOffset { - WTF_MAKE_FAST_ALLOCATED; - public: - Structure* structure; - StructureID offset; - }; - - StructureOrOffset* table() const { return m_table.get(); } - - static const size_t s_initialSize = 256; - - Vector<std::unique_ptr<StructureOrOffset[]>> m_oldTables; - - uint32_t m_firstFreeOffset; - std::unique_ptr<StructureOrOffset[]> m_table; - - size_t m_size; - size_t m_capacity; - -#if USE(JSVALUE64) - static const StructureID s_unusedID = unusedPointer; -#endif -}; - -inline Structure* StructureIDTable::get(StructureID structureID) -{ -#if USE(JSVALUE64) - ASSERT_WITH_SECURITY_IMPLICATION(structureID && structureID < m_capacity); - return table()[structureID].structure; -#else - return structureID; -#endif -} - -} // namespace JSC - -#endif // StructureIDTable_h diff --git a/Source/JavaScriptCore/runtime/StructureInlines.h b/Source/JavaScriptCore/runtime/StructureInlines.h index f1955f656..5895ecb20 100644 --- a/Source/JavaScriptCore/runtime/StructureInlines.h +++ b/Source/JavaScriptCore/runtime/StructureInlines.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * 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 @@ -10,10 +10,10 @@ * 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 + * 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 INC. OR + * 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 @@ -49,10 +49,10 @@ inline Structure* Structure::createStructure(VM& vm) return structure; } -inline Structure* Structure::create(VM& vm, Structure* structure, DeferredStructureTransitionWatchpointFire* deferred) +inline Structure* Structure::create(VM& vm, const Structure* structure) { ASSERT(vm.structureStructure); - Structure* newStructure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm, structure, deferred); + Structure* newStructure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm, structure); newStructure->finishCreation(vm); return newStructure; } @@ -61,7 +61,7 @@ inline JSObject* Structure::storedPrototypeObject() const { JSValue value = m_prototype.get(); if (value.isNull()) - return nullptr; + return 0; return asObject(value); } @@ -69,74 +69,42 @@ inline Structure* Structure::storedPrototypeStructure() const { JSObject* object = storedPrototypeObject(); if (!object) - return nullptr; + return 0; return object->structure(); } -ALWAYS_INLINE PropertyOffset Structure::get(VM& vm, PropertyName propertyName) +inline PropertyOffset Structure::get(VM& vm, PropertyName propertyName) { ASSERT(!isCompilationThread()); ASSERT(structure()->classInfo() == info()); - PropertyTable* propertyTable; - materializePropertyMapIfNecessary(vm, propertyTable); - if (!propertyTable) + DeferGC deferGC(vm.heap); + materializePropertyMapIfNecessary(vm, deferGC); + if (!propertyTable()) return invalidOffset; - PropertyMapEntry* entry = propertyTable->get(propertyName.uid()); + PropertyMapEntry* entry = propertyTable()->find(propertyName.uid()).first; return entry ? entry->offset : invalidOffset; } - -ALWAYS_INLINE PropertyOffset Structure::get(VM& vm, PropertyName propertyName, unsigned& attributes) + +inline PropertyOffset Structure::get(VM& vm, const WTF::String& name) { ASSERT(!isCompilationThread()); ASSERT(structure()->classInfo() == info()); - - PropertyTable* propertyTable; - materializePropertyMapIfNecessary(vm, propertyTable); - if (!propertyTable) - return invalidOffset; - - PropertyMapEntry* entry = propertyTable->get(propertyName.uid()); - if (!entry) + DeferGC deferGC(vm.heap); + materializePropertyMapIfNecessary(vm, deferGC); + if (!propertyTable()) return invalidOffset; - attributes = entry->attributes; - return entry->offset; + PropertyMapEntry* entry = propertyTable()->findWithString(name.impl()).first; + return entry ? entry->offset : invalidOffset; } - -template<typename Functor> -void Structure::forEachPropertyConcurrently(const Functor& functor) -{ - Vector<Structure*, 8> structures; - Structure* structure; - PropertyTable* table; - findStructuresAndMapForMaterialization(structures, structure, table); - - if (table) { - for (auto& entry : *table) { - if (!functor(entry)) { - structure->m_lock.unlock(); - return; - } - } - structure->m_lock.unlock(); - } - - for (unsigned i = structures.size(); i--;) { - structure = structures[i]; - if (!structure->m_nameInPrevious) - continue; - - if (!functor(PropertyMapEntry(structure->m_nameInPrevious.get(), structure->m_offset, structure->attributesInPrevious()))) - return; - } -} - -inline PropertyOffset Structure::getConcurrently(UniquedStringImpl* uid) +inline PropertyOffset Structure::getConcurrently(VM& vm, StringImpl* uid) { unsigned attributesIgnored; - return getConcurrently(uid, attributesIgnored); + JSCell* specificValueIgnored; + return getConcurrently( + vm, uid, attributesIgnored, specificValueIgnored); } inline bool Structure::hasIndexingHeader(const JSCell* cell) const @@ -164,12 +132,25 @@ inline bool Structure::transitivelyTransitionedFrom(Structure* structureToFind) 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(); - if (typeInfo().type() == SymbolType) - return globalObject->symbolPrototype(); ASSERT(typeInfo().type() == StringType); return globalObject->stringPrototype(); @@ -242,37 +223,12 @@ ALWAYS_INLINE WriteBarrier<PropertyTable>& Structure::propertyTable() return m_propertyTableUnsafe; } -inline void Structure::didReplaceProperty(PropertyOffset offset) -{ - if (LIKELY(!hasRareData())) - return; - StructureRareData::PropertyWatchpointMap* map = rareData()->m_replacementWatchpointSets.get(); - if (LIKELY(!map)) - return; - WatchpointSet* set = map->get(offset); - if (LIKELY(!set)) - return; - set->fireAll("Property did get replaced"); -} - -inline WatchpointSet* Structure::propertyReplacementWatchpointSet(PropertyOffset offset) -{ - ConcurrentJITLocker locker(m_lock); - if (!hasRareData()) - return nullptr; - WTF::loadLoadFence(); - StructureRareData::PropertyWatchpointMap* map = rareData()->m_replacementWatchpointSets.get(); - if (!map) - return nullptr; - return map->get(offset); -} - ALWAYS_INLINE bool Structure::checkOffsetConsistency() const { PropertyTable* propertyTable = m_propertyTableUnsafe.get(); if (!propertyTable) { - ASSERT(!isPinnedPropertyTable()); + ASSERT(!m_isPinnedPropertyTable); return true; } @@ -290,18 +246,6 @@ ALWAYS_INLINE bool Structure::checkOffsetConsistency() const return true; } -inline size_t nextOutOfLineStorageCapacity(size_t currentCapacity) -{ - if (!currentCapacity) - return initialOutOfLineCapacity; - return currentCapacity * outOfLineGrowthFactor; -} - -inline size_t Structure::suggestedNewOutOfLineStorageCapacity() -{ - return nextOutOfLineStorageCapacity(outOfLineCapacity()); -} - } // namespace JSC #endif // StructureInlines_h diff --git a/Source/JavaScriptCore/runtime/StructureRareData.cpp b/Source/JavaScriptCore/runtime/StructureRareData.cpp index 20a5371e7..9e7265178 100644 --- a/Source/JavaScriptCore/runtime/StructureRareData.cpp +++ b/Source/JavaScriptCore/runtime/StructureRareData.cpp @@ -26,17 +26,17 @@ #include "config.h" #include "StructureRareData.h" -#include "JSPropertyNameEnumerator.h" +#include "JSPropertyNameIterator.h" #include "JSString.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { -const ClassInfo StructureRareData::s_info = { "StructureRareData", 0, 0, CREATE_METHOD_TABLE(StructureRareData) }; +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(CellType, StructureFlags), info()); + return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, StructureFlags), info()); } StructureRareData* StructureRareData::create(VM& vm, Structure* previous) @@ -46,9 +46,11 @@ StructureRareData* StructureRareData::create(VM& vm, Structure* previous) return rareData; } -void StructureRareData::destroy(JSCell* cell) +StructureRareData* StructureRareData::clone(VM& vm, const StructureRareData* other) { - static_cast<StructureRareData*>(cell)->StructureRareData::~StructureRareData(); + StructureRareData* newRareData = new (NotNull, allocateCell<StructureRareData>(vm.heap)) StructureRareData(vm, other); + newRareData->finishCreation(vm); + return newRareData; } StructureRareData::StructureRareData(VM& vm, Structure* previous) @@ -58,26 +60,25 @@ StructureRareData::StructureRareData(VM& vm, Structure* 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, info()); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); JSCell::visitChildren(thisObject, visitor); visitor.append(&thisObject->m_previous); visitor.append(&thisObject->m_objectToStringValue); - visitor.append(&thisObject->m_cachedPropertyNameEnumerator); - visitor.append(&thisObject->m_cachedGenericPropertyNameEnumerator); -} - -JSPropertyNameEnumerator* StructureRareData::cachedPropertyNameEnumerator() const -{ - return m_cachedPropertyNameEnumerator.get(); -} - -void StructureRareData::setCachedPropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator) -{ - m_cachedPropertyNameEnumerator.set(vm, this, enumerator); + visitor.append(&thisObject->m_enumerationCache); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/StructureRareData.h b/Source/JavaScriptCore/runtime/StructureRareData.h index 2b11ab833..c6798823d 100644 --- a/Source/JavaScriptCore/runtime/StructureRareData.h +++ b/Source/JavaScriptCore/runtime/StructureRareData.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * 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 @@ -29,51 +29,46 @@ #include "ClassInfo.h" #include "JSCell.h" #include "JSTypeInfo.h" -#include "PropertyOffset.h" namespace JSC { -class JSPropertyNameEnumerator; +class JSPropertyNameIterator; class Structure; -class StructureRareData final : public JSCell { +class StructureRareData : public JSCell { + friend class Structure; public: - typedef JSCell Base; - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; - static StructureRareData* create(VM&, Structure*); - - static const bool needsDestruction = true; - static void destroy(JSCell*); + 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*); + void setPreviousID(VM&, Structure* transition, Structure*); void clearPreviousID(); JSString* objectToStringValue() const; - void setObjectToStringValue(VM&, JSString* value); + void setObjectToStringValue(VM&, const JSCell* owner, JSString* value); - JSPropertyNameEnumerator* cachedPropertyNameEnumerator() const; - void setCachedPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*); + JSPropertyNameIterator* enumerationCache(); + void setEnumerationCache(VM&, const Structure* owner, JSPropertyNameIterator* value); DECLARE_EXPORT_INFO; private: - friend class Structure; - StructureRareData(VM&, Structure*); + StructureRareData(VM&, const StructureRareData*); + + static const unsigned StructureFlags = OverridesVisitChildren | JSCell::StructureFlags; WriteBarrier<Structure> m_previous; WriteBarrier<JSString> m_objectToStringValue; - WriteBarrier<JSPropertyNameEnumerator> m_cachedPropertyNameEnumerator; - WriteBarrier<JSPropertyNameEnumerator> m_cachedGenericPropertyNameEnumerator; - - typedef HashMap<PropertyOffset, RefPtr<WatchpointSet>, WTF::IntHash<PropertyOffset>, WTF::UnsignedWithZeroKeyHashTraits<PropertyOffset>> PropertyWatchpointMap; - std::unique_ptr<PropertyWatchpointMap> m_replacementWatchpointSets; + WriteBarrier<JSPropertyNameIterator> m_enumerationCache; }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/StructureRareDataInlines.h b/Source/JavaScriptCore/runtime/StructureRareDataInlines.h index 99ac3c0ab..5b39bad1f 100644 --- a/Source/JavaScriptCore/runtime/StructureRareDataInlines.h +++ b/Source/JavaScriptCore/runtime/StructureRareDataInlines.h @@ -35,7 +35,7 @@ inline Structure* StructureRareData::previousID() const return m_previous.get(); } -inline void StructureRareData::setPreviousID(VM& vm, Structure* structure) +inline void StructureRareData::setPreviousID(VM& vm, Structure*, Structure* structure) { m_previous.set(vm, this, structure); } @@ -50,7 +50,7 @@ inline JSString* StructureRareData::objectToStringValue() const return m_objectToStringValue.get(); } -inline void StructureRareData::setObjectToStringValue(VM& vm, JSString* value) +inline void StructureRareData::setObjectToStringValue(VM& vm, const JSCell*, JSString* value) { m_objectToStringValue.set(vm, this, value); } diff --git a/Source/JavaScriptCore/runtime/StructureTransitionTable.h b/Source/JavaScriptCore/runtime/StructureTransitionTable.h index 17690a3da..d66202364 100644 --- a/Source/JavaScriptCore/runtime/StructureTransitionTable.h +++ b/Source/JavaScriptCore/runtime/StructureTransitionTable.h @@ -10,10 +10,10 @@ * 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 + * 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 INC. OR + * 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 @@ -29,7 +29,8 @@ #include "IndexingType.h" #include "WeakGCMap.h" #include <wtf/HashFunctions.h> -#include <wtf/text/UniquedStringImpl.h> +#include <wtf/OwnPtr.h> +#include <wtf/text/StringImpl.h> namespace JSC { @@ -78,7 +79,7 @@ inline IndexingType newIndexingType(IndexingType oldType, NonPropertyTransition ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType) || hasContiguous(oldType)); return (oldType & ~IndexingShapeMask) | SlowPutArrayStorageShape; case SwitchToSlowPutArrayStorage: - ASSERT(hasArrayStorage(oldType)); + ASSERT(hasFastArrayStorage(oldType)); return (oldType & ~IndexingShapeMask) | SlowPutArrayStorageShape; case AddIndexedAccessors: return oldType | MayHaveIndexedAccessors; @@ -93,11 +94,11 @@ class StructureTransitionTable { struct Hash { - typedef std::pair<UniquedStringImpl*, unsigned> Key; + typedef std::pair<StringImpl*, unsigned> Key; static unsigned hash(const Key& p) { - return PtrHash<UniquedStringImpl*>::hash(p.first) + p.second; + return PtrHash<StringImpl*>::hash(p.first) + p.second; } static bool equal(const Key& a, const Key& b) @@ -129,13 +130,11 @@ public: WeakSet::deallocate(impl); } - void add(VM&, Structure*); - bool contains(UniquedStringImpl*, unsigned attributes) const; - Structure* get(UniquedStringImpl*, unsigned attributes) const; + inline void add(VM&, Structure*); + inline bool contains(StringImpl* rep, unsigned attributes) const; + inline Structure* get(StringImpl* rep, unsigned attributes) const; private: - friend class SingleSlotTransitionWeakOwner; - bool isUsingSingleSlot() const { return m_data & UsingSingleSlotFlag; @@ -166,8 +165,24 @@ private: ASSERT(!isUsingSingleSlot()); } - Structure* singleTransition() const; - void setSingleTransition(Structure*); + Structure* singleTransition() const + { + ASSERT(isUsingSingleSlot()); + if (WeakImpl* impl = this->weakImpl()) { + if (impl->state() == WeakImpl::Live) + return reinterpret_cast<Structure*>(impl->jsValue().asCell()); + } + return 0; + } + + void setSingleTransition(VM&, Structure* structure) + { + ASSERT(isUsingSingleSlot()); + if (WeakImpl* impl = this->weakImpl()) + WeakSet::deallocate(impl); + WeakImpl* impl = WeakSet::allocate(reinterpret_cast<JSCell*>(structure)); + m_data = reinterpret_cast<intptr_t>(impl) | UsingSingleSlotFlag; + } intptr_t m_data; }; diff --git a/Source/JavaScriptCore/runtime/Symbol.cpp b/Source/JavaScriptCore/runtime/Symbol.cpp deleted file mode 100644 index a765609ea..000000000 --- a/Source/JavaScriptCore/runtime/Symbol.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2012 Apple Inc. All rights reserved. - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. - * - * 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 "Symbol.h" - -#include "Error.h" -#include "JSCInlines.h" -#include "SymbolObject.h" - -namespace JSC { - -const ClassInfo Symbol::s_info = { "symbol", nullptr, nullptr, CREATE_METHOD_TABLE(Symbol) }; - -Symbol::Symbol(VM& vm) - : Base(vm, vm.symbolStructure.get()) - , m_privateName() -{ -} - -Symbol::Symbol(VM& vm, const String& string) - : Base(vm, vm.symbolStructure.get()) - , m_privateName(PrivateName::Description, string) -{ -} - -Symbol::Symbol(VM& vm, SymbolImpl& uid) - : Base(vm, vm.symbolStructure.get()) - , m_privateName(uid) -{ -} - -inline SymbolObject* SymbolObject::create(VM& vm, JSGlobalObject* globalObject, Symbol* symbol) -{ - SymbolObject* object = new (NotNull, allocateCell<SymbolObject>(vm.heap)) SymbolObject(vm, globalObject->symbolObjectStructure()); - object->finishCreation(vm, symbol); - return object; -} - -JSValue Symbol::toPrimitive(ExecState*, PreferredPrimitiveType) const -{ - return const_cast<Symbol*>(this); -} - -bool Symbol::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result) const -{ - result = this; - number = toNumber(exec); - return true; -} - -JSObject* Symbol::toObject(ExecState* exec, JSGlobalObject* globalObject) const -{ - return SymbolObject::create(exec->vm(), globalObject, const_cast<Symbol*>(this)); -} - -double Symbol::toNumber(ExecState* exec) const -{ - throwTypeError(exec); - return 0.0; -} - -void Symbol::destroy(JSCell* cell) -{ - static_cast<Symbol*>(cell)->Symbol::~Symbol(); -} - -String Symbol::descriptiveString() const -{ - return makeString("Symbol(", String(privateName().uid()), ')'); -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Symbol.h b/Source/JavaScriptCore/runtime/Symbol.h deleted file mode 100644 index 83f5de248..000000000 --- a/Source/JavaScriptCore/runtime/Symbol.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2012 Apple Inc. All rights reserved. - * Copyright (C) 2014 Apple Inc. All rights reserved. - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. - * - * 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 Symbol_h -#define Symbol_h - -#include "JSCell.h" -#include "JSString.h" -#include "PrivateName.h" - -namespace JSC { - -class Symbol final : public JSCell { -public: - typedef JSCell Base; - static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | StructureIsImmortal; - - DECLARE_EXPORT_INFO; - - static const bool needsDestruction = true; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(SymbolType, StructureFlags), info()); - } - - static Symbol* create(VM& vm) - { - Symbol* symbol = new (NotNull, allocateCell<Symbol>(vm.heap)) Symbol(vm); - symbol->finishCreation(vm); - return symbol; - } - - static Symbol* create(ExecState* exec, JSString* description) - { - VM& vm = exec->vm(); - String desc = description->value(exec); - Symbol* symbol = new (NotNull, allocateCell<Symbol>(vm.heap)) Symbol(vm, desc); - symbol->finishCreation(vm); - return symbol; - } - - static Symbol* create(VM& vm, SymbolImpl& uid) - { - Symbol* symbol = new (NotNull, allocateCell<Symbol>(vm.heap)) Symbol(vm, uid); - symbol->finishCreation(vm); - return symbol; - } - - const PrivateName& privateName() const { return m_privateName; } - String descriptiveString() const; - - JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; - bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const; - JSObject* toObject(ExecState*, JSGlobalObject*) const; - double toNumber(ExecState*) const; - - static size_t offsetOfPrivateName() { return OBJECT_OFFSETOF(Symbol, m_privateName); } - -protected: - static void destroy(JSCell*); - - Symbol(VM&); - Symbol(VM&, const String&); - Symbol(VM&, SymbolImpl& uid); - - void finishCreation(VM& vm) - { - Base::finishCreation(vm); - ASSERT(inherits(info())); - } - - PrivateName m_privateName; -}; - -Symbol* asSymbol(JSValue); - -inline Symbol* asSymbol(JSValue value) -{ - ASSERT(value.asCell()->isSymbol()); - return jsCast<Symbol*>(value.asCell()); -} - -} // namespace JSC - -#endif // Symbol_h diff --git a/Source/JavaScriptCore/runtime/SymbolConstructor.cpp b/Source/JavaScriptCore/runtime/SymbolConstructor.cpp deleted file mode 100644 index 753ce60ee..000000000 --- a/Source/JavaScriptCore/runtime/SymbolConstructor.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2012 Apple Inc. All rights reserved. - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. - * - * 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 "SymbolConstructor.h" - -#include "Error.h" -#include "JSCInlines.h" -#include "JSGlobalObject.h" -#include "Symbol.h" -#include "SymbolPrototype.h" -#include <wtf/text/SymbolRegistry.h> - -namespace JSC { - -static EncodedJSValue JSC_HOST_CALL symbolConstructorFor(ExecState*); -static EncodedJSValue JSC_HOST_CALL symbolConstructorKeyFor(ExecState*); - -} - -#include "SymbolConstructor.lut.h" - -namespace JSC { - -STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(SymbolConstructor); - -const ClassInfo SymbolConstructor::s_info = { "Function", &Base::s_info, &symbolConstructorTable, CREATE_METHOD_TABLE(SymbolConstructor) }; - -/* Source for SymbolConstructor.lut.h -@begin symbolConstructorTable - for symbolConstructorFor DontEnum|Function 1 - keyFor symbolConstructorKeyFor DontEnum|Function 1 -@end -*/ - -SymbolConstructor::SymbolConstructor(VM& vm, Structure* structure) - : InternalFunction(vm, structure) -{ -} - -#define INITIALIZE_WELL_KNOWN_SYMBOLS(name) \ - putDirectWithoutTransition(vm, Identifier::fromString(&vm, #name), Symbol::create(vm, static_cast<SymbolImpl&>(*vm.propertyNames->name##Symbol.impl())), DontEnum | DontDelete | ReadOnly); - -void SymbolConstructor::finishCreation(VM& vm, SymbolPrototype* prototype) -{ - Base::finishCreation(vm, prototype->classInfo()->className); - putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, DontEnum | DontDelete | ReadOnly); - putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), DontDelete | ReadOnly | DontEnum); - - JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(INITIALIZE_WELL_KNOWN_SYMBOLS) -} - -bool SymbolConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot) -{ - return getStaticFunctionSlot<Base>(exec, symbolConstructorTable, jsCast<SymbolConstructor*>(object), propertyName, slot); -} - -// ------------------------------ Functions --------------------------- - -static EncodedJSValue JSC_HOST_CALL callSymbol(ExecState* exec) -{ - JSValue description = exec->argument(0); - if (description.isUndefined()) - return JSValue::encode(Symbol::create(exec->vm())); - return JSValue::encode(Symbol::create(exec, description.toString(exec))); -} - -ConstructType SymbolConstructor::getConstructData(JSCell*, ConstructData&) -{ - return ConstructTypeNone; -} - -CallType SymbolConstructor::getCallData(JSCell*, CallData& callData) -{ - callData.native.function = callSymbol; - return CallTypeHost; -} - -EncodedJSValue JSC_HOST_CALL symbolConstructorFor(ExecState* exec) -{ - JSString* stringKey = exec->argument(0).toString(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - String string = stringKey->value(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - return JSValue::encode(Symbol::create(exec->vm(), exec->vm().symbolRegistry().symbolForKey(string))); -} - -EncodedJSValue JSC_HOST_CALL symbolConstructorKeyFor(ExecState* exec) -{ - JSValue symbolValue = exec->argument(0); - if (!symbolValue.isSymbol()) - return JSValue::encode(throwTypeError(exec)); - - SymbolImpl* uid = asSymbol(symbolValue)->privateName().uid(); - if (!uid->symbolRegistry()) - return JSValue::encode(jsUndefined()); - - ASSERT(uid->symbolRegistry() == &exec->vm().symbolRegistry()); - return JSValue::encode(jsString(exec, exec->vm().symbolRegistry().keyForSymbol(*uid))); -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/SymbolObject.h b/Source/JavaScriptCore/runtime/SymbolObject.h deleted file mode 100644 index 46a049170..000000000 --- a/Source/JavaScriptCore/runtime/SymbolObject.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef SymbolObject_h -#define SymbolObject_h - -#include "JSWrapperObject.h" -#include "Symbol.h" - -namespace JSC { - -class SymbolObject : public JSWrapperObject { -public: - typedef JSWrapperObject Base; - - static SymbolObject* create(VM& vm, Structure* structure) - { - Symbol* symbol = Symbol::create(vm); - SymbolObject* object = new (NotNull, allocateCell<SymbolObject>(vm.heap)) SymbolObject(vm, structure); - object->finishCreation(vm, symbol); - return object; - } - static SymbolObject* create(VM& vm, Structure* structure, Symbol* symbol) - { - SymbolObject* object = new (NotNull, allocateCell<SymbolObject>(vm.heap)) SymbolObject(vm, structure); - object->finishCreation(vm, symbol); - return object; - } - static SymbolObject* create(VM&, JSGlobalObject*, Symbol*); - - DECLARE_EXPORT_INFO; - - Symbol* internalValue() const { return asSymbol(JSWrapperObject::internalValue());} - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } - - static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType); - -protected: - JS_EXPORT_PRIVATE void finishCreation(VM&, Symbol*); - JS_EXPORT_PRIVATE SymbolObject(VM&, Structure*); -}; - -} // namespace JSC - -#endif // SymbolObject_h diff --git a/Source/JavaScriptCore/runtime/SymbolPrototype.cpp b/Source/JavaScriptCore/runtime/SymbolPrototype.cpp deleted file mode 100644 index 2f4ac4dd5..000000000 --- a/Source/JavaScriptCore/runtime/SymbolPrototype.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2012 Apple Inc. All rights reserved. - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. - * - * 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 "SymbolPrototype.h" - -#include "Error.h" -#include "JSCInlines.h" - -namespace JSC { - -static EncodedJSValue JSC_HOST_CALL symbolProtoFuncToString(ExecState*); -static EncodedJSValue JSC_HOST_CALL symbolProtoFuncValueOf(ExecState*); - -} - -#include "SymbolPrototype.lut.h" - -namespace JSC { - -const ClassInfo SymbolPrototype::s_info = { "Symbol", &Base::s_info, &symbolPrototypeTable, CREATE_METHOD_TABLE(SymbolPrototype) }; - -/* Source for SymbolPrototype.lut.h -@begin symbolPrototypeTable - toString symbolProtoFuncToString DontEnum|Function 0 - valueOf symbolProtoFuncValueOf DontEnum|Function 0 -@end -*/ - -SymbolPrototype::SymbolPrototype(VM& vm, Structure* structure) - : Base(vm, structure) -{ -} - -void SymbolPrototype::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); -} - -bool SymbolPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot) -{ - return getStaticFunctionSlot<Base>(exec, symbolPrototypeTable, jsCast<SymbolPrototype*>(object), propertyName, slot); -} - -// ------------------------------ Functions --------------------------- - -EncodedJSValue JSC_HOST_CALL symbolProtoFuncToString(ExecState* exec) -{ - JSValue thisValue = exec->thisValue(); - Symbol* symbol = nullptr; - if (thisValue.isSymbol()) - symbol = asSymbol(thisValue); - else if (!thisValue.isObject()) - return throwVMTypeError(exec); - else { - JSObject* thisObject = asObject(thisValue); - if (!thisObject->inherits(SymbolObject::info())) - return throwVMTypeError(exec); - symbol = asSymbol(jsCast<SymbolObject*>(thisObject)->internalValue()); - } - - return JSValue::encode(jsNontrivialString(exec, symbol->descriptiveString())); -} - -EncodedJSValue JSC_HOST_CALL symbolProtoFuncValueOf(ExecState* exec) -{ - JSValue thisValue = exec->thisValue(); - if (thisValue.isSymbol()) - return JSValue::encode(thisValue); - - if (!thisValue.isObject()) - return throwVMTypeError(exec); - - JSObject* thisObject = asObject(thisValue); - if (!thisObject->inherits(SymbolObject::info())) - return throwVMTypeError(exec); - - return JSValue::encode(jsCast<SymbolObject*>(thisObject)->internalValue()); -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/SymbolTable.cpp b/Source/JavaScriptCore/runtime/SymbolTable.cpp index 02f943f0a..556dbf7af 100644 --- a/Source/JavaScriptCore/runtime/SymbolTable.cpp +++ b/Source/JavaScriptCore/runtime/SymbolTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2014, 2015 Apple Inc. All rights reserved. + * 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 @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -30,13 +30,12 @@ #include "SymbolTable.h" #include "JSDestructibleObject.h" -#include "JSCInlines.h" +#include "Operations.h" #include "SlotVisitorInlines.h" -#include "TypeProfiler.h" namespace JSC { -const ClassInfo SymbolTable::s_info = { "SymbolTable", 0, 0, CREATE_METHOD_TABLE(SymbolTable) }; +const ClassInfo SymbolTable::s_info = { "SymbolTable", 0, 0, 0, CREATE_METHOD_TABLE(SymbolTable) }; SymbolTableEntry& SymbolTableEntry::copySlow(const SymbolTableEntry& other) { @@ -59,14 +58,19 @@ void SymbolTableEntry::freeFatEntrySlow() delete fatEntry(); } +JSValue SymbolTableEntry::inferredValue() +{ + if (!isFat()) + return JSValue(); + return fatEntry()->m_watchpoints->inferredValue(); +} + void SymbolTableEntry::prepareToWatch() { - if (!isWatchable()) - return; FatEntry* entry = inflate(); if (entry->m_watchpoints) return; - entry->m_watchpoints = adoptRef(new WatchpointSet(ClearWatchpoint)); + entry->m_watchpoints = adoptRef(new VariableWatchpointSet()); } void SymbolTableEntry::addWatchpoint(Watchpoint* watchpoint) @@ -74,6 +78,15 @@ void SymbolTableEntry::addWatchpoint(Watchpoint* watchpoint) fatEntry()->m_watchpoints->add(watchpoint); } +void SymbolTableEntry::notifyWriteSlow(JSValue value) +{ + VariableWatchpointSet* watchpoints = fatEntry()->m_watchpoints.get(); + if (!watchpoints) + return; + + watchpoints->notifyWrite(value); +} + SymbolTableEntry::FatEntry* SymbolTableEntry::inflateSlow() { FatEntry* entry = new FatEntry(m_bits); @@ -83,179 +96,69 @@ SymbolTableEntry::FatEntry* SymbolTableEntry::inflateSlow() SymbolTable::SymbolTable(VM& vm) : JSCell(vm, vm.symbolTableStructure.get()) + , m_parameterCountIncludingThis(0) , m_usesNonStrictEval(false) - , m_scopeType(VarScope) + , m_captureStart(0) + , m_captureEnd(0) + , m_functionEnteredOnce(ClearWatchpoint) { } SymbolTable::~SymbolTable() { } -void SymbolTable::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - m_singletonScope.set(vm, this, InferredValue::create(vm)); -} - void SymbolTable::visitChildren(JSCell* thisCell, SlotVisitor& visitor) { SymbolTable* thisSymbolTable = jsCast<SymbolTable*>(thisCell); + if (!thisSymbolTable->m_watchpointCleanup) { + thisSymbolTable->m_watchpointCleanup = + std::make_unique<WatchpointCleanup>(thisSymbolTable); + } - visitor.append(&thisSymbolTable->m_arguments); - visitor.append(&thisSymbolTable->m_singletonScope); - - // Save some memory. This is O(n) to rebuild and we do so on the fly. - ConcurrentJITLocker locker(thisSymbolTable->m_lock); - thisSymbolTable->m_localToEntry = nullptr; + visitor.addUnconditionalFinalizer(thisSymbolTable->m_watchpointCleanup.get()); } -const SymbolTable::LocalToEntryVec& SymbolTable::localToEntry(const ConcurrentJITLocker&) +SymbolTable::WatchpointCleanup::WatchpointCleanup(SymbolTable* symbolTable) + : m_symbolTable(symbolTable) { - if (UNLIKELY(!m_localToEntry)) { - unsigned size = 0; - for (auto& entry : m_map) { - VarOffset offset = entry.value.varOffset(); - if (offset.isScope()) - size = std::max(size, offset.scopeOffset().offset() + 1); - } - - m_localToEntry = std::make_unique<LocalToEntryVec>(size, nullptr); - for (auto& entry : m_map) { - VarOffset offset = entry.value.varOffset(); - if (offset.isScope()) - m_localToEntry->at(offset.scopeOffset().offset()) = &entry.value; - } - } - - return *m_localToEntry; } -SymbolTableEntry* SymbolTable::entryFor(const ConcurrentJITLocker& locker, ScopeOffset offset) +SymbolTable::WatchpointCleanup::~WatchpointCleanup() { } + +void SymbolTable::WatchpointCleanup::finalizeUnconditionally() { - auto& toEntryVector = localToEntry(locker); - if (offset.offset() >= toEntryVector.size()) - return nullptr; - return toEntryVector[offset.offset()]; + Map::iterator iter = m_symbolTable->m_map.begin(); + Map::iterator end = m_symbolTable->m_map.end(); + for (; iter != end; ++iter) { + if (VariableWatchpointSet* set = iter->value.watchpointSet()) + set->finalizeUnconditionally(); + } } -SymbolTable* SymbolTable::cloneScopePart(VM& vm) +SymbolTable* SymbolTable::clone(VM& vm) { SymbolTable* result = SymbolTable::create(vm); + result->m_parameterCountIncludingThis = m_parameterCountIncludingThis; result->m_usesNonStrictEval = m_usesNonStrictEval; - result->m_scopeType = m_scopeType; - - for (auto iter = m_map.begin(), end = m_map.end(); iter != end; ++iter) { - if (!iter->value.varOffset().isScope()) - continue; + result->m_captureStart = m_captureStart; + result->m_captureEnd = m_captureEnd; + + Map::iterator iter = m_map.begin(); + Map::iterator end = m_map.end(); + for (; iter != end; ++iter) { result->m_map.add( iter->key, - SymbolTableEntry(iter->value.varOffset(), iter->value.getAttributes())); + SymbolTableEntry(iter->value.getIndex(), iter->value.getAttributes())); } - result->m_maxScopeOffset = m_maxScopeOffset; - - if (ScopedArgumentsTable* arguments = this->arguments()) - result->m_arguments.set(vm, result, arguments); - - if (m_typeProfilingRareData) { - result->m_typeProfilingRareData = std::make_unique<TypeProfilingRareData>(); - - { - auto iter = m_typeProfilingRareData->m_uniqueIDMap.begin(); - auto end = m_typeProfilingRareData->m_uniqueIDMap.end(); - for (; iter != end; ++iter) - result->m_typeProfilingRareData->m_uniqueIDMap.set(iter->key, iter->value); - } - - { - auto iter = m_typeProfilingRareData->m_offsetToVariableMap.begin(); - auto end = m_typeProfilingRareData->m_offsetToVariableMap.end(); - for (; iter != end; ++iter) - result->m_typeProfilingRareData->m_offsetToVariableMap.set(iter->key, iter->value); - } - - { - auto iter = m_typeProfilingRareData->m_uniqueTypeSetMap.begin(); - auto end = m_typeProfilingRareData->m_uniqueTypeSetMap.end(); - for (; iter != end; ++iter) - result->m_typeProfilingRareData->m_uniqueTypeSetMap.set(iter->key, iter->value); - } + if (m_slowArguments) { + result->m_slowArguments = std::make_unique<SlowArgument[]>(parameterCount()); + for (unsigned i = parameterCount(); i--;) + result->m_slowArguments[i] = m_slowArguments[i]; } return result; } -void SymbolTable::prepareForTypeProfiling(const ConcurrentJITLocker&) -{ - if (m_typeProfilingRareData) - return; - - m_typeProfilingRareData = std::make_unique<TypeProfilingRareData>(); - - for (auto iter = m_map.begin(), end = m_map.end(); iter != end; ++iter) { - m_typeProfilingRareData->m_uniqueIDMap.set(iter->key, TypeProfilerNeedsUniqueIDGeneration); - m_typeProfilingRareData->m_offsetToVariableMap.set(iter->value.varOffset(), iter->key); - } -} - -GlobalVariableID SymbolTable::uniqueIDForVariable(const ConcurrentJITLocker&, UniquedStringImpl* key, VM& vm) -{ - RELEASE_ASSERT(m_typeProfilingRareData); - - auto iter = m_typeProfilingRareData->m_uniqueIDMap.find(key); - auto end = m_typeProfilingRareData->m_uniqueIDMap.end(); - if (iter == end) - return TypeProfilerNoGlobalIDExists; - - GlobalVariableID id = iter->value; - if (id == TypeProfilerNeedsUniqueIDGeneration) { - id = vm.typeProfiler()->getNextUniqueVariableID(); - m_typeProfilingRareData->m_uniqueIDMap.set(key, id); - m_typeProfilingRareData->m_uniqueTypeSetMap.set(key, TypeSet::create()); // Make a new global typeset for this corresponding ID. - } - - return id; -} - -GlobalVariableID SymbolTable::uniqueIDForOffset(const ConcurrentJITLocker& locker, VarOffset offset, VM& vm) -{ - RELEASE_ASSERT(m_typeProfilingRareData); - - auto iter = m_typeProfilingRareData->m_offsetToVariableMap.find(offset); - auto end = m_typeProfilingRareData->m_offsetToVariableMap.end(); - if (iter == end) - return TypeProfilerNoGlobalIDExists; - - return uniqueIDForVariable(locker, iter->value.get(), vm); -} - -RefPtr<TypeSet> SymbolTable::globalTypeSetForOffset(const ConcurrentJITLocker& locker, VarOffset offset, VM& vm) -{ - RELEASE_ASSERT(m_typeProfilingRareData); - - uniqueIDForOffset(locker, offset, vm); // Lazily create the TypeSet if necessary. - - auto iter = m_typeProfilingRareData->m_offsetToVariableMap.find(offset); - auto end = m_typeProfilingRareData->m_offsetToVariableMap.end(); - if (iter == end) - return nullptr; - - return globalTypeSetForVariable(locker, iter->value.get(), vm); -} - -RefPtr<TypeSet> SymbolTable::globalTypeSetForVariable(const ConcurrentJITLocker& locker, UniquedStringImpl* key, VM& vm) -{ - RELEASE_ASSERT(m_typeProfilingRareData); - - uniqueIDForVariable(locker, key, vm); // Lazily create the TypeSet if necessary. - - auto iter = m_typeProfilingRareData->m_uniqueTypeSetMap.find(key); - auto end = m_typeProfilingRareData->m_uniqueTypeSetMap.end(); - if (iter == end) - return nullptr; - - return iter->value; -} - } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/SymbolTable.h b/Source/JavaScriptCore/runtime/SymbolTable.h index 990039c1b..6e2c26d68 100644 --- a/Source/JavaScriptCore/runtime/SymbolTable.h +++ b/Source/JavaScriptCore/runtime/SymbolTable.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2012-2015 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 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 @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -30,20 +30,30 @@ #define SymbolTable_h #include "ConcurrentJITLock.h" -#include "ConstantMode.h" -#include "InferredValue.h" #include "JSObject.h" -#include "ScopedArgumentsTable.h" -#include "TypeLocation.h" -#include "VarOffset.h" -#include "Watchpoint.h" +#include "VariableWatchpointSet.h" #include <memory> #include <wtf/HashTraits.h> -#include <wtf/text/UniquedStringImpl.h> +#include <wtf/text/StringImpl.h> namespace JSC { -class SymbolTable; +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. +}; static ALWAYS_INLINE int missingSymbolMarker() { return std::numeric_limits<int>::max(); } @@ -66,36 +76,14 @@ static ALWAYS_INLINE int missingSymbolMarker() { return std::numeric_limits<int> // 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 +// SymbolTableEntry --> FatEntry --> VariableWatchpointSet // // If you make a copy of a SymbolTableEntry, you will have: // -// original: SymbolTableEntry --> FatEntry --> WatchpointSet +// original: SymbolTableEntry --> FatEntry --> VariableWatchpointSet // copy: SymbolTableEntry --> FatEntry -----^ struct SymbolTableEntry { -private: - static VarOffset varOffsetFromBits(intptr_t bits) - { - VarKind kind; - intptr_t kindBits = bits & KindBitsMask; - if (kindBits <= UnwatchableScopeKindBits) - kind = VarKind::Scope; - else if (kindBits == StackKindBits) - kind = VarKind::Stack; - else - kind = VarKind::DirectArgument; - return VarOffset::assemble(kind, static_cast<int>(bits >> FlagBits)); - } - - static ScopeOffset scopeOffsetFromBits(intptr_t bits) - { - ASSERT((bits & KindBitsMask) <= UnwatchableScopeKindBits); - return ScopeOffset(static_cast<int>(bits >> FlagBits)); - } - -public: - // 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 @@ -117,35 +105,22 @@ public: return !(m_bits & ~SlimFlag); } - VarOffset varOffset() const - { - return varOffsetFromBits(m_bits); - } - - // Asserts if the offset is anything but a scope offset. This structures the assertions - // in a way that may result in better code, even in release, than doing - // varOffset().scopeOffset(). - ScopeOffset scopeOffset() const + int getIndex() const { - return scopeOffsetFromBits(m_bits); + return static_cast<int>(m_bits >> FlagBits); } - + bool isReadOnly() const { return m_bits & ReadOnlyFlag; } - bool isDontEnum() const - { - return m_bits & DontEnumFlag; - } - unsigned getAttributes() const { unsigned attributes = 0; - if (isReadOnly()) + if (m_bits & ReadOnlyFlag) attributes |= ReadOnly; - if (isDontEnum()) + if (m_bits & DontEnumFlag) attributes |= DontEnum; return attributes; } @@ -165,18 +140,18 @@ public: { } - SymbolTableEntry(VarOffset offset) + SymbolTableEntry(int index) : m_bits(SlimFlag) { - ASSERT(isValidVarOffset(offset)); - pack(offset, true, false, false); + ASSERT(isValidIndex(index)); + pack(index, false, false); } - SymbolTableEntry(VarOffset offset, unsigned attributes) + SymbolTableEntry(int index, unsigned attributes) : m_bits(SlimFlag) { - ASSERT(isValidVarOffset(offset)); - pack(offset, true, attributes & ReadOnly, attributes & DontEnum); + ASSERT(isValidIndex(index)); + pack(index, attributes & ReadOnly, attributes & DontEnum); } ~SymbolTableEntry() @@ -204,22 +179,9 @@ public: return !(bits() & ~SlimFlag); } - VarOffset varOffset() const - { - return varOffsetFromBits(bits()); - } - - bool isWatchable() const - { - return (m_bits & KindBitsMask) == ScopeKindBits; - } - - // Asserts if the offset is anything but a scope offset. This structures the assertions - // in a way that may result in better code, even in release, than doing - // varOffset().scopeOffset(). - ScopeOffset scopeOffset() const + int getIndex() const { - return scopeOffsetFromBits(bits()); + return static_cast<int>(bits() >> FlagBits); } ALWAYS_INLINE Fast getFast() const @@ -242,10 +204,10 @@ public: { return getFast().getAttributes(); } - + void setAttributes(unsigned attributes) { - pack(varOffset(), isWatchable(), attributes & ReadOnly, attributes & DontEnum); + pack(getIndex(), attributes & ReadOnly, attributes & DontEnum); } bool isReadOnly() const @@ -253,65 +215,32 @@ public: return bits() & ReadOnlyFlag; } - ConstantMode constantMode() const - { - return modeForIsConstant(isReadOnly()); - } - - bool isDontEnum() const - { - return bits() & DontEnumFlag; - } - - void disableWatching() - { - if (WatchpointSet* set = watchpointSet()) - set->invalidate("Disabling watching in symbol table"); - if (varOffset().isScope()) - pack(varOffset(), false, isReadOnly(), isDontEnum()); - } + JSValue inferredValue(); void prepareToWatch(); void addWatchpoint(Watchpoint*); - // This watchpoint set is initialized clear, and goes through the following state transitions: - // - // First write to this var, in any scope that has this symbol table: Clear->IsWatched. - // - // Second write to this var, in any scope that has this symbol table: IsWatched->IsInvalidated. - // - // We ensure that we touch the set (i.e. trigger its state transition) after we do the write. This - // means that if you're in the compiler thread, and you: - // - // 1) Observe that the set IsWatched and commit to adding your watchpoint. - // 2) Load a value from any scope that has this watchpoint set. - // - // Then you can be sure that that value is either going to be the correct value for that var forever, - // or the watchpoint set will invalidate and you'll get fired. - // - // It's possible to write a program that first creates multiple scopes with the same var, and then - // initializes that var in just one of them. This means that a compilation could constant-fold to one - // of the scopes that still has an undefined value for this variable. That's fine, because at that - // point any write to any of the instances of that variable would fire the watchpoint. - WatchpointSet* watchpointSet() + VariableWatchpointSet* watchpointSet() { if (!isFat()) return 0; return fatEntry()->m_watchpoints.get(); } + ALWAYS_INLINE void notifyWrite(JSValue value) + { + if (LIKELY(!isFat())) + return; + notifyWriteSlow(value); + } + 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 KindBitsMask = 0x30; - static const intptr_t ScopeKindBits = 0x00; - static const intptr_t UnwatchableScopeKindBits = 0x10; - static const intptr_t StackKindBits = 0x20; - static const intptr_t DirectArgumentKindBits = 0x30; - static const intptr_t FlagBits = 6; + static const intptr_t FlagBits = 4; class FatEntry { WTF_MAKE_FAST_ALLOCATED; @@ -323,11 +252,11 @@ private: 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; + RefPtr<VariableWatchpointSet> m_watchpoints; }; SymbolTableEntry& copySlow(const SymbolTableEntry&); - JS_EXPORT_PRIVATE void notifyWriteSlow(VM&, JSValue, const FireDetail&); + JS_EXPORT_PRIVATE void notifyWriteSlow(JSValue); bool isFat() const { @@ -378,38 +307,20 @@ private: JS_EXPORT_PRIVATE void freeFatEntrySlow(); - void pack(VarOffset offset, bool isWatchable, bool readOnly, bool dontEnum) + void pack(int index, bool readOnly, bool dontEnum) { ASSERT(!isFat()); intptr_t& bitsRef = bits(); - bitsRef = - (static_cast<intptr_t>(offset.rawOffset()) << FlagBits) | NotNullFlag | SlimFlag; + bitsRef = (static_cast<intptr_t>(index) << FlagBits) | NotNullFlag | SlimFlag; if (readOnly) bitsRef |= ReadOnlyFlag; if (dontEnum) bitsRef |= DontEnumFlag; - switch (offset.kind()) { - case VarKind::Scope: - if (isWatchable) - bitsRef |= ScopeKindBits; - else - bitsRef |= UnwatchableScopeKindBits; - break; - case VarKind::Stack: - bitsRef |= StackKindBits; - break; - case VarKind::DirectArgument: - bitsRef |= DirectArgumentKindBits; - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - break; - } } - static bool isValidVarOffset(VarOffset offset) + bool isValidIndex(int index) { - return ((static_cast<intptr_t>(offset.rawOffset()) << FlagBits) >> FlagBits) == static_cast<intptr_t>(offset.rawOffset()); + return ((static_cast<intptr_t>(index) << FlagBits) >> FlagBits) == static_cast<intptr_t>(index); } intptr_t m_bits; @@ -419,16 +330,11 @@ struct SymbolTableIndexHashTraits : HashTraits<SymbolTableEntry> { static const bool needsDestruction = true; }; -class SymbolTable final : public JSCell { +class SymbolTable : public JSCell { public: typedef JSCell Base; - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; - typedef HashMap<RefPtr<UniquedStringImpl>, SymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, SymbolTableIndexHashTraits> Map; - typedef HashMap<RefPtr<UniquedStringImpl>, GlobalVariableID, IdentifierRepHash> UniqueIDMap; - typedef HashMap<RefPtr<UniquedStringImpl>, RefPtr<TypeSet>, IdentifierRepHash> UniqueTypeSetMap; - typedef HashMap<VarOffset, RefPtr<UniquedStringImpl>> OffsetToVariableMap; - typedef Vector<SymbolTableEntry*> LocalToEntryVec; + typedef HashMap<RefPtr<StringImpl>, SymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<StringImpl>>, SymbolTableIndexHashTraits> Map; static SymbolTable* create(VM& vm) { @@ -436,50 +342,43 @@ public: symbolTable->finishCreation(vm); return symbolTable; } - - static SymbolTable* createNameScopeTable(VM& vm, const Identifier& ident, unsigned attributes) - { - SymbolTable* result = create(vm); - result->add(ident.impl(), SymbolTableEntry(VarOffset(ScopeOffset(0)), attributes)); - return result; - } - 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(CellType, StructureFlags), info()); + return Structure::create(vm, globalObject, prototype, TypeInfo(LeafType, StructureFlags), info()); } // You must hold the lock until after you're done with the iterator. - Map::iterator find(const ConcurrentJITLocker&, UniquedStringImpl* key) + Map::iterator find(const ConcurrentJITLocker&, StringImpl* key) { return m_map.find(key); } - Map::iterator find(const GCSafeConcurrentJITLocker&, UniquedStringImpl* key) + Map::iterator find(const GCSafeConcurrentJITLocker&, StringImpl* key) { return m_map.find(key); } - SymbolTableEntry get(const ConcurrentJITLocker&, UniquedStringImpl* key) + SymbolTableEntry get(const ConcurrentJITLocker&, StringImpl* key) { return m_map.get(key); } - SymbolTableEntry get(UniquedStringImpl* key) + SymbolTableEntry get(StringImpl* key) { ConcurrentJITLocker locker(m_lock); return get(locker, key); } - SymbolTableEntry inlineGet(const ConcurrentJITLocker&, UniquedStringImpl* key) + SymbolTableEntry inlineGet(const ConcurrentJITLocker&, StringImpl* key) { return m_map.inlineGet(key); } - SymbolTableEntry inlineGet(UniquedStringImpl* key) + SymbolTableEntry inlineGet(StringImpl* key) { ConcurrentJITLocker locker(m_lock); return inlineGet(locker, key); @@ -511,188 +410,100 @@ public: return size(locker); } - ScopeOffset maxScopeOffset() const - { - return m_maxScopeOffset; - } - - void didUseScopeOffset(ScopeOffset offset) - { - if (!m_maxScopeOffset || m_maxScopeOffset < offset) - m_maxScopeOffset = offset; - } - - void didUseVarOffset(VarOffset offset) + Map::AddResult add(const ConcurrentJITLocker&, StringImpl* key, const SymbolTableEntry& entry) { - if (offset.isScope()) - didUseScopeOffset(offset.scopeOffset()); + return m_map.add(key, entry); } - unsigned scopeSize() const - { - ScopeOffset maxScopeOffset = this->maxScopeOffset(); - - // Do some calculation that relies on invalid scope offset plus one being zero. - unsigned fastResult = maxScopeOffset.offsetUnchecked() + 1; - - // Assert that this works. - ASSERT(fastResult == (!maxScopeOffset ? 0 : maxScopeOffset.offset() + 1)); - - return fastResult; - } - - ScopeOffset nextScopeOffset() const - { - return ScopeOffset(scopeSize()); - } - - ScopeOffset takeNextScopeOffset(const ConcurrentJITLocker&) - { - ScopeOffset result = nextScopeOffset(); - m_maxScopeOffset = result; - return result; - } - - ScopeOffset takeNextScopeOffset() - { - ConcurrentJITLocker locker(m_lock); - return takeNextScopeOffset(locker); - } - - void add(const ConcurrentJITLocker&, UniquedStringImpl* key, const SymbolTableEntry& entry) - { - RELEASE_ASSERT(!m_localToEntry); - didUseVarOffset(entry.varOffset()); - Map::AddResult result = m_map.add(key, entry); - ASSERT_UNUSED(result, result.isNewEntry); - } - - void add(UniquedStringImpl* key, const SymbolTableEntry& entry) + void add(StringImpl* key, const SymbolTableEntry& entry) { ConcurrentJITLocker locker(m_lock); add(locker, key, entry); } - void set(const ConcurrentJITLocker&, UniquedStringImpl* key, const SymbolTableEntry& entry) + Map::AddResult set(const ConcurrentJITLocker&, StringImpl* key, const SymbolTableEntry& entry) { - RELEASE_ASSERT(!m_localToEntry); - didUseVarOffset(entry.varOffset()); - m_map.set(key, entry); + return m_map.set(key, entry); } - void set(UniquedStringImpl* key, const SymbolTableEntry& entry) + void set(StringImpl* key, const SymbolTableEntry& entry) { ConcurrentJITLocker locker(m_lock); set(locker, key, entry); } - bool contains(const ConcurrentJITLocker&, UniquedStringImpl* key) + bool contains(const ConcurrentJITLocker&, StringImpl* key) { return m_map.contains(key); } - bool contains(UniquedStringImpl* key) + bool contains(StringImpl* key) { ConcurrentJITLocker locker(m_lock); return contains(locker, key); } - // The principle behind ScopedArgumentsTable modifications is that we will create one and - // leave it unlocked - thereby allowing in-place changes - until someone asks for a pointer to - // the table. Then, we will lock it. Then both our future changes and their future changes - // will first have to make a copy. This discipline means that usually when we create a - // ScopedArguments object, we don't have to make a copy of the ScopedArgumentsTable - instead - // we just take a reference to one that we already have. - - uint32_t argumentsLength() const - { - if (!m_arguments) - return 0; - return m_arguments->length(); - } - - void setArgumentsLength(VM& vm, uint32_t length) - { - if (UNLIKELY(!m_arguments)) - m_arguments.set(vm, this, ScopedArgumentsTable::create(vm)); - m_arguments.set(vm, this, m_arguments->setLength(vm, length)); - } - - ScopeOffset argumentOffset(uint32_t i) const - { - ASSERT_WITH_SECURITY_IMPLICATION(m_arguments); - return m_arguments->get(i); - } - - void setArgumentOffset(VM& vm, uint32_t i, ScopeOffset offset) - { - ASSERT_WITH_SECURITY_IMPLICATION(m_arguments); - m_arguments.set(vm, this, m_arguments->set(vm, i, offset)); - } - - ScopedArgumentsTable* arguments() const - { - if (!m_arguments) - return nullptr; - m_arguments->lock(); - return m_arguments.get(); - } - - const LocalToEntryVec& localToEntry(const ConcurrentJITLocker&); - SymbolTableEntry* entryFor(const ConcurrentJITLocker&, ScopeOffset); - - GlobalVariableID uniqueIDForVariable(const ConcurrentJITLocker&, UniquedStringImpl* key, VM&); - GlobalVariableID uniqueIDForOffset(const ConcurrentJITLocker&, VarOffset, VM&); - RefPtr<TypeSet> globalTypeSetForOffset(const ConcurrentJITLocker&, VarOffset, VM&); - RefPtr<TypeSet> globalTypeSetForVariable(const ConcurrentJITLocker&, UniquedStringImpl* key, VM&); - bool usesNonStrictEval() { return m_usesNonStrictEval; } void setUsesNonStrictEval(bool usesNonStrictEval) { m_usesNonStrictEval = usesNonStrictEval; } - enum ScopeType { - VarScope, - LexicalScope, - CatchScope, - FunctionNameScope - }; - void setScopeType(ScopeType type) { m_scopeType = type; } - ScopeType scopeType() const { return static_cast<ScopeType>(m_scopeType); } + int captureStart() const { return m_captureStart; } + void setCaptureStart(int captureStart) { m_captureStart = captureStart; } + + int captureEnd() const { return m_captureEnd; } + void setCaptureEnd(int captureEnd) { m_captureEnd = captureEnd; } + + int captureCount() const { return -(m_captureEnd - m_captureStart); } + + bool isCaptured(int operand) + { + return operand <= captureStart() && operand > captureEnd(); + } - SymbolTable* cloneScopePart(VM&); + int parameterCount() { return m_parameterCountIncludingThis - 1; } + int parameterCountIncludingThis() { return m_parameterCountIncludingThis; } + void setParameterCountIncludingThis(int parameterCountIncludingThis) { m_parameterCountIncludingThis = parameterCountIncludingThis; } - void prepareForTypeProfiling(const ConcurrentJITLocker&); + // 0 if we don't capture any arguments; parameterCount() in length if we do. + const SlowArgument* slowArguments() { return m_slowArguments.get(); } + void setSlowArguments(std::unique_ptr<SlowArgument[]> slowArguments) { m_slowArguments = std::move(slowArguments); } - InferredValue* singletonScope() { return m_singletonScope.get(); } + SymbolTable* clone(VM&); static void visitChildren(JSCell*, SlotVisitor&); DECLARE_EXPORT_INFO; private: + class WatchpointCleanup : public UnconditionalFinalizer { + public: + WatchpointCleanup(SymbolTable*); + virtual ~WatchpointCleanup(); + + protected: + virtual void finalizeUnconditionally() override; + + private: + SymbolTable* m_symbolTable; + }; + JS_EXPORT_PRIVATE SymbolTable(VM&); ~SymbolTable(); - - JS_EXPORT_PRIVATE void finishCreation(VM&); Map m_map; - ScopeOffset m_maxScopeOffset; - struct TypeProfilingRareData { - UniqueIDMap m_uniqueIDMap; - OffsetToVariableMap m_offsetToVariableMap; - UniqueTypeSetMap m_uniqueTypeSetMap; - }; - std::unique_ptr<TypeProfilingRareData> m_typeProfilingRareData; + int m_parameterCountIncludingThis; + bool m_usesNonStrictEval; - bool m_usesNonStrictEval : 1; - unsigned m_scopeType : 2; // ScopeType - - WriteBarrier<ScopedArgumentsTable> m_arguments; - WriteBarrier<InferredValue> m_singletonScope; + int m_captureStart; + int m_captureEnd; + + std::unique_ptr<SlowArgument[]> m_slowArguments; - std::unique_ptr<LocalToEntryVec> m_localToEntry; + std::unique_ptr<WatchpointCleanup> m_watchpointCleanup; public: + InlineWatchpointSet m_functionEnteredOnce; + mutable ConcurrentJITLock m_lock; }; diff --git a/Source/JavaScriptCore/runtime/TemplateRegistry.cpp b/Source/JavaScriptCore/runtime/TemplateRegistry.cpp deleted file mode 100644 index 7bdac38e3..000000000 --- a/Source/JavaScriptCore/runtime/TemplateRegistry.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. - * - * 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 "TemplateRegistry.h" - -#include "JSCJSValueInlines.h" -#include "JSGlobalObject.h" -#include "ObjectConstructor.h" -#include "StructureInlines.h" -#include "WeakGCMapInlines.h" - -namespace JSC { - -TemplateRegistry::TemplateRegistry(VM& vm) - : m_templateMap(vm) -{ -} - -JSArray* TemplateRegistry::getTemplateObject(ExecState* exec, const TemplateRegistryKey& templateKey) -{ - JSArray* cached = m_templateMap.get(templateKey); - if (cached) - return cached; - - unsigned count = templateKey.cookedStrings().size(); - JSArray* templateObject = constructEmptyArray(exec, nullptr, count); - JSArray* rawObject = constructEmptyArray(exec, nullptr, count); - - for (unsigned index = 0; index < count; ++index) { - templateObject->putDirectIndex(exec, index, jsString(exec, templateKey.cookedStrings()[index]), ReadOnly | DontDelete, PutDirectIndexLikePutDirect); - rawObject->putDirectIndex(exec, index, jsString(exec, templateKey.rawStrings()[index]), ReadOnly | DontDelete, PutDirectIndexLikePutDirect); - } - - objectConstructorFreeze(exec, rawObject); - ASSERT(!exec->hadException()); - - templateObject->putDirect(exec->vm(), exec->propertyNames().raw, rawObject, ReadOnly | DontEnum | DontDelete); - - objectConstructorFreeze(exec, templateObject); - ASSERT(!exec->hadException()); - - m_templateMap.set(templateKey, templateObject); - - return templateObject; -} - - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/TemplateRegistry.h b/Source/JavaScriptCore/runtime/TemplateRegistry.h deleted file mode 100644 index 9cb62ddfd..000000000 --- a/Source/JavaScriptCore/runtime/TemplateRegistry.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. - * - * 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 TemplateRegistry_h -#define TemplateRegistry_h - -#include "JSArray.h" -#include "TemplateRegistryKey.h" -#include "WeakGCMap.h" -#include <limits> - -namespace JSC { - -class TemplateRegistry { -public: - TemplateRegistry(VM&); - - JSArray* getTemplateObject(ExecState*, const TemplateRegistryKey&); - -private: - WeakGCMap<TemplateRegistryKey, JSArray> m_templateMap; -}; - -} // namespace JSC - -#endif // TemplateRegistry_h diff --git a/Source/JavaScriptCore/runtime/TemplateRegistryKey.h b/Source/JavaScriptCore/runtime/TemplateRegistryKey.h deleted file mode 100644 index 17d882884..000000000 --- a/Source/JavaScriptCore/runtime/TemplateRegistryKey.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. - * - * 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 TemplateRegistryKey_h -#define TemplateRegistryKey_h - -#include <limits> -#include <wtf/Vector.h> -#include <wtf/text/StringHash.h> -#include <wtf/text/WTFString.h> - -namespace JSC { - -class TemplateRegistryKey { -public: - typedef Vector<String, 4> StringVector; - - TemplateRegistryKey(const StringVector& rawStrings, const StringVector& cookedStrings); - enum DeletedValueTag { DeletedValue }; - TemplateRegistryKey(DeletedValueTag); - enum EmptyValueTag { EmptyValue }; - TemplateRegistryKey(EmptyValueTag); - - bool isDeletedValue() const { return m_rawStrings.isEmpty() && m_hash == std::numeric_limits<unsigned>::max(); } - - bool isEmptyValue() const { return m_rawStrings.isEmpty() && !m_hash; } - - unsigned hash() const { return m_hash; } - - const StringVector& rawStrings() const { return m_rawStrings; } - const StringVector& cookedStrings() const { return m_cookedStrings; } - - bool operator==(const TemplateRegistryKey& other) const { return m_hash == other.m_hash && m_rawStrings == other.m_rawStrings; } - bool operator!=(const TemplateRegistryKey& other) const { return m_hash != other.m_hash || m_rawStrings != other.m_rawStrings; } - - struct Hasher { - static unsigned hash(const TemplateRegistryKey& key) { return key.hash(); } - static bool equal(const TemplateRegistryKey& a, const TemplateRegistryKey& b) { return a == b; } - static const bool safeToCompareToEmptyOrDeleted = false; - }; - -private: - StringVector m_rawStrings; - StringVector m_cookedStrings; - unsigned m_hash { 0 }; -}; - -inline TemplateRegistryKey::TemplateRegistryKey(const StringVector& rawStrings, const StringVector& cookedStrings) - : m_rawStrings(rawStrings) - , m_cookedStrings(cookedStrings) -{ - m_hash = 0; - for (const String& string : rawStrings) - m_hash += WTF::StringHash::hash(string); -} - -inline TemplateRegistryKey::TemplateRegistryKey(DeletedValueTag) - : m_hash(std::numeric_limits<unsigned>::max()) -{ -} - -inline TemplateRegistryKey::TemplateRegistryKey(EmptyValueTag) - : m_hash(0) -{ -} - -} // namespace JSC - -namespace WTF { -template<typename T> struct DefaultHash; - -template<> struct DefaultHash<JSC::TemplateRegistryKey> { - typedef JSC::TemplateRegistryKey::Hasher Hash; -}; - -template<> struct HashTraits<JSC::TemplateRegistryKey> : CustomHashTraits<JSC::TemplateRegistryKey> { -}; - -} // namespace WTF - -#endif // TemplateRegistryKey_h diff --git a/Source/JavaScriptCore/runtime/TestRunnerUtils.cpp b/Source/JavaScriptCore/runtime/TestRunnerUtils.cpp index 3c5dac7a0..337c00e6e 100644 --- a/Source/JavaScriptCore/runtime/TestRunnerUtils.cpp +++ b/Source/JavaScriptCore/runtime/TestRunnerUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * 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 @@ -27,11 +27,11 @@ #include "TestRunnerUtils.h" #include "CodeBlock.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { -FunctionExecutable* getExecutableForFunction(JSValue theFunctionValue) +static FunctionExecutable* getExecutable(JSValue theFunctionValue) { JSFunction* theFunction = jsDynamicCast<JSFunction*>(theFunctionValue); if (!theFunction) @@ -42,20 +42,6 @@ FunctionExecutable* getExecutableForFunction(JSValue theFunctionValue) return executable; } -CodeBlock* getSomeBaselineCodeBlockForFunction(JSValue theFunctionValue) -{ - FunctionExecutable* executable = getExecutableForFunction(theFunctionValue); - if (!executable) - return 0; - - CodeBlock* baselineCodeBlock = executable->baselineCodeBlockFor(CodeForCall); - - if (!baselineCodeBlock) - baselineCodeBlock = executable->baselineCodeBlockFor(CodeForConstruct); - - return baselineCodeBlock; -} - JSValue numberOfDFGCompiles(JSValue theFunctionValue) { bool pretendToHaveManyCompiles = false; @@ -65,36 +51,32 @@ JSValue numberOfDFGCompiles(JSValue theFunctionValue) #else pretendToHaveManyCompiles = true; #endif + + if (FunctionExecutable* executable = getExecutable(theFunctionValue)) { + CodeBlock* baselineCodeBlock = executable->baselineCodeBlockFor(CodeForCall); + + if (!baselineCodeBlock) + baselineCodeBlock = executable->baselineCodeBlockFor(CodeForConstruct); + + if (!baselineCodeBlock) + return jsNumber(0); - if (CodeBlock* baselineCodeBlock = getSomeBaselineCodeBlockForFunction(theFunctionValue)) { if (pretendToHaveManyCompiles) return jsNumber(1000000.0); return jsNumber(baselineCodeBlock->numberOfDFGCompiles()); } - return jsNumber(0); + return jsUndefined(); } JSValue setNeverInline(JSValue theFunctionValue) { - if (FunctionExecutable* executable = getExecutableForFunction(theFunctionValue)) + if (FunctionExecutable* executable = getExecutable(theFunctionValue)) executable->setNeverInline(true); return jsUndefined(); } -JSValue optimizeNextInvocation(JSValue theFunctionValue) -{ -#if ENABLE(JIT) - if (CodeBlock* baselineCodeBlock = getSomeBaselineCodeBlockForFunction(theFunctionValue)) - baselineCodeBlock->optimizeNextInvocation(); -#else - UNUSED_PARAM(theFunctionValue); -#endif - - return jsUndefined(); -} - JSValue numberOfDFGCompiles(ExecState* exec) { if (exec->argumentCount() < 1) @@ -109,12 +91,5 @@ JSValue setNeverInline(ExecState* exec) return setNeverInline(exec->uncheckedArgument(0)); } -JSValue optimizeNextInvocation(ExecState* exec) -{ - if (exec->argumentCount() < 1) - return jsUndefined(); - return optimizeNextInvocation(exec->uncheckedArgument(0)); -} - } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/TestRunnerUtils.h b/Source/JavaScriptCore/runtime/TestRunnerUtils.h index ffb843897..5ee87ac2c 100644 --- a/Source/JavaScriptCore/runtime/TestRunnerUtils.h +++ b/Source/JavaScriptCore/runtime/TestRunnerUtils.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2015 Apple Inc. All rights reserved. + * 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 @@ -30,24 +30,11 @@ namespace JSC { -class CodeBlock; -class FunctionExecutable; - -JS_EXPORT_PRIVATE FunctionExecutable* getExecutableForFunction(JSValue theFunctionValue); -JS_EXPORT_PRIVATE CodeBlock* getSomeBaselineCodeBlockForFunction(JSValue theFunctionValue); - JS_EXPORT_PRIVATE JSValue numberOfDFGCompiles(JSValue function); JS_EXPORT_PRIVATE JSValue setNeverInline(JSValue function); -JS_EXPORT_PRIVATE JSValue optimizeNextInvocation(JSValue function); JS_EXPORT_PRIVATE JSValue numberOfDFGCompiles(ExecState*); JS_EXPORT_PRIVATE JSValue setNeverInline(ExecState*); -JS_EXPORT_PRIVATE JSValue optimizeNextInvocation(ExecState*); - -JS_EXPORT_PRIVATE unsigned numberOfExceptionFuzzChecks(); -JS_EXPORT_PRIVATE unsigned numberOfExecutableAllocationFuzzChecks(); -JS_EXPORT_PRIVATE unsigned numberOfStaticOSRExitFuzzChecks(); -JS_EXPORT_PRIVATE unsigned numberOfOSRExitFuzzChecks(); } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Tracing.d b/Source/JavaScriptCore/runtime/Tracing.d deleted file mode 100644 index ec13625d8..000000000 --- a/Source/JavaScriptCore/runtime/Tracing.d +++ /dev/null @@ -1,40 +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. - * - * 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. - */ - -provider JavaScriptCore -{ - probe gc__begin(); - probe gc__marked(); - probe gc__end(); - - probe profile__will_execute(int, char*, char*, int, int); - probe profile__did_execute(int, char*, char*, int, int); -}; - -#pragma D attributes Unstable/Unstable/Common provider JavaScriptCore provider -#pragma D attributes Private/Private/Unknown provider JavaScriptCore module -#pragma D attributes Private/Private/Unknown provider JavaScriptCore function -#pragma D attributes Unstable/Unstable/Common provider JavaScriptCore name -#pragma D attributes Unstable/Unstable/Common provider JavaScriptCore args diff --git a/Source/JavaScriptCore/runtime/Tracing.h b/Source/JavaScriptCore/runtime/Tracing.h index 69ead921c..c28c85f61 100644 --- a/Source/JavaScriptCore/runtime/Tracing.h +++ b/Source/JavaScriptCore/runtime/Tracing.h @@ -39,10 +39,10 @@ #define JAVASCRIPTCORE_GC_MARKED() #define JAVASCRIPTCORE_GC_MARKED_ENABLED() 0 -#define JAVASCRIPTCORE_PROFILE_WILL_EXECUTE(arg0, arg1, arg2, arg3, arg4) +#define JAVASCRIPTCORE_PROFILE_WILL_EXECUTE(arg0, arg1, arg2, arg3) #define JAVASCRIPTCORE_PROFILE_WILL_EXECUTE_ENABLED() 0 -#define JAVASCRIPTCORE_PROFILE_DID_EXECUTE(arg0, arg1, arg2, arg3, arg4) +#define JAVASCRIPTCORE_PROFILE_DID_EXECUTE(arg0, arg1, arg2, arg3) #define JAVASCRIPTCORE_PROFILE_DID_EXECUTE_ENABLED() 0 #endif diff --git a/Source/JavaScriptCore/runtime/TypeLocationCache.cpp b/Source/JavaScriptCore/runtime/TypeLocationCache.cpp deleted file mode 100644 index 4c8069a8c..000000000 --- a/Source/JavaScriptCore/runtime/TypeLocationCache.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2014 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 "TypeLocationCache.h" - -#include "TypeProfiler.h" -#include "VM.h" - -namespace JSC { - -std::pair<TypeLocation*, bool> TypeLocationCache::getTypeLocation(GlobalVariableID globalVariableID, intptr_t sourceID, unsigned start, unsigned end, PassRefPtr<TypeSet> globalTypeSet, VM* vm) -{ - LocationKey key; - key.m_globalVariableID = globalVariableID; - key.m_sourceID = sourceID; - key.m_start = start; - key.m_end = end; - - bool isNewLocation = false; - if (m_locationMap.find(key) == m_locationMap.end()) { - ASSERT(vm->typeProfiler()); - TypeLocation* location = vm->typeProfiler()->nextTypeLocation(); - location->m_globalVariableID = globalVariableID; - location->m_sourceID = sourceID; - location->m_divotStart = start; - location->m_divotEnd = end; - location->m_globalTypeSet = globalTypeSet; - - m_locationMap[key] = location; - isNewLocation = true; - } - - TypeLocation* location = m_locationMap.find(key)->second; - return std::pair<TypeLocation*, bool>(location, isNewLocation); -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/TypeLocationCache.h b/Source/JavaScriptCore/runtime/TypeLocationCache.h deleted file mode 100644 index 9f856666c..000000000 --- a/Source/JavaScriptCore/runtime/TypeLocationCache.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2014 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 TypeLocationCache_h -#define TypeLocationCache_h - -#include "TypeLocation.h" -#include <unordered_map> -#include <wtf/HashMethod.h> - -namespace JSC { - -class VM; - -class TypeLocationCache { -public: - struct LocationKey { - LocationKey() {} - bool operator==(const LocationKey& other) const - { - return m_globalVariableID == other.m_globalVariableID - && m_sourceID == other.m_sourceID - && m_start == other.m_start - && m_end == other.m_end; - } - - unsigned hash() const - { - return m_globalVariableID + m_sourceID + m_start + m_end; - } - - GlobalVariableID m_globalVariableID; - intptr_t m_sourceID; - unsigned m_start; - unsigned m_end; - }; - - std::pair<TypeLocation*, bool> getTypeLocation(GlobalVariableID, intptr_t, unsigned start, unsigned end, PassRefPtr<TypeSet>, VM*); -private: - typedef std::unordered_map<LocationKey, TypeLocation*, HashMethod<LocationKey>> LocationMap; - LocationMap m_locationMap; -}; - -} // namespace JSC - -#endif // TypeLocationCache_h diff --git a/Source/JavaScriptCore/runtime/TypeProfiler.cpp b/Source/JavaScriptCore/runtime/TypeProfiler.cpp deleted file mode 100644 index 338a1c219..000000000 --- a/Source/JavaScriptCore/runtime/TypeProfiler.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) 2014 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 "TypeProfiler.h" - -#include "InspectorProtocolObjects.h" -#include "TypeLocation.h" -#include <wtf/text/StringBuilder.h> - -namespace JSC { - -static const bool verbose = false; - -TypeProfiler::TypeProfiler() - : m_nextUniqueVariableID(1) -{ -} - -void TypeProfiler::logTypesForTypeLocation(TypeLocation* location, VM& vm) -{ - TypeProfilerSearchDescriptor descriptor = location->m_globalVariableID == TypeProfilerReturnStatement ? TypeProfilerSearchDescriptorFunctionReturn : TypeProfilerSearchDescriptorNormal; - - dataLogF("[Start, End]::[%u, %u]\n", location->m_divotStart, location->m_divotEnd); - - if (findLocation(location->m_divotStart, location->m_sourceID, descriptor, vm)) - dataLog("\t\t[Entry IS in System]\n"); - else - dataLog("\t\t[Entry IS NOT in system]\n"); - - dataLog("\t\t", location->m_globalVariableID == TypeProfilerReturnStatement ? "[Return Statement]" : "[Normal Statement]", "\n"); - - dataLog("\t\t#Local#\n\t\t", location->m_instructionTypeSet->dumpTypes().replace("\n", "\n\t\t"), "\n"); - if (location->m_globalTypeSet) - dataLog("\t\t#Global#\n\t\t", location->m_globalTypeSet->dumpTypes().replace("\n", "\n\t\t"), "\n"); -} - -void TypeProfiler::insertNewLocation(TypeLocation* location) -{ - if (verbose) - dataLogF("Registering location:: divotStart:%u, divotEnd:%u\n", location->m_divotStart, location->m_divotEnd); - - if (!m_bucketMap.contains(location->m_sourceID)) { - Vector<TypeLocation*> bucket; - m_bucketMap.set(location->m_sourceID, bucket); - } - - Vector<TypeLocation*>& bucket = m_bucketMap.find(location->m_sourceID)->value; - bucket.append(location); -} - -String TypeProfiler::typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptor descriptor, unsigned offset, intptr_t sourceID, VM& vm) -{ - // This returns a JSON string representing an Object with the following properties: - // globalTypeSet: 'JSON<TypeSet> | null' - // instructionTypeSet: 'JSON<TypeSet>' - - TypeLocation* location = findLocation(offset, sourceID, descriptor, vm); - ASSERT(location); - - StringBuilder json; - - json.append('{'); - - json.appendLiteral("\"globalTypeSet\":"); - if (location->m_globalTypeSet && location->m_globalVariableID != TypeProfilerNoGlobalIDExists) - json.append(location->m_globalTypeSet->toJSONString()); - else - json.appendLiteral("null"); - json.append(','); - - json.appendLiteral("\"instructionTypeSet\":"); - json.append(location->m_instructionTypeSet->toJSONString()); - json.append(','); - - json.appendLiteral("\"isOverflown\":"); - if (location->m_instructionTypeSet->isOverflown() || (location->m_globalTypeSet && location->m_globalTypeSet->isOverflown())) - json.appendLiteral("true"); - else - json.appendLiteral("false"); - - json.append('}'); - - return json.toString(); -} - -TypeLocation* TypeProfiler::findLocation(unsigned divot, intptr_t sourceID, TypeProfilerSearchDescriptor descriptor, VM& vm) -{ - QueryKey queryKey(sourceID, divot); - auto iter = m_queryCache.find(queryKey); - if (iter != m_queryCache.end()) - return iter->value; - - if (!vm.functionHasExecutedCache()->hasExecutedAtOffset(sourceID, divot)) - return nullptr; - - if (!m_bucketMap.contains(sourceID)) - return nullptr; - - Vector<TypeLocation*>& bucket = m_bucketMap.find(sourceID)->value; - TypeLocation* bestMatch = nullptr; - unsigned distance = UINT_MAX; // Because assignments may be nested, make sure we find the closest enclosing assignment to this character offset. - for (size_t i = 0, size = bucket.size(); i < size; i++) { - TypeLocation* location = bucket.at(i); - // We found the type location that correlates to the convergence of all return statements in a function. - // This text offset is the offset of the opening brace in a function declaration. - if (descriptor == TypeProfilerSearchDescriptorFunctionReturn && location->m_globalVariableID == TypeProfilerReturnStatement && location->m_divotForFunctionOffsetIfReturnStatement == divot) - return location; - - if (descriptor != TypeProfilerSearchDescriptorFunctionReturn && location->m_divotStart <= divot && divot <= location->m_divotEnd && location->m_divotEnd - location->m_divotStart <= distance) { - distance = location->m_divotEnd - location->m_divotStart; - bestMatch = location; - } - } - - if (bestMatch) - m_queryCache.set(queryKey, bestMatch); - // FIXME: BestMatch should never be null past this point. This doesn't hold currently because we ignore var assignments when code contains eval/With (VarInjection). - // https://bugs.webkit.org/show_bug.cgi?id=135184 - return bestMatch; -} - -TypeLocation* TypeProfiler::nextTypeLocation() -{ - return m_typeLocationInfo.add(); -} - -void TypeProfiler::invalidateTypeSetCache() -{ - for (Bag<TypeLocation>::iterator iter = m_typeLocationInfo.begin(); !!iter; ++iter) { - TypeLocation* location = *iter; - location->m_instructionTypeSet->invalidateCache(); - if (location->m_globalTypeSet) - location->m_globalTypeSet->invalidateCache(); - } -} - -void TypeProfiler::dumpTypeProfilerData(VM& vm) -{ - for (Bag<TypeLocation>::iterator iter = m_typeLocationInfo.begin(); !!iter; ++iter) { - TypeLocation* location = *iter; - logTypesForTypeLocation(location, vm); - } -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/TypeProfiler.h b/Source/JavaScriptCore/runtime/TypeProfiler.h deleted file mode 100644 index 6b27bd4c3..000000000 --- a/Source/JavaScriptCore/runtime/TypeProfiler.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2014 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 TypeProfiler_h -#define TypeProfiler_h - -#include "CodeBlock.h" -#include "TypeLocation.h" -#include "TypeLocationCache.h" -#include <wtf/Bag.h> -#include <wtf/HashMap.h> -#include <wtf/Vector.h> -#include <wtf/text/WTFString.h> - -namespace Inspector { namespace Protocol { namespace Runtime { -class TypeDescription; -}}} - -namespace JSC { - -struct QueryKey { - QueryKey() - : m_sourceID(0) - , m_divot(0) - { } - - QueryKey(intptr_t sourceID, unsigned divot) - : m_sourceID(sourceID) - , m_divot(divot) - { } - - QueryKey(WTF::HashTableDeletedValueType) - : m_sourceID(INTPTR_MAX) - , m_divot(UINT_MAX) - { } - - bool isHashTableDeletedValue() const { return m_sourceID == INTPTR_MAX && m_divot == UINT_MAX; } - bool operator==(const QueryKey& other) const { return m_sourceID == other.m_sourceID && m_divot == other.m_divot; } - unsigned hash() const { return m_sourceID + m_divot; } - - intptr_t m_sourceID; - unsigned m_divot; -}; - -struct QueryKeyHash { - static unsigned hash(const QueryKey& key) { return key.hash(); } - static bool equal(const QueryKey& a, const QueryKey& b) { return a == b; } - static const bool safeToCompareToEmptyOrDeleted = true; -}; - -} // namespace JSC - -namespace WTF { - -template<typename T> struct DefaultHash; -template<> struct DefaultHash<JSC::QueryKey> { - typedef JSC::QueryKeyHash Hash; -}; - -template<typename T> struct HashTraits; -template<> struct HashTraits<JSC::QueryKey> : SimpleClassHashTraits<JSC::QueryKey> { }; - -} // namespace WTF - -namespace JSC { - -class VM; - -enum TypeProfilerSearchDescriptor { - TypeProfilerSearchDescriptorNormal = 1, - TypeProfilerSearchDescriptorFunctionReturn = 2 -}; - -class TypeProfiler { - WTF_MAKE_FAST_ALLOCATED; -public: - TypeProfiler(); - void logTypesForTypeLocation(TypeLocation*, VM&); - JS_EXPORT_PRIVATE String typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptor, unsigned offset, intptr_t sourceID, VM&); - void insertNewLocation(TypeLocation*); - TypeLocationCache* typeLocationCache() { return &m_typeLocationCache; } - TypeLocation* findLocation(unsigned divot, intptr_t sourceID, TypeProfilerSearchDescriptor, VM&); - GlobalVariableID getNextUniqueVariableID() { return m_nextUniqueVariableID++; } - TypeLocation* nextTypeLocation(); - void invalidateTypeSetCache(); - void dumpTypeProfilerData(VM&); - -private: - typedef HashMap<intptr_t, Vector<TypeLocation*>> SourceIDToLocationBucketMap; - SourceIDToLocationBucketMap m_bucketMap; - TypeLocationCache m_typeLocationCache; - typedef HashMap<QueryKey, TypeLocation*> TypeLocationQueryCache; - TypeLocationQueryCache m_queryCache; - GlobalVariableID m_nextUniqueVariableID; - Bag<TypeLocation> m_typeLocationInfo; -}; - -} // namespace JSC - -#endif // TypeProfiler_h diff --git a/Source/JavaScriptCore/runtime/TypeProfilerLog.cpp b/Source/JavaScriptCore/runtime/TypeProfilerLog.cpp deleted file mode 100644 index 9d10aae88..000000000 --- a/Source/JavaScriptCore/runtime/TypeProfilerLog.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2014 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 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 "TypeProfilerLog.h" - -#include "JSCJSValueInlines.h" -#include "TypeLocation.h" -#include <wtf/CurrentTime.h> - - -namespace JSC { - -static const bool verbose = false; - -void TypeProfilerLog::initializeLog() -{ - ASSERT(!m_logStartPtr); - m_logSize = 50000; - m_logStartPtr = new LogEntry[m_logSize]; - m_currentLogEntryPtr = m_logStartPtr; - m_logEndPtr = m_logStartPtr + m_logSize; -} - -TypeProfilerLog::~TypeProfilerLog() -{ - delete[] m_logStartPtr; -} - -void TypeProfilerLog::processLogEntries(const String& reason) -{ - double before = 0; - if (verbose) { - dataLog("Process caller:'", reason, "'"); - before = currentTimeMS(); - } - - LogEntry* entry = m_logStartPtr; - HashMap<Structure*, RefPtr<StructureShape>> seenShapes; - while (entry != m_currentLogEntryPtr) { - StructureID id = entry->structureID; - RefPtr<StructureShape> shape; - JSValue value = entry->value; - Structure* structure = nullptr; - if (id) { - structure = Heap::heap(value.asCell())->structureIDTable().get(id); - auto iter = seenShapes.find(structure); - if (iter == seenShapes.end()) { - shape = structure->toStructureShape(value); - seenShapes.set(structure, shape); - } else - shape = iter->value; - } - - RuntimeType type = runtimeTypeForValue(value); - TypeLocation* location = entry->location; - location->m_lastSeenType = type; - if (location->m_globalTypeSet) - location->m_globalTypeSet->addTypeInformation(type, shape, structure); - location->m_instructionTypeSet->addTypeInformation(type, shape, structure); - - entry++; - } - - m_currentLogEntryPtr = m_logStartPtr; - - if (verbose) { - double after = currentTimeMS(); - dataLogF(" Processing the log took: '%f' ms\n", after - before); - } -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/TypeSet.cpp b/Source/JavaScriptCore/runtime/TypeSet.cpp deleted file mode 100644 index a436cda13..000000000 --- a/Source/JavaScriptCore/runtime/TypeSet.cpp +++ /dev/null @@ -1,587 +0,0 @@ -/* - * Copyright (C) 2014, 2015 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 "TypeSet.h" - -#include "InspectorProtocolObjects.h" -#include "JSCJSValue.h" -#include "JSCJSValueInlines.h" -#include <wtf/text/CString.h> -#include <wtf/text/WTFString.h> -#include <wtf/text/StringBuilder.h> -#include <wtf/Vector.h> - -namespace JSC { - -TypeSet::TypeSet() - : m_seenTypes(TypeNothing) - , m_isOverflown(false) -{ -} - -void TypeSet::addTypeInformation(RuntimeType type, PassRefPtr<StructureShape> prpNewShape, Structure* structure) -{ - RefPtr<StructureShape> newShape = prpNewShape; - m_seenTypes = m_seenTypes | type; - - if (structure && newShape && !runtimeTypeIsPrimitive(type)) { - if (!m_structureSet.contains(structure)) { - m_structureSet.add(structure); - // Make one more pass making sure that: - // - We don't have two instances of the same shape. (Same shapes may have different Structures). - // - We don't have two shapes that share the same prototype chain. If these shapes share the same - // prototype chain, they will be merged into one shape. - bool found = false; - String hash = newShape->propertyHash(); - for (size_t i = 0; i < m_structureHistory.size(); i++) { - RefPtr<StructureShape>& seenShape = m_structureHistory.at(i); - if (seenShape->propertyHash() == hash) { - found = true; - break; - } - if (seenShape->hasSamePrototypeChain(newShape)) { - seenShape = StructureShape::merge(seenShape, newShape); - found = true; - break; - } - } - - if (!found) { - if (m_structureHistory.size() < 100) - m_structureHistory.append(newShape); - else if (!m_isOverflown) - m_isOverflown = true; - } - } - } -} - -void TypeSet::invalidateCache() -{ - auto keepMarkedStructuresFilter = [] (Structure* structure) -> bool { return Heap::isMarked(structure); }; - m_structureSet.genericFilter(keepMarkedStructuresFilter); -} - -String TypeSet::dumpTypes() const -{ - if (m_seenTypes == TypeNothing) - return ASCIILiteral("(Unreached Statement)"); - - StringBuilder seen; - - if (m_seenTypes & TypeFunction) - seen.appendLiteral("Function "); - if (m_seenTypes & TypeUndefined) - seen.appendLiteral("Undefined "); - if (m_seenTypes & TypeNull) - seen.appendLiteral("Null "); - if (m_seenTypes & TypeBoolean) - seen.appendLiteral("Boolean "); - if (m_seenTypes & TypeMachineInt) - seen.appendLiteral("MachineInt "); - if (m_seenTypes & TypeNumber) - seen.appendLiteral("Number "); - if (m_seenTypes & TypeString) - seen.appendLiteral("String "); - if (m_seenTypes & TypeObject) - seen.appendLiteral("Object "); - if (m_seenTypes & TypeSymbol) - seen.appendLiteral("Symbol "); - - for (size_t i = 0; i < m_structureHistory.size(); i++) { - RefPtr<StructureShape> shape = m_structureHistory.at(i); - seen.append(shape->m_constructorName); - seen.append(' '); - } - - if (m_structureHistory.size()) - seen.appendLiteral("\nStructures:[ "); - for (size_t i = 0; i < m_structureHistory.size(); i++) { - seen.append(m_structureHistory.at(i)->stringRepresentation()); - seen.append(' '); - } - if (m_structureHistory.size()) - seen.append(']'); - - if (m_structureHistory.size()) { - seen.appendLiteral("\nLeast Common Ancestor: "); - seen.append(leastCommonAncestor()); - } - - return seen.toString(); -} - -bool TypeSet::doesTypeConformTo(RuntimeTypeMask test) const -{ - // This function checks if our seen types conform to the types described by the test bitstring. (i.e we haven't seen more types than test). - // We are <= to those types if ANDing with the bitstring doesn't zero out any of our bits. - - // For example: - - // 0b0110 (seen) - // 0b1111 (test) - // ------ (AND) - // 0b0110 == seen - - // 0b0110 (seen) - // 0b0010 (test) - // ------ (AND) - // 0b0010 != seen - - return m_seenTypes != TypeNothing && (m_seenTypes & test) == m_seenTypes; -} - -String TypeSet::displayName() const -{ - if (m_seenTypes == TypeNothing) - return emptyString(); - - if (m_structureHistory.size() && doesTypeConformTo(TypeObject | TypeNull | TypeUndefined)) { - String ctorName = leastCommonAncestor(); - - if (doesTypeConformTo(TypeObject)) - return ctorName; - if (doesTypeConformTo(TypeObject | TypeNull | TypeUndefined)) - return ctorName + '?'; - } - - // The order of these checks are important. For example, if a value is only a function, it conforms to TypeFunction, but it also conforms to TypeFunction | TypeNull. - // Therefore, more specific types must be checked first. - - if (doesTypeConformTo(TypeFunction)) - return ASCIILiteral("Function"); - if (doesTypeConformTo(TypeUndefined)) - return ASCIILiteral("Undefined"); - if (doesTypeConformTo(TypeNull)) - return ASCIILiteral("Null"); - if (doesTypeConformTo(TypeBoolean)) - return ASCIILiteral("Boolean"); - if (doesTypeConformTo(TypeMachineInt)) - return ASCIILiteral("Integer"); - if (doesTypeConformTo(TypeNumber | TypeMachineInt)) - return ASCIILiteral("Number"); - if (doesTypeConformTo(TypeString)) - return ASCIILiteral("String"); - if (doesTypeConformTo(TypeSymbol)) - return ASCIILiteral("Symbol"); - - if (doesTypeConformTo(TypeNull | TypeUndefined)) - return ASCIILiteral("(?)"); - - if (doesTypeConformTo(TypeFunction | TypeNull | TypeUndefined)) - return ASCIILiteral("Function?"); - if (doesTypeConformTo(TypeBoolean | TypeNull | TypeUndefined)) - return ASCIILiteral("Boolean?"); - if (doesTypeConformTo(TypeMachineInt | TypeNull | TypeUndefined)) - return ASCIILiteral("Integer?"); - if (doesTypeConformTo(TypeNumber | TypeMachineInt | TypeNull | TypeUndefined)) - return ASCIILiteral("Number?"); - if (doesTypeConformTo(TypeString | TypeNull | TypeUndefined)) - return ASCIILiteral("String?"); - if (doesTypeConformTo(TypeSymbol | TypeNull | TypeUndefined)) - return ASCIILiteral("Symbol?"); - - if (doesTypeConformTo(TypeObject | TypeFunction | TypeString)) - return ASCIILiteral("Object"); - if (doesTypeConformTo(TypeObject | TypeFunction | TypeString | TypeNull | TypeUndefined)) - return ASCIILiteral("Object?"); - - return ASCIILiteral("(many)"); -} - -String TypeSet::leastCommonAncestor() const -{ - return StructureShape::leastCommonAncestor(m_structureHistory); -} - -Ref<Inspector::Protocol::Array<Inspector::Protocol::Runtime::StructureDescription>> TypeSet::allStructureRepresentations() const -{ - auto description = Inspector::Protocol::Array<Inspector::Protocol::Runtime::StructureDescription>::create(); - - for (size_t i = 0; i < m_structureHistory.size(); i++) - description->addItem(m_structureHistory.at(i)->inspectorRepresentation()); - - return WTF::move(description); -} - -Ref<Inspector::Protocol::Runtime::TypeSet> TypeSet::inspectorTypeSet() const -{ - return Inspector::Protocol::Runtime::TypeSet::create() - .setIsFunction((m_seenTypes & TypeFunction) != TypeNothing) - .setIsUndefined((m_seenTypes & TypeUndefined) != TypeNothing) - .setIsNull((m_seenTypes & TypeNull) != TypeNothing) - .setIsBoolean((m_seenTypes & TypeBoolean) != TypeNothing) - .setIsInteger((m_seenTypes & TypeMachineInt) != TypeNothing) - .setIsNumber((m_seenTypes & TypeNumber) != TypeNothing) - .setIsString((m_seenTypes & TypeString) != TypeNothing) - .setIsObject((m_seenTypes & TypeObject) != TypeNothing) - .setIsSymbol((m_seenTypes & TypeSymbol) != TypeNothing) - .release(); -} - -String TypeSet::toJSONString() const -{ - // This returns a JSON string representing an Object with the following properties: - // displayTypeName: 'String' - // primitiveTypeNames: 'Array<String>' - // structures: 'Array<JSON<StructureShape>>' - - StringBuilder json; - json.append('{'); - - json.appendLiteral("\"displayTypeName\":"); - json.append('"'); - json.append(displayName()); - json.append('"'); - json.append(','); - - json.appendLiteral("\"primitiveTypeNames\":"); - json.append('['); - bool hasAnItem = false; - if (m_seenTypes & TypeUndefined) { - hasAnItem = true; - json.appendLiteral("\"Undefined\""); - } - if (m_seenTypes & TypeNull) { - if (hasAnItem) - json.append(','); - hasAnItem = true; - json.appendLiteral("\"Null\""); - } - if (m_seenTypes & TypeBoolean) { - if (hasAnItem) - json.append(','); - hasAnItem = true; - json.appendLiteral("\"Boolean\""); - } - if (m_seenTypes & TypeMachineInt) { - if (hasAnItem) - json.append(','); - hasAnItem = true; - json.appendLiteral("\"Integer\""); - } - if (m_seenTypes & TypeNumber) { - if (hasAnItem) - json.append(','); - hasAnItem = true; - json.appendLiteral("\"Number\""); - } - if (m_seenTypes & TypeString) { - if (hasAnItem) - json.append(','); - hasAnItem = true; - json.appendLiteral("\"String\""); - } - if (m_seenTypes & TypeSymbol) { - if (hasAnItem) - json.append(','); - hasAnItem = true; - json.appendLiteral("\"Symbol\""); - } - json.append(']'); - - json.append(','); - - json.appendLiteral("\"structures\":"); - json.append('['); - hasAnItem = false; - for (size_t i = 0; i < m_structureHistory.size(); i++) { - if (hasAnItem) - json.append(','); - hasAnItem = true; - json.append(m_structureHistory[i]->toJSONString()); - } - json.append(']'); - - json.append('}'); - return json.toString(); -} - -StructureShape::StructureShape() - : m_proto(nullptr) - , m_propertyHash(nullptr) - , m_final(false) - , m_isInDictionaryMode(false) -{ -} - -void StructureShape::markAsFinal() -{ - ASSERT(!m_final); - m_final = true; -} - -void StructureShape::addProperty(UniquedStringImpl& uid) -{ - ASSERT(!m_final); - m_fields.add(&uid); -} - -String StructureShape::propertyHash() -{ - ASSERT(m_final); - if (m_propertyHash) - return *m_propertyHash; - - StringBuilder builder; - builder.append(':'); - builder.append(m_constructorName); - builder.append(':'); - for (auto& key : m_fields) { - String property = key.get(); - property.replace(":", "\\:"); // Ensure that hash({"foo:", "bar"}) != hash({"foo", ":bar"}) because we're using colons as a separator and colons are legal characters in field names in JS. - builder.append(property); - } - - if (m_proto) { - builder.append(':'); - builder.appendLiteral("__proto__"); - builder.append(m_proto->propertyHash()); - } - - m_propertyHash = std::make_unique<String>(builder.toString()); - return *m_propertyHash; -} - -String StructureShape::leastCommonAncestor(const Vector<RefPtr<StructureShape>> shapes) -{ - if (!shapes.size()) - return emptyString(); - - RefPtr<StructureShape> origin = shapes.at(0); - for (size_t i = 1; i < shapes.size(); i++) { - bool foundLUB = false; - while (!foundLUB) { - RefPtr<StructureShape> check = shapes.at(i); - String curCtorName = origin->m_constructorName; - while (check) { - if (check->m_constructorName == curCtorName) { - foundLUB = true; - break; - } - check = check->m_proto; - } - if (!foundLUB) { - origin = origin->m_proto; - // All Objects must share the 'Object' Prototype. Therefore, at the very least, we should always converge on 'Object' before reaching a null prototype. - RELEASE_ASSERT(origin); - } - } - - if (origin->m_constructorName == "Object") - break; - } - - return origin->m_constructorName; -} - -String StructureShape::stringRepresentation() -{ - StringBuilder representation; - RefPtr<StructureShape> curShape = this; - - representation.append('{'); - while (curShape) { - for (auto it = curShape->m_fields.begin(), end = curShape->m_fields.end(); it != end; ++it) { - String prop((*it).get()); - representation.append(prop); - representation.appendLiteral(", "); - } - - if (curShape->m_proto) { - representation.appendLiteral("__proto__ ["); - representation.append(curShape->m_proto->m_constructorName); - representation.appendLiteral("], "); - } - - curShape = curShape->m_proto; - } - - if (representation.length() >= 3) - representation.resize(representation.length() - 2); - - representation.append('}'); - - return representation.toString(); -} - -String StructureShape::toJSONString() const -{ - // This returns a JSON string representing an Object with the following properties: - // constructorName: 'String' - // fields: 'Array<String>' - // optionalFields: 'Array<String>' - // proto: 'JSON<StructureShape> | null' - - StringBuilder json; - json.append('{'); - - json.appendLiteral("\"constructorName\":"); - json.append('"'); - json.append(m_constructorName); - json.append('"'); - json.append(','); - - json.appendLiteral("\"isInDictionaryMode\":"); - if (m_isInDictionaryMode) - json.appendLiteral("true"); - else - json.appendLiteral("false"); - json.append(','); - - json.appendLiteral("\"fields\":"); - json.append('['); - bool hasAnItem = false; - for (auto it = m_fields.begin(), end = m_fields.end(); it != end; ++it) { - if (hasAnItem) - json.append(','); - hasAnItem = true; - - String fieldName((*it).get()); - json.append('"'); - json.append(fieldName); - json.append('"'); - } - json.append(']'); - json.append(','); - - json.appendLiteral("\"optionalFields\":"); - json.append('['); - hasAnItem = false; - for (auto it = m_optionalFields.begin(), end = m_optionalFields.end(); it != end; ++it) { - if (hasAnItem) - json.append(','); - hasAnItem = true; - - String fieldName((*it).get()); - json.append('"'); - json.append(fieldName); - json.append('"'); - } - json.append(']'); - json.append(','); - - json.appendLiteral("\"proto\":"); - if (m_proto) - json.append(m_proto->toJSONString()); - else - json.appendLiteral("null"); - - json.append('}'); - - return json.toString(); -} - -Ref<Inspector::Protocol::Runtime::StructureDescription> StructureShape::inspectorRepresentation() -{ - auto base = Inspector::Protocol::Runtime::StructureDescription::create().release(); - Ref<Inspector::Protocol::Runtime::StructureDescription> currentObject = base.copyRef(); - RefPtr<StructureShape> currentShape(this); - - while (currentShape) { - auto fields = Inspector::Protocol::Array<String>::create(); - auto optionalFields = Inspector::Protocol::Array<String>::create(); - for (auto field : currentShape->m_fields) - fields->addItem(field.get()); - for (auto field : currentShape->m_optionalFields) - optionalFields->addItem(field.get()); - - currentObject->setFields(&fields.get()); - currentObject->setOptionalFields(&optionalFields.get()); - currentObject->setConstructorName(currentShape->m_constructorName); - currentObject->setIsImprecise(currentShape->m_isInDictionaryMode); - - if (currentShape->m_proto) { - auto nextObject = Inspector::Protocol::Runtime::StructureDescription::create().release(); - currentObject->setPrototypeStructure(&nextObject.get()); - currentObject = WTF::move(nextObject); - } - - currentShape = currentShape->m_proto; - } - - return WTF::move(base); -} - -bool StructureShape::hasSamePrototypeChain(PassRefPtr<StructureShape> prpOther) -{ - RefPtr<StructureShape> self = this; - RefPtr<StructureShape> other = prpOther; - while (self && other) { - if (self->m_constructorName != other->m_constructorName) - return false; - self = self->m_proto; - other = other->m_proto; - } - - return !self && !other; -} - -PassRefPtr<StructureShape> StructureShape::merge(const PassRefPtr<StructureShape> prpA, const PassRefPtr<StructureShape> prpB) -{ - RefPtr<StructureShape> a = prpA; - RefPtr<StructureShape> b = prpB; - ASSERT(a->hasSamePrototypeChain(b)); - - RefPtr<StructureShape> merged = StructureShape::create(); - for (auto field : a->m_fields) { - if (b->m_fields.contains(field)) - merged->m_fields.add(field); - else - merged->m_optionalFields.add(field); - } - - for (auto field : b->m_fields) { - if (!merged->m_fields.contains(field)) { - auto addResult = merged->m_optionalFields.add(field); - ASSERT_UNUSED(addResult, addResult.isNewEntry); - } - } - - for (auto field : a->m_optionalFields) - merged->m_optionalFields.add(field); - for (auto field : b->m_optionalFields) - merged->m_optionalFields.add(field); - - ASSERT(a->m_constructorName == b->m_constructorName); - merged->setConstructorName(a->m_constructorName); - - if (a->m_proto) { - RELEASE_ASSERT(b->m_proto); - merged->setProto(StructureShape::merge(a->m_proto, b->m_proto)); - } - - merged->markAsFinal(); - - return merged.release(); -} - -void StructureShape::enterDictionaryMode() -{ - m_isInDictionaryMode = true; -} - -} //namespace JSC diff --git a/Source/JavaScriptCore/runtime/TypeSet.h b/Source/JavaScriptCore/runtime/TypeSet.h deleted file mode 100644 index eb29e6c5f..000000000 --- a/Source/JavaScriptCore/runtime/TypeSet.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2008, 2014 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 TypeSet_h -#define TypeSet_h - -#include "RuntimeType.h" -#include "StructureSet.h" -#include <wtf/HashSet.h> -#include <wtf/RefCounted.h> -#include <wtf/text/WTFString.h> -#include <wtf/Vector.h> - -namespace Inspector { -namespace Protocol { -template<typename T> class Array; - -namespace Runtime { -class StructureDescription; -class TypeSet; -} - -} -} - -namespace JSC { - -class StructureShape : public RefCounted<StructureShape> { - friend class TypeSet; - -public: - StructureShape(); - - static Ref<StructureShape> create() { return adoptRef(*new StructureShape); } - String propertyHash(); - void markAsFinal(); - void addProperty(UniquedStringImpl&); - String stringRepresentation(); - String toJSONString() const; - Ref<Inspector::Protocol::Runtime::StructureDescription> inspectorRepresentation(); - void setConstructorName(String name) { m_constructorName = (name.isEmpty() ? "Object" : name); } - String constructorName() { return m_constructorName; } - void setProto(PassRefPtr<StructureShape> shape) { m_proto = shape; } - void enterDictionaryMode(); - -private: - static String leastCommonAncestor(const Vector<RefPtr<StructureShape>>); - static PassRefPtr<StructureShape> merge(const PassRefPtr<StructureShape>, const PassRefPtr<StructureShape>); - bool hasSamePrototypeChain(PassRefPtr<StructureShape>); - - HashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash> m_fields; - HashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash> m_optionalFields; - RefPtr<StructureShape> m_proto; - std::unique_ptr<String> m_propertyHash; - String m_constructorName; - bool m_final; - bool m_isInDictionaryMode; -}; - -class TypeSet : public RefCounted<TypeSet> { - -public: - static Ref<TypeSet> create() { return adoptRef(*new TypeSet); } - TypeSet(); - void addTypeInformation(RuntimeType, PassRefPtr<StructureShape>, Structure*); - void invalidateCache(); - String dumpTypes() const; - String displayName() const; - Ref<Inspector::Protocol::Array<Inspector::Protocol::Runtime::StructureDescription>> allStructureRepresentations() const; - String toJSONString() const; - bool isOverflown() const { return m_isOverflown; } - String leastCommonAncestor() const; - Ref<Inspector::Protocol::Runtime::TypeSet> inspectorTypeSet() const; - bool isEmpty() const { return m_seenTypes == TypeNothing; } - bool doesTypeConformTo(RuntimeTypeMask test) const; - RuntimeTypeMask seenTypes() const { return m_seenTypes; } - StructureSet structureSet() const { return m_structureSet; }; - -private: - RuntimeTypeMask m_seenTypes; - bool m_isOverflown; - Vector<RefPtr<StructureShape>> m_structureHistory; - StructureSet m_structureSet; -}; - -} //namespace JSC - -#endif //TypeSet_h diff --git a/Source/JavaScriptCore/runtime/TypedArrayAdaptors.h b/Source/JavaScriptCore/runtime/TypedArrayAdaptors.h index d4dc53557..84d3db5e1 100644 --- a/Source/JavaScriptCore/runtime/TypedArrayAdaptors.h +++ b/Source/JavaScriptCore/runtime/TypedArrayAdaptors.h @@ -89,7 +89,9 @@ struct FloatTypedArrayAdaptor { static JSValue toJSValue(Type value) { - return jsDoubleNumber(purifyNaN(value)); + if (value != value) + return jsDoubleNumber(QNaN); + return jsDoubleNumber(value); } static double toDouble(Type value) diff --git a/Source/JavaScriptCore/runtime/TypedArrayBase.h b/Source/JavaScriptCore/runtime/TypedArrayBase.h index ee2746d78..4fe7a6c1a 100644 --- a/Source/JavaScriptCore/runtime/TypedArrayBase.h +++ b/Source/JavaScriptCore/runtime/TypedArrayBase.h @@ -11,10 +11,10 @@ * 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 + * 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 INC. OR + * 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 @@ -94,7 +94,7 @@ protected: RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(length, sizeof(T)); if (!buffer.get()) return 0; - return create<Subclass>(buffer.release(), 0, length); + return create<Subclass>(buffer, 0, length); } template <class Subclass> @@ -104,30 +104,30 @@ protected: if (a) for (unsigned i = 0; i < length; ++i) a->set(i, array[i]); - return a.release(); + return a; } template <class Subclass> - static RefPtr<Subclass> create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length) + static PassRefPtr<Subclass> create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length) { RefPtr<ArrayBuffer> buf(buffer); if (!verifySubRange<T>(buf, byteOffset, length)) - return nullptr; + return 0; - return adoptRef(new Subclass(buf.release(), byteOffset, length)); + return adoptRef(new Subclass(buf, byteOffset, length)); } template <class Subclass> - static RefPtr<Subclass> createUninitialized(unsigned length) + static PassRefPtr<Subclass> createUninitialized(unsigned length) { RefPtr<ArrayBuffer> buffer = ArrayBuffer::createUninitialized(length, sizeof(T)); if (!buffer.get()) - return nullptr; - return create<Subclass>(buffer.release(), 0, length); + return 0; + return create<Subclass>(buffer, 0, length); } template <class Subclass> - RefPtr<Subclass> subarrayImpl(int start, int end) const + PassRefPtr<Subclass> subarrayImpl(int start, int end) const { unsigned offset, length; calculateOffsetAndLength(start, end, m_length, &offset, &length); diff --git a/Source/JavaScriptCore/runtime/TypedArrayType.cpp b/Source/JavaScriptCore/runtime/TypedArrayType.cpp index 60875a209..46d505137 100644 --- a/Source/JavaScriptCore/runtime/TypedArrayType.cpp +++ b/Source/JavaScriptCore/runtime/TypedArrayType.cpp @@ -10,10 +10,10 @@ * 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 + * 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 INC. OR + * 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 @@ -32,37 +32,34 @@ namespace JSC { -JSType typeForTypedArrayType(TypedArrayType type) +const ClassInfo* classInfoForType(TypedArrayType type) { switch (type) { case NotTypedArray: - RELEASE_ASSERT_NOT_REACHED(); - return UnspecifiedType; + return 0; case TypeInt8: - return Int8ArrayType; + return JSInt8Array::info(); case TypeUint8: - return Uint8ArrayType; + return JSUint8Array::info(); case TypeUint8Clamped: - return Uint8ClampedArrayType; + return JSUint8ClampedArray::info(); case TypeInt16: - return Int16ArrayType; + return JSInt16Array::info(); case TypeUint16: - return Uint16ArrayType; + return JSUint16Array::info(); case TypeInt32: - return Int32ArrayType; + return JSInt32Array::info(); case TypeUint32: - return Uint32ArrayType; + return JSUint32Array::info(); case TypeFloat32: - return Float32ArrayType; + return JSFloat32Array::info(); case TypeFloat64: - return Float64ArrayType; + return JSFloat64Array::info(); case TypeDataView: - return DataViewType; - - default: - RELEASE_ASSERT_NOT_REACHED(); - return UnspecifiedType; + return JSDataView::info(); } + RELEASE_ASSERT_NOT_REACHED(); + return 0; } const ClassInfo* constructorClassInfoForType(TypedArrayType type) diff --git a/Source/JavaScriptCore/runtime/TypedArrayType.h b/Source/JavaScriptCore/runtime/TypedArrayType.h index 3a08eebf6..ae3e5a88c 100644 --- a/Source/JavaScriptCore/runtime/TypedArrayType.h +++ b/Source/JavaScriptCore/runtime/TypedArrayType.h @@ -10,10 +10,10 @@ * 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 + * 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 INC. OR + * 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 @@ -26,7 +26,6 @@ #ifndef TypedArrayType_h #define TypedArrayType_h -#include "JSType.h" #include <wtf/PrintStream.h> namespace JSC { @@ -101,8 +100,8 @@ inline size_t elementSize(TypedArrayType type) return static_cast<size_t>(1) << logElementSize(type); } +const ClassInfo* classInfoForType(TypedArrayType); const ClassInfo* constructorClassInfoForType(TypedArrayType); -JSType typeForTypedArrayType(TypedArrayType); inline bool isInt(TypedArrayType type) { diff --git a/Source/JavaScriptCore/runtime/TypeofType.cpp b/Source/JavaScriptCore/runtime/TypeofType.cpp deleted file mode 100644 index db162b7f4..000000000 --- a/Source/JavaScriptCore/runtime/TypeofType.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2015 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 "TypeofType.h" - -namespace WTF { - -using namespace JSC; - -void printInternal(PrintStream& out, TypeofType type) -{ - switch (type) { - case TypeofType::Undefined: - out.print("undefined"); - return; - case TypeofType::Boolean: - out.print("boolean"); - return; - case TypeofType::Number: - out.print("number"); - return; - case TypeofType::String: - out.print("string"); - return; - case TypeofType::Symbol: - out.print("symbol"); - return; - case TypeofType::Object: - out.print("object"); - return; - case TypeofType::Function: - out.print("function"); - return; - } - - RELEASE_ASSERT_NOT_REACHED(); -} - -} // namespace WTF - diff --git a/Source/JavaScriptCore/runtime/TypeofType.h b/Source/JavaScriptCore/runtime/TypeofType.h deleted file mode 100644 index 3eb78d4f9..000000000 --- a/Source/JavaScriptCore/runtime/TypeofType.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2015 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 TypeofType_h -#define TypeofType_h - -#include <wtf/PrintStream.h> - -namespace JSC { - -enum class TypeofType { - Undefined, - Boolean, - Number, - String, - Symbol, - Object, - Function -}; - -} // namespace JSC - -namespace WTF { - -void printInternal(PrintStream& out, JSC::TypeofType); - -} // namespace WTF - -#endif // TypeofType_h - diff --git a/Source/JavaScriptCore/runtime/VM.cpp b/Source/JavaScriptCore/runtime/VM.cpp index 9724575cc..d7e50ed61 100644 --- a/Source/JavaScriptCore/runtime/VM.cpp +++ b/Source/JavaScriptCore/runtime/VM.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2011, 2013-2015 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 @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -30,19 +30,15 @@ #include "VM.h" #include "ArgList.h" -#include "ArityCheckFailReturnThunks.h" #include "ArrayBufferNeuteringWatchpoint.h" -#include "BuiltinExecutables.h" +#include "CallFrameInlines.h" #include "CodeBlock.h" #include "CodeCache.h" #include "CommonIdentifiers.h" -#include "CommonSlowPaths.h" -#include "CustomGetterSetter.h" #include "DFGLongLivedState.h" #include "DFGWorklist.h" -#include "Disassembler.h" +#include "DebuggerActivation.h" #include "ErrorInstance.h" -#include "Exception.h" #include "FTLThunks.h" #include "FunctionConstructor.h" #include "GCActivityCallback.h" @@ -53,49 +49,36 @@ #include "Identifier.h" #include "IncrementalSweeper.h" #include "Interpreter.h" -#include "JITCode.h" #include "JSAPIValueWrapper.h" +#include "JSActivation.h" #include "JSArray.h" -#include "JSCInlines.h" #include "JSFunction.h" #include "JSGlobalObjectFunctions.h" -#include "JSLexicalEnvironment.h" #include "JSLock.h" +#include "JSNameScope.h" #include "JSNotAnObject.h" #include "JSPromiseDeferred.h" -#include "JSPropertyNameEnumerator.h" -#include "JSTemplateRegistryKey.h" +#include "JSPromiseReaction.h" +#include "JSPropertyNameIterator.h" #include "JSWithScope.h" #include "Lexer.h" #include "Lookup.h" #include "MapData.h" #include "Nodes.h" -#include "Parser.h" -#include "ProfilerDatabase.h" -#include "PropertyMapHashTable.h" +#include "ParserArena.h" #include "RegExpCache.h" #include "RegExpObject.h" -#include "RuntimeType.h" #include "SimpleTypedArrayController.h" #include "SourceProviderCache.h" -#include "StackVisitor.h" #include "StrictEvalActivation.h" #include "StrongInlines.h" -#include "StructureInlines.h" -#include "TypeProfiler.h" -#include "TypeProfilerLog.h" #include "UnlinkedCodeBlock.h" -#include "Watchdog.h" -#include "WeakGCMapInlines.h" #include "WeakMapData.h" -#include <wtf/CurrentTime.h> #include <wtf/ProcessID.h> #include <wtf/RetainPtr.h> #include <wtf/StringPrintStream.h> #include <wtf/Threading.h> #include <wtf/WTFThreadData.h> -#include <wtf/text/AtomicStringTable.h> -#include <wtf/text/SymbolRegistry.h> #if ENABLE(DFG_JIT) #include "ConservativeRoots.h" @@ -113,6 +96,28 @@ using namespace WTF; namespace JSC { +extern const HashTable arrayConstructorTable; +extern const HashTable arrayPrototypeTable; +extern const HashTable booleanPrototypeTable; +extern const HashTable jsonTable; +extern const HashTable dataViewTable; +extern const HashTable dateTable; +extern const HashTable dateConstructorTable; +extern const HashTable errorPrototypeTable; +extern const HashTable globalObjectTable; +extern const HashTable numberConstructorTable; +extern const HashTable numberPrototypeTable; +JS_EXPORTDATA extern const HashTable objectConstructorTable; +extern const HashTable privateNamePrototypeTable; +extern const HashTable regExpTable; +extern const HashTable regExpConstructorTable; +extern const HashTable regExpPrototypeTable; +extern const HashTable stringConstructorTable; +#if ENABLE(PROMISES) +extern const HashTable promisePrototypeTable; +extern const HashTable promiseConstructorTable; +#endif + // Note: Platform.h will enforce that ENABLE(ASSEMBLER) is true if either // ENABLE(JIT) or ENABLE(YARR_JIT) or both are enabled. The code below // just checks for ENABLE(JIT) or ENABLE(YARR_JIT) with this premise in mind. @@ -129,6 +134,20 @@ static bool enableAssembler(ExecutableAllocator& executableAllocator) return false; } +#if USE(CF) +#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)); + CFStringRef canUseJITKey = canUseJITKeyRetain.get(); +#else + CFStringRef canUseJITKey = CFSTR("JavaScriptCoreUseJIT"); +#endif // COMPILER(GCC) && !COMPILER(CLANG) + RetainPtr<CFTypeRef> canUseJIT = adoptCF(CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication)); + if (canUseJIT) + return kCFBooleanTrue == canUseJIT.get(); +#endif + #if USE(CF) || OS(UNIX) char* canUseJITString = getenv("JavaScriptCoreUseJIT"); return !canUseJITString || atoi(canUseJITString); @@ -146,13 +165,33 @@ VM::VM(VMType vmType, HeapType heapType) , heap(this, heapType) , vmType(vmType) , clientData(0) - , topVMEntryFrame(nullptr) , topCallFrame(CallFrame::noCaller()) - , m_atomicStringTable(vmType == Default ? wtfThreadData().atomicStringTable() : new AtomicStringTable) - , propertyNames(nullptr) + , arrayConstructorTable(adoptPtr(new HashTable(JSC::arrayConstructorTable))) + , arrayPrototypeTable(adoptPtr(new HashTable(JSC::arrayPrototypeTable))) + , booleanPrototypeTable(adoptPtr(new HashTable(JSC::booleanPrototypeTable))) + , dataViewTable(adoptPtr(new HashTable(JSC::dataViewTable))) + , dateTable(adoptPtr(new HashTable(JSC::dateTable))) + , dateConstructorTable(adoptPtr(new HashTable(JSC::dateConstructorTable))) + , errorPrototypeTable(adoptPtr(new HashTable(JSC::errorPrototypeTable))) + , globalObjectTable(adoptPtr(new HashTable(JSC::globalObjectTable))) + , jsonTable(adoptPtr(new HashTable(JSC::jsonTable))) + , numberConstructorTable(adoptPtr(new HashTable(JSC::numberConstructorTable))) + , numberPrototypeTable(adoptPtr(new HashTable(JSC::numberPrototypeTable))) + , objectConstructorTable(adoptPtr(new HashTable(JSC::objectConstructorTable))) + , privateNamePrototypeTable(adoptPtr(new HashTable(JSC::privateNamePrototypeTable))) + , regExpTable(adoptPtr(new HashTable(JSC::regExpTable))) + , regExpConstructorTable(adoptPtr(new HashTable(JSC::regExpConstructorTable))) + , regExpPrototypeTable(adoptPtr(new HashTable(JSC::regExpPrototypeTable))) + , stringConstructorTable(adoptPtr(new HashTable(JSC::stringConstructorTable))) +#if ENABLE(PROMISES) + , promisePrototypeTable(adoptPtr(new HashTable(JSC::promisePrototypeTable))) + , promiseConstructorTable(adoptPtr(new HashTable(JSC::promiseConstructorTable))) +#endif + , identifierTable(vmType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable()) + , propertyNames(new CommonIdentifiers(this)) , emptyList(new MarkedArgumentBuffer) - , stringCache(*this) - , prototypeMap(*this) + , parserArena(adoptPtr(new ParserArena)) + , keywords(adoptPtr(new Keywords(*this))) , interpreter(0) , jsArrayClassInfo(JSArray::info()) , jsFinalObjectClassInfo(JSFinalObject::info()) @@ -162,6 +201,7 @@ VM::VM(VMType vmType, HeapType heapType) #if ENABLE(REGEXP_TRACING) , m_rtTraceList(new RTTraceList()) #endif + , exclusiveThread(0) , m_newStringsSinceLastHashCons(0) #if ENABLE(ASSEMBLER) , m_canUseAssembler(enableAssembler(executableAllocator)) @@ -175,43 +215,29 @@ VM::VM(VMType vmType, HeapType heapType) #if ENABLE(GC_VALIDATION) , m_initializingObjectClass(0) #endif - , m_stackPointerAtVMEntry(0) , m_stackLimit(0) -#if !ENABLE(JIT) +#if USE(SEPARATE_C_AND_JS_STACK) , m_jsStackLimit(0) #endif -#if ENABLE(FTL_JIT) - , m_ftlStackLimit(0) - , m_largestFTLStackSize(0) -#endif , m_inDefineOwnProperty(false) - , m_codeCache(std::make_unique<CodeCache>()) + , m_codeCache(CodeCache::create()) , m_enabledProfiler(nullptr) - , m_builtinExecutables(std::make_unique<BuiltinExecutables>(*this)) - , m_typeProfilerEnabledCount(0) - , m_controlFlowProfilerEnabledCount(0) { interpreter = new Interpreter(*this); StackBounds stack = wtfThreadData().stack(); - updateReservedZoneSize(Options::reservedZoneSize()); -#if !ENABLE(JIT) - interpreter->stack().setReservedZoneSize(Options::reservedZoneSize()); -#endif - setLastStackTop(stack.origin()); + setStackLimit(stack.recursionLimit()); // Need to be careful to keep everything consistent here JSLockHolder lock(this); - AtomicStringTable* existingEntryAtomicStringTable = wtfThreadData().setCurrentAtomicStringTable(m_atomicStringTable); - propertyNames = new CommonIdentifiers(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())); terminatedExecutionErrorStructure.set(*this, TerminatedExecutionError::createStructure(*this, 0, jsNull())); stringStructure.set(*this, JSString::createStructure(*this, 0, jsNull())); notAnObjectStructure.set(*this, JSNotAnObject::createStructure(*this, 0, jsNull())); - propertyNameEnumeratorStructure.set(*this, JSPropertyNameEnumerator::createStructure(*this, 0, jsNull())); + propertyNameIteratorStructure.set(*this, JSPropertyNameIterator::createStructure(*this, 0, jsNull())); getterSetterStructure.set(*this, GetterSetter::createStructure(*this, 0, jsNull())); - customGetterSetterStructure.set(*this, CustomGetterSetter::createStructure(*this, 0, jsNull())); - scopedArgumentsTableStructure.set(*this, ScopedArgumentsTable::createStructure(*this, 0, jsNull())); apiWrapperStructure.set(*this, JSAPIValueWrapper::createStructure(*this, 0, jsNull())); JSScopeStructure.set(*this, JSScope::createStructure(*this, 0, jsNull())); executableStructure.set(*this, ExecutableBase::createStructure(*this, 0, jsNull())); @@ -220,32 +246,28 @@ VM::VM(VMType vmType, HeapType heapType) programExecutableStructure.set(*this, ProgramExecutable::createStructure(*this, 0, jsNull())); functionExecutableStructure.set(*this, FunctionExecutable::createStructure(*this, 0, jsNull())); regExpStructure.set(*this, RegExp::createStructure(*this, 0, jsNull())); - symbolStructure.set(*this, Symbol::createStructure(*this, 0, jsNull())); symbolTableStructure.set(*this, SymbolTable::createStructure(*this, 0, jsNull())); structureChainStructure.set(*this, StructureChain::createStructure(*this, 0, jsNull())); sparseArrayValueMapStructure.set(*this, SparseArrayValueMap::createStructure(*this, 0, jsNull())); - templateRegistryKeyStructure.set(*this, JSTemplateRegistryKey::createStructure(*this, 0, jsNull())); arrayBufferNeuteringWatchpointStructure.set(*this, ArrayBufferNeuteringWatchpoint::createStructure(*this)); + withScopeStructure.set(*this, JSWithScope::createStructure(*this, 0, jsNull())); unlinkedFunctionExecutableStructure.set(*this, UnlinkedFunctionExecutable::createStructure(*this, 0, jsNull())); 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())); + mapDataStructure.set(*this, MapData::createStructure(*this, 0, jsNull())); weakMapDataStructure.set(*this, WeakMapData::createStructure(*this, 0, jsNull())); - inferredValueStructure.set(*this, InferredValue::createStructure(*this, 0, jsNull())); - functionRareDataStructure.set(*this, FunctionRareData::createStructure(*this, 0, jsNull())); - exceptionStructure.set(*this, Exception::createStructure(*this, 0, jsNull())); promiseDeferredStructure.set(*this, JSPromiseDeferred::createStructure(*this, 0, jsNull())); + promiseReactionStructure.set(*this, JSPromiseReaction::createStructure(*this, 0, jsNull())); iterationTerminator.set(*this, JSFinalObject::create(*this, JSFinalObject::createStructure(*this, 0, jsNull(), 1))); smallStrings.initializeCommonStrings(*this); - wtfThreadData().setCurrentAtomicStringTable(existingEntryAtomicStringTable); + wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable); #if ENABLE(JIT) - jitStubs = std::make_unique<JITThunks>(); - arityCheckFailReturnThunks = std::make_unique<ArityCheckFailReturnThunks>(); + jitStubs = adoptPtr(new JITThunks()); #endif - arityCheckData = std::make_unique<CommonSlowPaths::ArityCheckData>(); #if ENABLE(FTL_JIT) ftlThunks = std::make_unique<FTL::Thunks>(); @@ -258,39 +280,30 @@ VM::VM(VMType vmType, HeapType heapType) #endif heap.notifyIsSafeToCollect(); - + LLInt::Data::performAssertions(*this); if (Options::enableProfiler()) { - m_perBytecodeProfiler = std::make_unique<Profiler::Database>(*this); + 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()) - dfgState = std::make_unique<DFG::LongLivedState>(); + dfgState = adoptPtr(new DFG::LongLivedState()); #endif // Initialize this last, as a free way of asserting that VM initialization itself // won't use this. m_typedArrayController = adoptRef(new SimpleTypedArrayController()); - - if (Options::enableTypeProfiler()) - enableTypeProfiler(); - if (Options::enableControlFlowProfiler()) - enableControlFlowProfiler(); - - if (Options::watchdog()) { - std::chrono::milliseconds timeoutMillis(Options::watchdog()); - Watchdog& watchdog = ensureWatchdog(); - watchdog.setTimeLimit(timeoutMillis); - } } VM::~VM() @@ -301,19 +314,15 @@ VM::~VM() #if ENABLE(DFG_JIT) // Make sure concurrent compilations are done, but don't install them, since there is // no point to doing so. - for (unsigned i = DFG::numberOfWorklists(); i--;) { - if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i)) { - worklist->waitUntilAllPlansForVMAreReady(*this); - worklist->removeAllReadyPlansForVM(*this); - } + if (worklist) { + worklist->waitUntilAllPlansForVMAreReady(*this); + worklist->removeAllReadyPlansForVM(*this); } #endif // ENABLE(DFG_JIT) - waitForAsynchronousDisassembly(); - // Clear this first to ensure that nobody tries to remove themselves from it. - m_perBytecodeProfiler = nullptr; - + m_perBytecodeProfiler.clear(); + ASSERT(m_apiLock->currentThreadIsHoldingLock()); m_apiLock->willDestroyVM(this); heap.lastChanceToFinalize(); @@ -323,11 +332,33 @@ VM::~VM() interpreter = reinterpret_cast<Interpreter*>(0xbbadbeef); #endif + arrayPrototypeTable->deleteTable(); + arrayConstructorTable->deleteTable(); + booleanPrototypeTable->deleteTable(); + dataViewTable->deleteTable(); + dateTable->deleteTable(); + dateConstructorTable->deleteTable(); + errorPrototypeTable->deleteTable(); + globalObjectTable->deleteTable(); + jsonTable->deleteTable(); + numberConstructorTable->deleteTable(); + numberPrototypeTable->deleteTable(); + objectConstructorTable->deleteTable(); + privateNamePrototypeTable->deleteTable(); + regExpTable->deleteTable(); + regExpConstructorTable->deleteTable(); + regExpPrototypeTable->deleteTable(); + stringConstructorTable->deleteTable(); +#if ENABLE(PROMISES) + promisePrototypeTable->deleteTable(); + promiseConstructorTable->deleteTable(); +#endif + delete emptyList; delete propertyNames; if (vmType != Default) - delete m_atomicStringTable; + deleteIdentifierTable(identifierTable); delete clientData; delete m_regExpCache; @@ -341,17 +372,17 @@ VM::~VM() #endif } -Ref<VM> VM::createContextGroup(HeapType heapType) +PassRefPtr<VM> VM::createContextGroup(HeapType heapType) { - return adoptRef(*new VM(APIContextGroup, heapType)); + return adoptRef(new VM(APIContextGroup, heapType)); } -Ref<VM> VM::create(HeapType heapType) +PassRefPtr<VM> VM::create(HeapType heapType) { - return adoptRef(*new VM(Default, heapType)); + return adoptRef(new VM(Default, heapType)); } -Ref<VM> VM::createLeaked(HeapType heapType) +PassRefPtr<VM> VM::createLeaked(HeapType heapType) { return create(heapType); } @@ -365,8 +396,10 @@ VM& VM::sharedInstance() { GlobalJSLock globalLock; VM*& instance = sharedInstanceInternal(); - if (!instance) + if (!instance) { instance = adoptRef(new VM(APIShared, SmallHeap)).leakRef(); + instance->makeUsableFromMultipleThreads(); + } return *instance; } @@ -376,24 +409,6 @@ VM*& VM::sharedInstanceInternal() return sharedInstance; } -Watchdog& VM::ensureWatchdog() -{ - if (!watchdog) { - watchdog = adoptRef(new Watchdog()); - - // The LLINT peeks into the Watchdog object directly. In order to do that, - // the LLINT assumes that the internal shape of a std::unique_ptr is the - // same as a plain C++ pointer, and loads the address of Watchdog from it. - RELEASE_ASSERT(*reinterpret_cast<Watchdog**>(&watchdog) == watchdog.get()); - - // And if we've previously compiled any functions, we need to revert - // them because they don't have the needed polling checks for the watchdog - // yet. - deleteAllCode(); - } - return *watchdog; -} - #if ENABLE(JIT) static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic) { @@ -402,8 +417,6 @@ static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic) return charCodeAtThunkGenerator; case CharAtIntrinsic: return charAtThunkGenerator; - case Clz32Intrinsic: - return clz32ThunkGenerator; case FromCharCodeIntrinsic: return fromCharCodeThunkGenerator; case SqrtIntrinsic: @@ -424,6 +437,10 @@ static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic) return logThunkGenerator; case IMulIntrinsic: return imulThunkGenerator; + case ArrayIteratorNextKeyIntrinsic: + return arrayIteratorNextKeyThunkGenerator; + case ArrayIteratorNextValueIntrinsic: + return arrayIteratorNextValueThunkGenerator; default: return 0; } @@ -444,8 +461,8 @@ NativeExecutable* VM::getHostFunction(NativeFunction function, Intrinsic intrins NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor) { return NativeExecutable::create(*this, - adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createLLIntCodeRef(llint_native_call_trampoline), JITCode::HostCallThunk)), function, - adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createLLIntCodeRef(llint_native_construct_trampoline), JITCode::HostCallThunk)), constructor, + MacroAssemblerCodeRef::createLLIntCodeRef(llint_native_call_trampoline), function, + MacroAssemblerCodeRef::createLLIntCodeRef(llint_native_construct_trampoline), constructor, NoIntrinsic); } @@ -459,7 +476,7 @@ void VM::resetDateCache() { localTimeOffsetCache.reset(); cachedDateString = String(); - cachedDateStringValue = std::numeric_limits<double>::quiet_NaN(); + cachedDateStringValue = QNaN; dateInstanceCache.reset(); } @@ -473,23 +490,21 @@ void VM::stopSampling() interpreter->stopSampling(); } -void VM::prepareToDeleteCode() +void VM::prepareToDiscardCode() { #if ENABLE(DFG_JIT) - for (unsigned i = DFG::numberOfWorklists(); i--;) { - if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i)) - worklist->completeAllPlansForVM(*this); - } -#endif // ENABLE(DFG_JIT) + if (!worklist) + return; + + worklist->completeAllPlansForVM(*this); +#endif } -void VM::deleteAllCode() +void VM::discardAllCode() { - prepareToDeleteCode(); + prepareToDiscardCode(); m_codeCache->clear(); - m_regExpCache->deleteAllCode(); heap.deleteAllCompiledCode(); - heap.deleteAllUnlinkedFunctionCode(); heap.reportAbandonedObjectGraph(); } @@ -514,112 +529,187 @@ void VM::clearSourceProviderCaches() sourceProviderCacheMap.clear(); } -void VM::throwException(ExecState* exec, Exception* exception) -{ - if (Options::breakOnThrow()) { - dataLog("In call frame ", RawPointer(exec), " for code block ", *exec->codeBlock(), "\n"); - CRASH(); +struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor { + HashSet<FunctionExecutable*> currentlyExecutingFunctions; + void operator()(JSCell* cell) + { + if (!cell->inherits(FunctionExecutable::info())) + return; + FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell); + if (currentlyExecutingFunctions.contains(executable)) + return; + executable->clearCodeIfNotCompiling(); } +}; + +void VM::releaseExecutableMemory() +{ + prepareToDiscardCode(); - ASSERT(exec == topCallFrame || exec == exec->lexicalGlobalObject()->globalExec() || exec == exec->vmEntryGlobalObject()->globalExec()); - setException(exception); + if (entryScope) { + StackPreservingRecompiler recompiler; + HeapIterationScope iterationScope(heap); + HashSet<JSCell*> roots; + heap.getConservativeRegisterRoots(roots); + HashSet<JSCell*>::iterator end = roots.end(); + for (HashSet<JSCell*>::iterator ptr = roots.begin(); ptr != end; ++ptr) { + ScriptExecutable* executable = 0; + JSCell* cell = *ptr; + if (cell->inherits(ScriptExecutable::info())) + executable = static_cast<ScriptExecutable*>(*ptr); + else if (cell->inherits(JSFunction::info())) { + JSFunction* function = jsCast<JSFunction*>(*ptr); + if (function->isHostFunction()) + continue; + executable = function->jsExecutable(); + } else + continue; + ASSERT(executable->inherits(ScriptExecutable::info())); + executable->unlinkCalls(); + if (executable->inherits(FunctionExecutable::info())) + recompiler.currentlyExecutingFunctions.add(static_cast<FunctionExecutable*>(executable)); + + } + heap.objectSpace().forEachLiveCell<StackPreservingRecompiler>(iterationScope, recompiler); + } + m_regExpCache->invalidateCode(); + heap.collectAllGarbage(); } -JSValue VM::throwException(ExecState* exec, JSValue thrownValue) +static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, unsigned bytecodeOffset) { - Exception* exception = jsDynamicCast<Exception*>(thrownValue); - if (!exception) - exception = Exception::create(*this, thrownValue); - - throwException(exec, exception); - return JSValue(exception); + exception->clearAppendSourceToMessage(); + + if (!callFrame->codeBlock()->hasExpressionInfo()) + return; + + int startOffset = 0; + int endOffset = 0; + int divotPoint = 0; + unsigned line = 0; + unsigned column = 0; + + CodeBlock* codeBlock = callFrame->codeBlock(); + codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divotPoint, startOffset, endOffset, line, column); + + int expressionStart = divotPoint - startOffset; + int expressionStop = divotPoint + endOffset; + + const String& sourceString = codeBlock->source()->source(); + if (!expressionStop || expressionStart > static_cast<int>(sourceString.length())) + return; + + VM* vm = &callFrame->vm(); + JSValue jsMessage = exception->getDirect(*vm, vm->propertyNames->message); + if (!jsMessage || !jsMessage.isString()) + return; + + String message = asString(jsMessage)->value(callFrame); + + if (expressionStart < expressionStop) + message = makeString(message, " (evaluating '", codeBlock->source()->getRange(expressionStart, expressionStop), "')"); + else { + // No range information, so give a few characters of context. + const StringImpl* data = sourceString.impl(); + int dataLength = sourceString.length(); + int start = expressionStart; + int stop = expressionStart; + // Get up to 20 characters of context to the left and right of the divot, clamping to the line. + // Then strip whitespace. + while (start > 0 && (expressionStart - start < 20) && (*data)[start - 1] != '\n') + start--; + while (start < (expressionStart - 1) && isStrWhiteSpace((*data)[start])) + start++; + while (stop < dataLength && (stop - expressionStart < 20) && (*data)[stop] != '\n') + stop++; + while (stop > expressionStart && isStrWhiteSpace((*data)[stop - 1])) + stop--; + message = makeString(message, " (near '...", codeBlock->source()->getRange(start, stop), "...')"); + } + + exception->putDirect(*vm, vm->propertyNames->message, jsString(vm, message)); } + +JSValue VM::throwException(ExecState* exec, JSValue error) +{ + ASSERT(exec == topCallFrame || exec == exec->lexicalGlobalObject()->globalExec() || exec == exec->vmEntryGlobalObject()->globalExec()); + + Vector<StackFrame> stackTrace; + interpreter->getStackTrace(stackTrace); + m_exceptionStack = RefCountedArray<StackFrame>(stackTrace); + m_exception = error; + + if (stackTrace.isEmpty() || !error.isObject()) + return error; + JSObject* exception = asObject(error); + + StackFrame stackFrame; + for (unsigned i = 0 ; i < stackTrace.size(); ++i) { + stackFrame = stackTrace.at(i); + if (stackFrame.bytecodeOffset) + break; + } + unsigned bytecodeOffset = stackFrame.bytecodeOffset; + if (!hasErrorInfo(exec, exception)) { + // FIXME: We should only really be adding these properties to VM generated exceptions, + // but the inspector currently requires these for all thrown objects. + unsigned line; + unsigned column; + stackFrame.computeLineAndColumn(line, column); + exception->putDirect(*this, Identifier(this, "line"), jsNumber(line), ReadOnly | DontDelete); + exception->putDirect(*this, Identifier(this, "column"), jsNumber(column), ReadOnly | DontDelete); + if (!stackFrame.sourceURL.isEmpty()) + exception->putDirect(*this, Identifier(this, "sourceURL"), jsString(this, stackFrame.sourceURL), ReadOnly | DontDelete); + } + if (exception->isErrorInstance() && static_cast<ErrorInstance*>(exception)->appendSourceToMessage()) { + unsigned stackIndex = 0; + CallFrame* callFrame; + for (callFrame = exec; callFrame && !callFrame->codeBlock(); ) { + stackIndex++; + callFrame = callFrame->callerFrameSkippingVMEntrySentinel(); + } + if (callFrame && callFrame->codeBlock()) { + stackFrame = stackTrace.at(stackIndex); + bytecodeOffset = stackFrame.bytecodeOffset; + appendSourceToError(callFrame, static_cast<ErrorInstance*>(exception), bytecodeOffset); + } + } + if (exception->hasProperty(exec, this->propertyNames->stack)) + return error; + + exception->putDirect(*this, propertyNames->stack, interpreter->stackTraceAsString(topCallFrame, stackTrace), DontEnum); + return error; +} + JSObject* VM::throwException(ExecState* exec, JSObject* error) { return asObject(throwException(exec, JSValue(error))); } - -void VM::setStackPointerAtVMEntry(void* sp) +void VM::getExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack) { - m_stackPointerAtVMEntry = sp; - updateStackLimit(); + exception = m_exception; + exceptionStack = m_exceptionStack; } - -size_t VM::updateReservedZoneSize(size_t reservedZoneSize) +void VM::setExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack) { - size_t oldReservedZoneSize = m_reservedZoneSize; - m_reservedZoneSize = reservedZoneSize; - - updateStackLimit(); - - return oldReservedZoneSize; + m_exception = exception; + m_exceptionStack = exceptionStack; } -#if PLATFORM(WIN) -// On Windows the reserved stack space consists of committed memory, a guard page, and uncommitted memory, -// where the guard page is a barrier between committed and uncommitted memory. -// When data from the guard page is read or written, the guard page is moved, and memory is committed. -// This is how the system grows the stack. -// When using the C stack on Windows we need to precommit the needed stack space. -// Otherwise we might crash later if we access uncommitted stack memory. -// This can happen if we allocate stack space larger than the page guard size (4K). -// The system does not get the chance to move the guard page, and commit more memory, -// and we crash if uncommitted memory is accessed. -// The MSVC compiler fixes this by inserting a call to the _chkstk() function, -// when needed, see http://support.microsoft.com/kb/100775. -// By touching every page up to the stack limit with a dummy operation, -// we force the system to move the guard page, and commit memory. - -static void preCommitStackMemory(void* stackLimit) +void VM::clearException() { - const int pageSize = 4096; - for (volatile char* p = reinterpret_cast<char*>(&stackLimit); p > stackLimit; p -= pageSize) { - char ch = *p; - *p = ch; - } + m_exception = JSValue(); } -#endif - -inline void VM::updateStackLimit() +void VM:: clearExceptionStack() { -#if PLATFORM(WIN) - void* lastStackLimit = m_stackLimit; -#endif - - if (m_stackPointerAtVMEntry) { - ASSERT(wtfThreadData().stack().isGrowingDownward()); - char* startOfStack = reinterpret_cast<char*>(m_stackPointerAtVMEntry); -#if ENABLE(FTL_JIT) - m_stackLimit = wtfThreadData().stack().recursionLimit(startOfStack, Options::maxPerThreadStackUsage(), m_reservedZoneSize + m_largestFTLStackSize); - m_ftlStackLimit = wtfThreadData().stack().recursionLimit(startOfStack, Options::maxPerThreadStackUsage(), m_reservedZoneSize + 2 * m_largestFTLStackSize); -#else - m_stackLimit = wtfThreadData().stack().recursionLimit(startOfStack, Options::maxPerThreadStackUsage(), m_reservedZoneSize); -#endif - } else { -#if ENABLE(FTL_JIT) - m_stackLimit = wtfThreadData().stack().recursionLimit(m_reservedZoneSize + m_largestFTLStackSize); - m_ftlStackLimit = wtfThreadData().stack().recursionLimit(m_reservedZoneSize + 2 * m_largestFTLStackSize); -#else - m_stackLimit = wtfThreadData().stack().recursionLimit(m_reservedZoneSize); -#endif - } - -#if PLATFORM(WIN) - if (lastStackLimit != m_stackLimit) - preCommitStackMemory(m_stackLimit); -#endif + m_exceptionStack = RefCountedArray<StackFrame>(); } -#if ENABLE(FTL_JIT) -void VM::updateFTLLargestStackSize(size_t stackSize) +void releaseExecutableMemory(VM& vm) { - if (stackSize > m_largestFTLStackSize) { - m_largestFTLStackSize = stackSize; - updateStackLimit(); - } + vm.releaseExecutableMemory(); } -#endif #if ENABLE(DFG_JIT) void VM::gatherConservativeRoots(ConservativeRoots& conservativeRoots) @@ -632,24 +722,20 @@ void VM::gatherConservativeRoots(ConservativeRoots& conservativeRoots) } } } -#endif -void logSanitizeStack(VM* vm) +DFG::Worklist* VM::ensureWorklist() { - if (Options::verboseSanitizeStack() && vm->topCallFrame) { - int dummy; - dataLog( - "Sanitizing stack with top call frame at ", RawPointer(vm->topCallFrame), - ", current stack pointer at ", RawPointer(&dummy), ", in ", - pointerDump(vm->topCallFrame->codeBlock()), " and last code origin = ", - vm->topCallFrame->codeOrigin(), "\n"); - } + if (!DFG::enableConcurrentJIT()) + return 0; + if (!worklist) + worklist = DFG::globalWorklist(); + return worklist.get(); } +#endif #if ENABLE(REGEXP_TRACING) void VM::addRegExpToTrace(RegExp* regExp) { - gcProtect(regExp); m_rtTraceList->add(regExp); } @@ -660,16 +746,14 @@ void VM::dumpRegExpTrace() if (iter != m_rtTraceList->end()) { dataLogF("\nRegExp Tracing\n"); - dataLogF("Regular Expression 8 Bit 16 Bit match() Matches Average\n"); - dataLogF(" <Match only / Match> JIT Addr JIT Address calls found String len\n"); - dataLogF("----------------------------------------+----------------+----------------+----------+----------+-----------\n"); + dataLogF(" match() matches\n"); + dataLogF("Regular Expression JIT Address calls found\n"); + dataLogF("----------------------------------------+----------------+----------+----------\n"); unsigned reCount = 0; - for (; iter != m_rtTraceList->end(); ++iter, ++reCount) { + for (; iter != m_rtTraceList->end(); ++iter, ++reCount) (*iter)->printTraceData(); - gcUnprotect(*iter); - } dataLogF("%d Regular Expressions\n", reCount); } @@ -693,15 +777,15 @@ void VM::registerWatchpointForImpureProperty(const Identifier& propertyName, Wat void VM::addImpureProperty(const String& propertyName) { if (RefPtr<WatchpointSet> watchpointSet = m_impurePropertyWatchpointSets.take(propertyName)) - watchpointSet->fireAll("Impure property added"); + watchpointSet->fireAll(); } class SetEnabledProfilerFunctor { public: bool operator()(CodeBlock* codeBlock) { - if (JITCode::isOptimizingJIT(codeBlock->jitType())) - codeBlock->jettison(Profiler::JettisonDueToLegacyProfiler); + if (codeBlock->jitType() == JITCode::DFGJIT) + codeBlock->jettison(); return false; } }; @@ -710,108 +794,9 @@ void VM::setEnabledProfiler(LegacyProfiler* profiler) { m_enabledProfiler = profiler; if (m_enabledProfiler) { - prepareToDeleteCode(); SetEnabledProfilerFunctor functor; heap.forEachCodeBlock(functor); } } -static bool enableProfilerWithRespectToCount(unsigned& counter, std::function<void()> doEnableWork) -{ - bool needsToRecompile = false; - if (!counter) { - doEnableWork(); - needsToRecompile = true; - } - counter++; - - return needsToRecompile; -} - -static bool disableProfilerWithRespectToCount(unsigned& counter, std::function<void()> doDisableWork) -{ - RELEASE_ASSERT(counter > 0); - bool needsToRecompile = false; - counter--; - if (!counter) { - doDisableWork(); - needsToRecompile = true; - } - - return needsToRecompile; -} - -bool VM::enableTypeProfiler() -{ - auto enableTypeProfiler = [this] () { - this->m_typeProfiler = std::make_unique<TypeProfiler>(); - this->m_typeProfilerLog = std::make_unique<TypeProfilerLog>(); - }; - - return enableProfilerWithRespectToCount(m_typeProfilerEnabledCount, enableTypeProfiler); -} - -bool VM::disableTypeProfiler() -{ - auto disableTypeProfiler = [this] () { - this->m_typeProfiler.reset(nullptr); - this->m_typeProfilerLog.reset(nullptr); - }; - - return disableProfilerWithRespectToCount(m_typeProfilerEnabledCount, disableTypeProfiler); -} - -bool VM::enableControlFlowProfiler() -{ - auto enableControlFlowProfiler = [this] () { - this->m_controlFlowProfiler = std::make_unique<ControlFlowProfiler>(); - }; - - return enableProfilerWithRespectToCount(m_controlFlowProfilerEnabledCount, enableControlFlowProfiler); -} - -bool VM::disableControlFlowProfiler() -{ - auto disableControlFlowProfiler = [this] () { - this->m_controlFlowProfiler.reset(nullptr); - }; - - return disableProfilerWithRespectToCount(m_controlFlowProfilerEnabledCount, disableControlFlowProfiler); -} - -void VM::dumpTypeProfilerData() -{ - if (!typeProfiler()) - return; - - typeProfilerLog()->processLogEntries(ASCIILiteral("VM Dump Types")); - typeProfiler()->dumpTypeProfilerData(*this); -} - -void VM::queueMicrotask(JSGlobalObject* globalObject, PassRefPtr<Microtask> task) -{ - m_microtaskQueue.append(std::make_unique<QueuedTask>(*this, globalObject, task)); -} - -void VM::drainMicrotasks() -{ - while (!m_microtaskQueue.isEmpty()) - m_microtaskQueue.takeFirst()->run(); -} - -void QueuedTask::run() -{ - m_microtask->run(m_globalObject->globalExec()); -} - -void sanitizeStackForVM(VM* vm) -{ - logSanitizeStack(vm); -#if !ENABLE(JIT) - vm->interpreter->stack().sanitizeStack(); -#else - sanitizeStackForVMImpl(vm); -#endif -} - } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/VM.h b/Source/JavaScriptCore/runtime/VM.h index 0634a3bba..1de423e0e 100644 --- a/Source/JavaScriptCore/runtime/VM.h +++ b/Source/JavaScriptCore/runtime/VM.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2013-2015 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 @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -29,10 +29,9 @@ #ifndef VM_h #define VM_h -#include "ControlFlowProfiler.h" #include "DateInstanceCache.h" #include "ExecutableAllocator.h" -#include "FunctionHasExecutedCache.h" +#include "GPRInfo.h" #include "Heap.h" #include "Intrinsic.h" #include "JITThunks.h" @@ -40,31 +39,28 @@ #include "JSLock.h" #include "LLIntData.h" #include "MacroAssemblerCodeRef.h" -#include "Microtask.h" #include "NumericStrings.h" +#include "ProfilerDatabase.h" #include "PrivateName.h" #include "PrototypeMap.h" #include "SmallStrings.h" -#include "SourceCode.h" #include "Strong.h" #include "ThunkGenerators.h" #include "TypedArrayController.h" -#include "VMEntryRecord.h" +#include "Watchdog.h" #include "Watchpoint.h" #include "WeakRandom.h" -#include <wtf/Bag.h> #include <wtf/BumpPointerAllocator.h> #include <wtf/DateMath.h> -#include <wtf/Deque.h> #include <wtf/Forward.h> #include <wtf/HashMap.h> #include <wtf/HashSet.h> +#include <wtf/RefCountedArray.h> #include <wtf/SimpleStats.h> #include <wtf/StackBounds.h> #include <wtf/ThreadSafeRefCounted.h> #include <wtf/ThreadSpecific.h> #include <wtf/WTFThreadData.h> -#include <wtf/text/SymbolRegistry.h> #include <wtf/text/WTFString.h> #if ENABLE(REGEXP_TRACING) #include <wtf/ListHashSet.h> @@ -72,572 +68,484 @@ namespace JSC { -class ArityCheckFailReturnThunks; -class BuiltinExecutables; -class CodeBlock; -class CodeCache; -class CommonIdentifiers; -class ExecState; -class Exception; -class HandleStack; -class TypeProfiler; -class TypeProfilerLog; -class Identifier; -class Interpreter; -class JSGlobalObject; -class JSObject; -class LLIntOffsetsExtractor; -class LegacyProfiler; -class NativeExecutable; -class RegExpCache; -class ScriptExecutable; -class SourceProvider; -class SourceProviderCache; -struct StackFrame; -class Stringifier; -class Structure; + class CodeBlock; + class CodeCache; + class CommonIdentifiers; + class ExecState; + class HandleStack; + class Identifier; + class IdentifierTable; + class Interpreter; + class JSGlobalObject; + class JSObject; + class Keywords; + class LLIntOffsetsExtractor; + class LegacyProfiler; + class NativeExecutable; + class ParserArena; + class RegExpCache; + class SourceProvider; + class SourceProviderCache; + struct StackFrame; + class Stringifier; + class Structure; #if ENABLE(REGEXP_TRACING) -class RegExp; + class RegExp; #endif -class UnlinkedCodeBlock; -class UnlinkedEvalCodeBlock; -class UnlinkedFunctionExecutable; -class UnlinkedProgramCodeBlock; -class VirtualRegister; -class VMEntryScope; -class Watchdog; -class Watchpoint; -class WatchpointSet; + class UnlinkedCodeBlock; + class UnlinkedEvalCodeBlock; + class UnlinkedFunctionExecutable; + class UnlinkedProgramCodeBlock; + class VMEntryScope; + class Watchpoint; + class WatchpointSet; #if ENABLE(DFG_JIT) -namespace DFG { -class LongLivedState; -} + namespace DFG { + class LongLivedState; + class Worklist; + } #endif // ENABLE(DFG_JIT) #if ENABLE(FTL_JIT) -namespace FTL { -class Thunks; -} -#endif // ENABLE(FTL_JIT) -namespace CommonSlowPaths { -struct ArityCheckData; -} -namespace Profiler { -class Database; -} - -struct HashTable; -struct Instruction; - -struct LocalTimeOffsetCache { - LocalTimeOffsetCache() - : start(0.0) - , end(-1.0) - , increment(0.0) - , timeType(WTF::UTCTime) - { + namespace FTL { + class Thunks; } +#endif // ENABLE(FTL_JIT) - void reset() - { - offset = LocalTimeOffset(); - start = 0.0; - end = -1.0; - increment = 0.0; - timeType = WTF::UTCTime; - } + struct HashTable; + struct Instruction; - LocalTimeOffset offset; - double start; - double end; - double increment; - WTF::TimeType timeType; -}; - -class QueuedTask { - WTF_MAKE_NONCOPYABLE(QueuedTask); - WTF_MAKE_FAST_ALLOCATED; -public: - void run(); - - QueuedTask(VM& vm, JSGlobalObject* globalObject, PassRefPtr<Microtask> microtask) - : m_globalObject(vm, globalObject) - , m_microtask(microtask) - { - } + struct LocalTimeOffsetCache { + LocalTimeOffsetCache() + : start(0.0) + , end(-1.0) + , increment(0.0) + , timeType(WTF::UTCTime) + { + } + + void reset() + { + offset = LocalTimeOffset(); + start = 0.0; + end = -1.0; + increment = 0.0; + timeType = WTF::UTCTime; + } -private: - Strong<JSGlobalObject> m_globalObject; - RefPtr<Microtask> m_microtask; -}; + LocalTimeOffset offset; + double start; + double end; + double increment; + WTF::TimeType timeType; + }; -class ConservativeRoots; + class ConservativeRoots; #if COMPILER(MSVC) #pragma warning(push) #pragma warning(disable: 4200) // Disable "zero-sized array in struct/union" warning #endif -struct ScratchBuffer { - ScratchBuffer() - { - u.m_activeLength = 0; - } + struct ScratchBuffer { + ScratchBuffer() + { + u.m_activeLength = 0; + } - static ScratchBuffer* create(size_t size) - { - ScratchBuffer* result = new (fastMalloc(ScratchBuffer::allocationSize(size))) ScratchBuffer; + static ScratchBuffer* create(size_t size) + { + ScratchBuffer* result = new (fastMalloc(ScratchBuffer::allocationSize(size))) ScratchBuffer; - return result; - } + return result; + } - static size_t allocationSize(size_t bufferSize) { return sizeof(ScratchBuffer) + bufferSize; } - 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; } + static size_t allocationSize(size_t bufferSize) { return sizeof(ScratchBuffer) + bufferSize; } + 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; } - union { - size_t m_activeLength; - double pad; // Make sure m_buffer is double aligned. - } u; + 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))); + void* m_buffer[0] __attribute__((aligned(8))); #else - void* m_buffer[0]; + void* m_buffer[0]; #endif -}; + }; #if COMPILER(MSVC) #pragma warning(pop) #endif -class VM : public ThreadSafeRefCounted<VM> { -public: - // 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' 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 VM created for use by - // the original API. - enum VMType { Default, APIContextGroup, APIShared }; - - struct ClientData { - JS_EXPORT_PRIVATE virtual ~ClientData() = 0; - }; + class VM : public ThreadSafeRefCounted<VM> { + public: + // 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' 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 VM created for use by + // the original API. + enum VMType { Default, APIContextGroup, APIShared }; + + struct ClientData { + JS_EXPORT_PRIVATE virtual ~ClientData() = 0; + }; - bool isSharedInstance() { return vmType == APIShared; } - bool usingAPI() { return vmType != Default; } - JS_EXPORT_PRIVATE static bool sharedInstanceExists(); - JS_EXPORT_PRIVATE static VM& sharedInstance(); + bool isSharedInstance() { return vmType == APIShared; } + bool usingAPI() { return vmType != Default; } + JS_EXPORT_PRIVATE static bool sharedInstanceExists(); + JS_EXPORT_PRIVATE static VM& sharedInstance(); - JS_EXPORT_PRIVATE static Ref<VM> create(HeapType = SmallHeap); - JS_EXPORT_PRIVATE static Ref<VM> createLeaked(HeapType = SmallHeap); - static Ref<VM> createContextGroup(HeapType = SmallHeap); - JS_EXPORT_PRIVATE ~VM(); + 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(); - JS_EXPORT_PRIVATE Watchdog& ensureWatchdog(); + void makeUsableFromMultipleThreads() { heap.machineThreads().makeUsableFromMultipleThreads(); } + +#if ENABLE(DFG_JIT) + DFG::Worklist* ensureWorklist(); +#endif // ENABLE(DFG_JIT) -private: - RefPtr<JSLock> m_apiLock; + private: + RefPtr<JSLock> m_apiLock; -public: + public: #if ENABLE(ASSEMBLER) - // executableAllocator should be destructed after the heap, as the heap can call executableAllocator - // in its destructor. - ExecutableAllocator executableAllocator; + // executableAllocator should be destructed after the heap, as the heap can call executableAllocator + // in its destructor. + ExecutableAllocator executableAllocator; #endif - // 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; - + // 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) - std::unique_ptr<DFG::LongLivedState> dfgState; + OwnPtr<DFG::LongLivedState> dfgState; + RefPtr<DFG::Worklist> worklist; #endif // ENABLE(DFG_JIT) - VMType vmType; - ClientData* clientData; - VMEntryFrame* topVMEntryFrame; - ExecState* topCallFrame; - RefPtr<Watchdog> watchdog; - - Strong<Structure> structureStructure; - Strong<Structure> structureRareDataStructure; - Strong<Structure> terminatedExecutionErrorStructure; - Strong<Structure> stringStructure; - Strong<Structure> notAnObjectStructure; - Strong<Structure> propertyNameIteratorStructure; - Strong<Structure> propertyNameEnumeratorStructure; - Strong<Structure> getterSetterStructure; - Strong<Structure> customGetterSetterStructure; - Strong<Structure> scopedArgumentsTableStructure; - Strong<Structure> apiWrapperStructure; - Strong<Structure> JSScopeStructure; - Strong<Structure> executableStructure; - Strong<Structure> nativeExecutableStructure; - Strong<Structure> evalExecutableStructure; - Strong<Structure> programExecutableStructure; - Strong<Structure> functionExecutableStructure; - Strong<Structure> regExpStructure; - Strong<Structure> symbolStructure; - Strong<Structure> symbolTableStructure; - Strong<Structure> structureChainStructure; - Strong<Structure> sparseArrayValueMapStructure; - Strong<Structure> templateRegistryKeyStructure; - Strong<Structure> arrayBufferNeuteringWatchpointStructure; - Strong<Structure> unlinkedFunctionExecutableStructure; - Strong<Structure> unlinkedProgramCodeBlockStructure; - Strong<Structure> unlinkedEvalCodeBlockStructure; - Strong<Structure> unlinkedFunctionCodeBlockStructure; - Strong<Structure> propertyTableStructure; - Strong<Structure> weakMapDataStructure; - Strong<Structure> inferredValueStructure; - Strong<Structure> functionRareDataStructure; - Strong<Structure> exceptionStructure; - Strong<Structure> promiseDeferredStructure; - Strong<JSCell> iterationTerminator; - Strong<JSCell> emptyPropertyNameEnumerator; - - AtomicStringTable* m_atomicStringTable; - WTF::SymbolRegistry m_symbolRegistry; - CommonIdentifiers* propertyNames; - const MarkedArgumentBuffer* emptyList; // Lists are supposed to be allocated on the stack to have their elements properly marked, which is not the case here - but this list has nothing to mark. - SmallStrings smallStrings; - NumericStrings numericStrings; - DateInstanceCache dateInstanceCache; - WTF::SimpleStats machineCodeBytesPerBytecodeWordForBaselineJIT; - WeakGCMap<StringImpl*, JSString, PtrHash<StringImpl*>> stringCache; - Strong<JSString> lastCachedString; - - AtomicStringTable* atomicStringTable() const { return m_atomicStringTable; } - WTF::SymbolRegistry& symbolRegistry() { return m_symbolRegistry; } - - void setInDefineOwnProperty(bool inDefineOwnProperty) - { - m_inDefineOwnProperty = inDefineOwnProperty; - } + VMType vmType; + ClientData* clientData; + ExecState* topCallFrame; + Watchdog watchdog; + + const OwnPtr<const HashTable> arrayConstructorTable; + const OwnPtr<const HashTable> arrayPrototypeTable; + const OwnPtr<const HashTable> booleanPrototypeTable; + const OwnPtr<const HashTable> dataViewTable; + const OwnPtr<const HashTable> dateTable; + const OwnPtr<const HashTable> dateConstructorTable; + const OwnPtr<const HashTable> errorPrototypeTable; + const OwnPtr<const HashTable> globalObjectTable; + const OwnPtr<const HashTable> jsonTable; + const OwnPtr<const HashTable> numberConstructorTable; + const OwnPtr<const HashTable> numberPrototypeTable; + const OwnPtr<const HashTable> objectConstructorTable; + const OwnPtr<const HashTable> privateNamePrototypeTable; + const OwnPtr<const HashTable> regExpTable; + const OwnPtr<const HashTable> regExpConstructorTable; + const OwnPtr<const HashTable> regExpPrototypeTable; + const OwnPtr<const HashTable> stringConstructorTable; +#if ENABLE(PROMISES) + const OwnPtr<const HashTable> promisePrototypeTable; + const OwnPtr<const HashTable> promiseConstructorTable; +#endif - bool isInDefineOwnProperty() - { - return m_inDefineOwnProperty; - } + Strong<Structure> structureStructure; + Strong<Structure> structureRareDataStructure; + Strong<Structure> debuggerActivationStructure; + Strong<Structure> terminatedExecutionErrorStructure; + Strong<Structure> stringStructure; + Strong<Structure> notAnObjectStructure; + Strong<Structure> propertyNameIteratorStructure; + Strong<Structure> getterSetterStructure; + Strong<Structure> apiWrapperStructure; + Strong<Structure> JSScopeStructure; + Strong<Structure> executableStructure; + Strong<Structure> nativeExecutableStructure; + Strong<Structure> evalExecutableStructure; + Strong<Structure> programExecutableStructure; + Strong<Structure> functionExecutableStructure; + Strong<Structure> regExpStructure; + Strong<Structure> symbolTableStructure; + Strong<Structure> structureChainStructure; + Strong<Structure> sparseArrayValueMapStructure; + Strong<Structure> arrayBufferNeuteringWatchpointStructure; + Strong<Structure> withScopeStructure; + Strong<Structure> unlinkedFunctionExecutableStructure; + Strong<Structure> unlinkedProgramCodeBlockStructure; + Strong<Structure> unlinkedEvalCodeBlockStructure; + Strong<Structure> unlinkedFunctionCodeBlockStructure; + Strong<Structure> propertyTableStructure; + Strong<Structure> mapDataStructure; + Strong<Structure> weakMapDataStructure; + Strong<Structure> promiseDeferredStructure; + Strong<Structure> promiseReactionStructure; + Strong<JSCell> iterationTerminator; + + IdentifierTable* identifierTable; + CommonIdentifiers* propertyNames; + const MarkedArgumentBuffer* emptyList; // Lists are supposed to be allocated on the stack to have their elements properly marked, which is not the case here - but this list has nothing to mark. + SmallStrings smallStrings; + NumericStrings numericStrings; + DateInstanceCache dateInstanceCache; + WTF::SimpleStats machineCodeBytesPerBytecodeWordForBaselineJIT; + + void setInDefineOwnProperty(bool inDefineOwnProperty) + { + m_inDefineOwnProperty = inDefineOwnProperty; + } - LegacyProfiler* enabledProfiler() { return m_enabledProfiler; } - void setEnabledProfiler(LegacyProfiler*); + bool isInDefineOwnProperty() + { + return m_inDefineOwnProperty; + } - void* enabledProfilerAddress() { return &m_enabledProfiler; } + LegacyProfiler* enabledProfiler() { return m_enabledProfiler; } + void setEnabledProfiler(LegacyProfiler*); -#if ENABLE(JIT) - bool canUseJIT() { return m_canUseJIT; } + void* enabledProfilerAddress() { return &m_enabledProfiler; } + +#if ENABLE(JIT) && ENABLE(LLINT) + bool canUseJIT() { return m_canUseJIT; } +#elif ENABLE(JIT) + bool canUseJIT() { return true; } // jit only #else - bool canUseJIT() { return false; } // interpreter only + bool canUseJIT() { return false; } // interpreter only #endif #if ENABLE(YARR_JIT) - bool canUseRegExpJIT() { return m_canUseRegExpJIT; } + bool canUseRegExpJIT() { return m_canUseRegExpJIT; } #else - bool canUseRegExpJIT() { return false; } // interpreter only + bool canUseRegExpJIT() { return false; } // interpreter only #endif - SourceProviderCache* addSourceProviderCache(SourceProvider*); - void clearSourceProviderCaches(); + SourceProviderCache* addSourceProviderCache(SourceProvider*); + void clearSourceProviderCaches(); - PrototypeMap prototypeMap; + PrototypeMap prototypeMap; - typedef HashMap<RefPtr<SourceProvider>, RefPtr<SourceProviderCache>> SourceProviderCacheMap; - SourceProviderCacheMap sourceProviderCacheMap; - Interpreter* interpreter; + OwnPtr<ParserArena> parserArena; + typedef HashMap<RefPtr<SourceProvider>, RefPtr<SourceProviderCache>> SourceProviderCacheMap; + SourceProviderCacheMap sourceProviderCacheMap; + OwnPtr<Keywords> keywords; + Interpreter* interpreter; #if ENABLE(JIT) - std::unique_ptr<JITThunks> jitStubs; - MacroAssemblerCodeRef getCTIStub(ThunkGenerator generator) - { - return jitStubs->ctiStub(this, generator); - } - NativeExecutable* getHostFunction(NativeFunction, Intrinsic); - - std::unique_ptr<ArityCheckFailReturnThunks> arityCheckFailReturnThunks; -#endif // ENABLE(JIT) - std::unique_ptr<CommonSlowPaths::ArityCheckData> arityCheckData; -#if ENABLE(FTL_JIT) - std::unique_ptr<FTL::Thunks> ftlThunks; + OwnPtr<JITThunks> jitStubs; + MacroAssemblerCodeRef getCTIStub(ThunkGenerator generator) + { + return jitStubs->ctiStub(this, generator); + } + NativeExecutable* getHostFunction(NativeFunction, Intrinsic); #endif - NativeExecutable* getHostFunction(NativeFunction, NativeFunction constructor); - - static ptrdiff_t exceptionOffset() - { - return OBJECT_OFFSETOF(VM, m_exception); - } - - static ptrdiff_t vmEntryFrameForThrowOffset() - { - return OBJECT_OFFSETOF(VM, vmEntryFrameForThrow); - } - - static ptrdiff_t topVMEntryFrameOffset() - { - return OBJECT_OFFSETOF(VM, topVMEntryFrame); - } - - static ptrdiff_t callFrameForThrowOffset() - { - return OBJECT_OFFSETOF(VM, callFrameForThrow); - } - - static ptrdiff_t targetMachinePCForThrowOffset() - { - return OBJECT_OFFSETOF(VM, targetMachinePCForThrow); - } - - void clearException() { m_exception = nullptr; } - void clearLastException() { m_lastException = nullptr; } - - void setException(Exception* exception) - { - m_exception = exception; - m_lastException = exception; - } - - Exception* exception() const { return m_exception; } - JSCell** addressOfException() { return reinterpret_cast<JSCell**>(&m_exception); } - - Exception* lastException() const { return m_lastException; } - JSCell** addressOfLastException() { return reinterpret_cast<JSCell**>(&m_lastException); } - - JS_EXPORT_PRIVATE void throwException(ExecState*, Exception*); - JS_EXPORT_PRIVATE JSValue throwException(ExecState*, JSValue); - JS_EXPORT_PRIVATE JSObject* throwException(ExecState*, JSObject*); - - void* stackPointerAtVMEntry() const { return m_stackPointerAtVMEntry; } - void setStackPointerAtVMEntry(void*); - - size_t reservedZoneSize() const { return m_reservedZoneSize; } - size_t updateReservedZoneSize(size_t reservedZoneSize); - #if ENABLE(FTL_JIT) - void updateFTLLargestStackSize(size_t); - void** addressOfFTLStackLimit() { return &m_ftlStackLimit; } + std::unique_ptr<FTL::Thunks> ftlThunks; #endif + NativeExecutable* getHostFunction(NativeFunction, NativeFunction constructor); -#if !ENABLE(JIT) - void* jsStackLimit() { return m_jsStackLimit; } - void setJSStackLimit(void* limit) { m_jsStackLimit = limit; } -#endif - void* stackLimit() { return m_stackLimit; } - void** addressOfStackLimit() { return &m_stackLimit; } + static ptrdiff_t exceptionOffset() + { + return OBJECT_OFFSETOF(VM, m_exception); + } - bool isSafeToRecurse(size_t neededStackInBytes = 0) const - { - ASSERT(wtfThreadData().stack().isGrowingDownward()); - int8_t* curr = reinterpret_cast<int8_t*>(&curr); - int8_t* limit = reinterpret_cast<int8_t*>(m_stackLimit); - return curr >= limit && static_cast<size_t>(curr - limit) >= neededStackInBytes; - } + static ptrdiff_t callFrameForThrowOffset() + { + return OBJECT_OFFSETOF(VM, callFrameForThrow); + } - void* lastStackTop() { return m_lastStackTop; } - void setLastStackTop(void* lastStackTop) { m_lastStackTop = lastStackTop; } - - const ClassInfo* const jsArrayClassInfo; - const ClassInfo* const jsFinalObjectClassInfo; - - JSValue hostCallReturnValue; - unsigned varargsLength; - ExecState* newCallFrameReturnValue; - VMEntryFrame* vmEntryFrameForThrow; - ExecState* callFrameForThrow; - void* targetMachinePCForThrow; - Instruction* targetInterpreterPCForThrow; - uint32_t osrExitIndex; - void* osrExitJumpDestination; - Vector<ScratchBuffer*> scratchBuffers; - size_t sizeOfLastScratchBuffer; - - ScratchBuffer* scratchBufferForSize(size_t size) - { - if (!size) - return 0; - - if (size > sizeOfLastScratchBuffer) { - // Protect against a N^2 memory usage pathology by ensuring - // that at worst, we get a geometric series, meaning that the - // total memory usage is somewhere around - // max(scratch buffer size) * 4. - sizeOfLastScratchBuffer = size * 2; - - ScratchBuffer* newBuffer = ScratchBuffer::create(sizeOfLastScratchBuffer); - RELEASE_ASSERT(newBuffer); - scratchBuffers.append(newBuffer); + static ptrdiff_t targetMachinePCForThrowOffset() + { + return OBJECT_OFFSETOF(VM, targetMachinePCForThrow); } - ScratchBuffer* result = scratchBuffers.last(); - result->setActiveLength(0); - return result; - } + JS_EXPORT_PRIVATE void clearException(); + JS_EXPORT_PRIVATE void clearExceptionStack(); + void getExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack); + void setExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack); + JSValue exception() const { return m_exception; } + JSValue* addressOfException() { return &m_exception; } + const RefCountedArray<StackFrame>& exceptionStack() const { return m_exceptionStack; } - void gatherConservativeRoots(ConservativeRoots&); + JS_EXPORT_PRIVATE JSValue throwException(ExecState*, JSValue); + JS_EXPORT_PRIVATE JSObject* throwException(ExecState*, JSObject*); + + void** addressOfJSStackLimit() { return &m_jsStackLimit; } + void* jsStackLimit() { return m_jsStackLimit; } + void setJSStackLimit(void* limit) { m_jsStackLimit = limit; } + + void* stackLimit() { return m_stackLimit; } + void setStackLimit(void* limit) { m_stackLimit = limit; } + bool isSafeToRecurse(size_t neededStackInBytes = 0) const + { + ASSERT(wtfThreadData().stack().isGrowingDownward()); + int8_t* curr = reinterpret_cast<int8_t*>(&curr); + int8_t* limit = reinterpret_cast<int8_t*>(m_stackLimit); + return curr >= limit && static_cast<size_t>(curr - limit) >= neededStackInBytes; + } - VMEntryScope* entryScope; + const ClassInfo* const jsArrayClassInfo; + const ClassInfo* const jsFinalObjectClassInfo; + + ReturnAddressPtr exceptionLocation; + JSValue hostCallReturnValue; + ExecState* newCallFrameReturnValue; + ExecState* callFrameForThrow; + void* targetMachinePCForThrow; + Instruction* targetInterpreterPCForThrow; + uint32_t osrExitIndex; + void* osrExitJumpDestination; + Vector<ScratchBuffer*> scratchBuffers; + size_t sizeOfLastScratchBuffer; + + ScratchBuffer* scratchBufferForSize(size_t size) + { + if (!size) + return 0; + + if (size > sizeOfLastScratchBuffer) { + // Protect against a N^2 memory usage pathology by ensuring + // that at worst, we get a geometric series, meaning that the + // total memory usage is somewhere around + // max(scratch buffer size) * 4. + sizeOfLastScratchBuffer = size * 2; + + scratchBuffers.append(ScratchBuffer::create(sizeOfLastScratchBuffer)); + } + + ScratchBuffer* result = scratchBuffers.last(); + result->setActiveLength(0); + return result; + } + + void gatherConservativeRoots(ConservativeRoots&); - JSObject* stringRecursionCheckFirstObject { nullptr }; - HashSet<JSObject*> stringRecursionCheckVisitedObjects; + VMEntryScope* entryScope; - LocalTimeOffsetCache localTimeOffsetCache; + HashSet<JSObject*> stringRecursionCheckVisitedObjects; - String cachedDateString; - double cachedDateStringValue; + LocalTimeOffsetCache localTimeOffsetCache; + + String cachedDateString; + double cachedDateStringValue; - std::unique_ptr<Profiler::Database> m_perBytecodeProfiler; - RefPtr<TypedArrayController> m_typedArrayController; - RegExpCache* m_regExpCache; - BumpPointerAllocator m_regExpAllocator; + OwnPtr<Profiler::Database> m_perBytecodeProfiler; + RefPtr<TypedArrayController> m_typedArrayController; + RegExpCache* m_regExpCache; + BumpPointerAllocator m_regExpAllocator; #if ENABLE(REGEXP_TRACING) - typedef ListHashSet<RegExp*> RTTraceList; - RTTraceList* m_rtTraceList; + typedef ListHashSet<RefPtr<RegExp>> RTTraceList; + RTTraceList* m_rtTraceList; #endif - bool hasExclusiveThread() const { return m_apiLock->hasExclusiveThread(); } - std::thread::id exclusiveThread() const { return m_apiLock->exclusiveThread(); } - void setExclusiveThread(std::thread::id threadId) { m_apiLock->setExclusiveThread(threadId); } + ThreadIdentifier exclusiveThread; - JS_EXPORT_PRIVATE void resetDateCache(); + JS_EXPORT_PRIVATE void resetDateCache(); - JS_EXPORT_PRIVATE void startSampling(); - JS_EXPORT_PRIVATE void stopSampling(); - JS_EXPORT_PRIVATE void dumpSampleData(ExecState*); - RegExpCache* regExpCache() { return m_regExpCache; } + JS_EXPORT_PRIVATE void startSampling(); + JS_EXPORT_PRIVATE void stopSampling(); + JS_EXPORT_PRIVATE void dumpSampleData(ExecState* exec); + RegExpCache* regExpCache() { return m_regExpCache; } #if ENABLE(REGEXP_TRACING) - void addRegExpToTrace(RegExp*); + void addRegExpToTrace(PassRefPtr<RegExp> regExp); #endif - JS_EXPORT_PRIVATE void dumpRegExpTrace(); + JS_EXPORT_PRIVATE void dumpRegExpTrace(); - bool isCollectorBusy() { return heap.isBusy(); } + bool isCollectorBusy() { return heap.isBusy(); } + JS_EXPORT_PRIVATE void releaseExecutableMemory(); #if ENABLE(GC_VALIDATION) - bool isInitializingObject() const; - void setInitializingObjectClass(const ClassInfo*); + bool isInitializingObject() const; + void setInitializingObjectClass(const ClassInfo*); #endif - unsigned m_newStringsSinceLastHashCons; + unsigned m_newStringsSinceLastHashCons; - static const unsigned s_minNumberOfNewStringsToHashCons = 100; + static const unsigned s_minNumberOfNewStringsToHashCons = 100; - bool haveEnoughNewStringsToHashCons() { return m_newStringsSinceLastHashCons > s_minNumberOfNewStringsToHashCons; } - void resetNewStringsSinceLastHashCons() { m_newStringsSinceLastHashCons = 0; } + bool haveEnoughNewStringsToHashCons() { return m_newStringsSinceLastHashCons > s_minNumberOfNewStringsToHashCons; } + void resetNewStringsSinceLastHashCons() { m_newStringsSinceLastHashCons = 0; } - bool currentThreadIsHoldingAPILock() const { return m_apiLock->currentThreadIsHoldingLock(); } + bool currentThreadIsHoldingAPILock() const + { + return m_apiLock->currentThreadIsHoldingLock() || exclusiveThread == currentThread(); + } - JSLock& apiLock() { return *m_apiLock; } - CodeCache* codeCache() { return m_codeCache.get(); } + JSLock& apiLock() { return *m_apiLock; } + CodeCache* codeCache() { return m_codeCache.get(); } - void prepareToDeleteCode(); + void prepareToDiscardCode(); - JS_EXPORT_PRIVATE void deleteAllCode(); - - void registerWatchpointForImpureProperty(const Identifier&, Watchpoint*); - - // FIXME: Use AtomicString once it got merged with Identifier. - JS_EXPORT_PRIVATE void addImpureProperty(const String&); + JS_EXPORT_PRIVATE void discardAllCode(); - BuiltinExecutables* builtinExecutables() { return m_builtinExecutables.get(); } - - bool enableTypeProfiler(); - bool disableTypeProfiler(); - TypeProfilerLog* typeProfilerLog() { return m_typeProfilerLog.get(); } - TypeProfiler* typeProfiler() { return m_typeProfiler.get(); } - JS_EXPORT_PRIVATE void dumpTypeProfilerData(); - - FunctionHasExecutedCache* functionHasExecutedCache() { return &m_functionHasExecutedCache; } - - ControlFlowProfiler* controlFlowProfiler() { return m_controlFlowProfiler.get(); } - bool enableControlFlowProfiler(); - bool disableControlFlowProfiler(); - - JS_EXPORT_PRIVATE void queueMicrotask(JSGlobalObject*, PassRefPtr<Microtask>); - JS_EXPORT_PRIVATE void drainMicrotasks(); - - inline bool shouldTriggerTermination(ExecState*); - -private: - friend class LLIntOffsetsExtractor; - friend class ClearExceptionScope; - friend class RecursiveAllocationScope; - - VM(VMType, HeapType); - static VM*& sharedInstanceInternal(); - void createNativeThunk(); - - void updateStackLimit(); + void registerWatchpointForImpureProperty(const Identifier&, Watchpoint*); + // FIXME: Use AtomicString once it got merged with Identifier. + JS_EXPORT_PRIVATE void addImpureProperty(const String&); + private: + friend class LLIntOffsetsExtractor; + friend class ClearExceptionScope; + friend class RecursiveAllocationScope; + + VM(VMType, HeapType); + static VM*& sharedInstanceInternal(); + void createNativeThunk(); #if ENABLE(ASSEMBLER) - bool m_canUseAssembler; + bool m_canUseAssembler; #endif #if ENABLE(JIT) - bool m_canUseJIT; + bool m_canUseJIT; #endif #if ENABLE(YARR_JIT) - bool m_canUseRegExpJIT; + bool m_canUseRegExpJIT; #endif #if ENABLE(GC_VALIDATION) - const ClassInfo* m_initializingObjectClass; + const ClassInfo* m_initializingObjectClass; #endif - void* m_stackPointerAtVMEntry; - size_t m_reservedZoneSize; -#if !ENABLE(JIT) - struct { - void* m_stackLimit; - void* m_jsStackLimit; - }; + +#if USE(SEPARATE_C_AND_JS_STACK) + struct { + void* m_stackLimit; + void* m_jsStackLimit; + }; #else - union { - void* m_stackLimit; - void* m_jsStackLimit; - }; -#if ENABLE(FTL_JIT) - void* m_ftlStackLimit; - size_t m_largestFTLStackSize; + union { + void* m_stackLimit; + void* m_jsStackLimit; + }; #endif -#endif - void* m_lastStackTop; - Exception* m_exception { nullptr }; - Exception* m_lastException { nullptr }; - bool m_inDefineOwnProperty; - std::unique_ptr<CodeCache> m_codeCache; - LegacyProfiler* m_enabledProfiler; - std::unique_ptr<BuiltinExecutables> m_builtinExecutables; - HashMap<String, RefPtr<WatchpointSet>> m_impurePropertyWatchpointSets; - std::unique_ptr<TypeProfiler> m_typeProfiler; - std::unique_ptr<TypeProfilerLog> m_typeProfilerLog; - unsigned m_typeProfilerEnabledCount; - FunctionHasExecutedCache m_functionHasExecutedCache; - std::unique_ptr<ControlFlowProfiler> m_controlFlowProfiler; - unsigned m_controlFlowProfilerEnabledCount; - Deque<std::unique_ptr<QueuedTask>> m_microtaskQueue; -}; + JSValue m_exception; + bool m_inDefineOwnProperty; + OwnPtr<CodeCache> m_codeCache; + RefCountedArray<StackFrame> m_exceptionStack; -#if ENABLE(GC_VALIDATION) -inline bool VM::isInitializingObject() const -{ - return !!m_initializingObjectClass; -} - -inline void VM::setInitializingObjectClass(const ClassInfo* initializingObjectClass) -{ - m_initializingObjectClass = initializingObjectClass; -} -#endif + LegacyProfiler* m_enabledProfiler; -inline Heap* WeakSet::heap() const -{ - return &m_vm->heap; -} + HashMap<String, RefPtr<WatchpointSet>> m_impurePropertyWatchpointSets; + }; -#if ENABLE(JIT) -extern "C" void sanitizeStackForVMImpl(VM*); +#if ENABLE(GC_VALIDATION) + inline bool VM::isInitializingObject() const + { + return !!m_initializingObjectClass; + } + + inline void VM::setInitializingObjectClass(const ClassInfo* initializingObjectClass) + { + m_initializingObjectClass = initializingObjectClass; + } #endif -void sanitizeStackForVM(VM*); -void logSanitizeStack(VM*); + inline Heap* WeakSet::heap() const + { + return &m_vm->heap; + } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/VMEntryScope.cpp b/Source/JavaScriptCore/runtime/VMEntryScope.cpp index bc901b215..47782ce3b 100644 --- a/Source/JavaScriptCore/runtime/VMEntryScope.cpp +++ b/Source/JavaScriptCore/runtime/VMEntryScope.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2015 Apple Inc. All rights reserved. + * 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 @@ -27,18 +27,19 @@ #include "VMEntryScope.h" #include "Debugger.h" -#include "Options.h" #include "VM.h" -#include "Watchdog.h" #include <wtf/StackBounds.h> namespace JSC { VMEntryScope::VMEntryScope(VM& vm, JSGlobalObject* globalObject) : m_vm(vm) + , m_stack(wtfThreadData().stack()) , m_globalObject(globalObject) + , m_prev(vm.entryScope) + , m_prevStackLimit(vm.stackLimit()) + , m_recompilationNeeded(false) { - ASSERT(wtfThreadData().stack().isGrowingDownward()); if (!vm.entryScope) { #if ENABLE(ASSEMBLER) if (ExecutableAllocator::underMemoryPressure()) @@ -49,31 +50,46 @@ VMEntryScope::VMEntryScope(VM& vm, JSGlobalObject* globalObject) // Reset the date cache between JS invocations to force the VM to // observe time xone changes. vm.resetDateCache(); - - if (vm.watchdog) - vm.watchdog->enteredVM(); } + // Clear the exception stack between entries + vm.clearExceptionStack(); - vm.clearLastException(); + void* limit = m_stack.recursionLimit(requiredCapacity()); + vm.setStackLimit(limit); } -void VMEntryScope::setEntryScopeDidPopListener(void* key, EntryScopeDidPopListener listener) +VMEntryScope::~VMEntryScope() { - m_allEntryScopeDidPopListeners.set(key, listener); + m_vm.entryScope = m_prev; + m_vm.setStackLimit(m_prevStackLimit); + + if (m_recompilationNeeded) { + if (m_vm.entryScope) + m_vm.entryScope->setRecompilationNeeded(true); + else { + if (Debugger* debugger = m_globalObject->debugger()) + debugger->recompileAllJSFunctions(&m_vm); + } + } } -VMEntryScope::~VMEntryScope() +size_t VMEntryScope::requiredCapacity() const { - if (m_vm.entryScope != this) - return; - - if (m_vm.watchdog) - m_vm.watchdog->exitedVM(); + Interpreter* interpreter = m_vm.interpreter; - m_vm.entryScope = nullptr; + // We require a smaller stack budget for the error stack. This is to allow + // some minimal JS execution to proceed and do the work of throwing a stack + // overflow error if needed. In contrast, arbitrary JS code will require the + // more generous stack budget in order to proceed. + // + // 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; - for (auto& listener : m_allEntryScopeDidPopListeners.values()) - listener(m_vm, m_globalObject); + size_t requiredCapacity = interpreter->isInErrorHandlingMode() ? errorModeRequiredStack : requiredStack; + RELEASE_ASSERT(m_stack.size() >= requiredCapacity); + return requiredCapacity; } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/VMEntryScope.h b/Source/JavaScriptCore/runtime/VMEntryScope.h index 6a62831b8..d5ba823d0 100644 --- a/Source/JavaScriptCore/runtime/VMEntryScope.h +++ b/Source/JavaScriptCore/runtime/VMEntryScope.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * 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 @@ -27,7 +27,6 @@ #define VMEntryScope_h #include "Interpreter.h" -#include <wtf/HashMap.h> #include <wtf/StackBounds.h> #include <wtf/StackStats.h> @@ -43,15 +42,23 @@ public: JSGlobalObject* globalObject() const { return m_globalObject; } - typedef std::function<void (VM&, JSGlobalObject*)> EntryScopeDidPopListener; - void setEntryScopeDidPopListener(void*, EntryScopeDidPopListener); + void setRecompilationNeeded(bool recompileNeeded) { m_recompilationNeeded = recompileNeeded; } private: + size_t requiredCapacity() const; + VM& m_vm; + StackStats::CheckPoint m_stackCheckPoint; + StackBounds m_stack; JSGlobalObject* m_globalObject; - HashMap<void*, EntryScopeDidPopListener> m_allEntryScopeDidPopListeners; + + // m_prev and m_prevStackLimit may belong to a different thread's stack. + VMEntryScope* m_prev; + void* m_prevStackLimit; + bool m_recompilationNeeded; }; } // namespace JSC #endif // VMEntryScope_h + diff --git a/Source/JavaScriptCore/runtime/VMInlines.h b/Source/JavaScriptCore/runtime/VMInlines.h deleted file mode 100644 index fcc93888e..000000000 --- a/Source/JavaScriptCore/runtime/VMInlines.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2015 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 VMInlines_h -#define VMInlines_h - -#include "VM.h" -#include "Watchdog.h" - -namespace JSC { - -bool VM::shouldTriggerTermination(ExecState* exec) -{ - if (!watchdog) - return false; - return watchdog->didFire(exec); -} - -} // namespace JSC - -#endif // LLIntData_h - diff --git a/Source/JavaScriptCore/runtime/VarOffset.cpp b/Source/JavaScriptCore/runtime/VarOffset.cpp deleted file mode 100644 index e0d65e54f..000000000 --- a/Source/JavaScriptCore/runtime/VarOffset.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2015 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 "VarOffset.h" - -namespace JSC { - -void VarOffset::dump(PrintStream& out) const -{ - switch (m_kind) { - case VarKind::Invalid: - out.print("invalid"); - return; - case VarKind::Scope: - out.print(scopeOffset()); - return; - case VarKind::Stack: - out.print(stackOffset()); - return; - case VarKind::DirectArgument: - out.print(capturedArgumentsOffset()); - return; - } - RELEASE_ASSERT_NOT_REACHED(); -} - -} // namespace JSC - -namespace WTF { - -using namespace JSC; - -void printInternal(PrintStream& out, VarKind varKind) -{ - switch (varKind) { - case VarKind::Invalid: - out.print("Invalid"); - return; - case VarKind::Scope: - out.print("Scope"); - return; - case VarKind::Stack: - out.print("Stack"); - return; - case VarKind::DirectArgument: - out.print("DirectArgument"); - return; - } - RELEASE_ASSERT_NOT_REACHED(); -} - -} // namespace WTF - diff --git a/Source/JavaScriptCore/runtime/VarOffset.h b/Source/JavaScriptCore/runtime/VarOffset.h deleted file mode 100644 index b844f57e4..000000000 --- a/Source/JavaScriptCore/runtime/VarOffset.h +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (C) 2015 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 VarOffset_h -#define VarOffset_h - -#include "DirectArgumentsOffset.h" -#include "ScopeOffset.h" -#include "VirtualRegister.h" -#include <wtf/HashMap.h> - -namespace JSC { - -enum class VarKind : uint8_t { - Invalid, - Scope, - Stack, - DirectArgument -}; - -class VarOffset { -public: - VarOffset() - : m_kind(VarKind::Invalid) - , m_offset(UINT_MAX) - { - } - - VarOffset(WTF::HashTableDeletedValueType) - : m_kind(VarKind::Invalid) - , m_offset(0) - { - } - - explicit VarOffset(VirtualRegister stackOffset) - { - if (!stackOffset.isValid()) { - m_kind = VarKind::Invalid; - m_offset = UINT_MAX; - } else { - m_kind = VarKind::Stack; - m_offset = stackOffset.offset(); - } - } - - explicit VarOffset(ScopeOffset scopeOffset) - { - if (!scopeOffset) { - m_kind = VarKind::Invalid; - m_offset = UINT_MAX; - } else { - m_kind = VarKind::Scope; - m_offset = scopeOffset.offset(); - } - } - - explicit VarOffset(DirectArgumentsOffset capturedArgumentsOffset) - { - if (!capturedArgumentsOffset) { - m_kind = VarKind::Invalid; - m_offset = UINT_MAX; - } else { - m_kind = VarKind::DirectArgument; - m_offset = capturedArgumentsOffset.offset(); - } - } - - static VarOffset assemble(VarKind kind, unsigned offset) - { - VarOffset result; - result.m_kind = kind; - result.m_offset = offset; - result.checkSanity(); - return result; - } - - bool isValid() const - { - return m_kind != VarKind::Invalid; - } - - bool operator!() const - { - return !isValid(); - } - - VarKind kind() const { return m_kind; } - - bool isStack() const - { - return m_kind == VarKind::Stack; - } - - bool isScope() const - { - return m_kind == VarKind::Scope; - } - - bool isDirectArgument() const - { - return m_kind == VarKind::DirectArgument; - } - - VirtualRegister stackOffsetUnchecked() const - { - if (!isStack()) - return VirtualRegister(); - return VirtualRegister(m_offset); - } - - ScopeOffset scopeOffsetUnchecked() const - { - if (!isScope()) - return ScopeOffset(); - return ScopeOffset(m_offset); - } - - DirectArgumentsOffset capturedArgumentsOffsetUnchecked() const - { - if (!isDirectArgument()) - return DirectArgumentsOffset(); - return DirectArgumentsOffset(m_offset); - } - - VirtualRegister stackOffset() const - { - ASSERT(isStack()); - return VirtualRegister(m_offset); - } - - ScopeOffset scopeOffset() const - { - ASSERT(isScope()); - return ScopeOffset(m_offset); - } - - DirectArgumentsOffset capturedArgumentsOffset() const - { - ASSERT(isDirectArgument()); - return DirectArgumentsOffset(m_offset); - } - - unsigned rawOffset() const - { - ASSERT(isValid()); - return m_offset; - } - - void checkSanity() const - { - if (ASSERT_DISABLED) - return; - - switch (m_kind) { - case VarKind::Invalid: - ASSERT(m_offset == UINT_MAX); - return; - case VarKind::Scope: - ASSERT(scopeOffset()); - return; - case VarKind::Stack: - ASSERT(stackOffset().isValid()); - return; - case VarKind::DirectArgument: - ASSERT(capturedArgumentsOffset()); - return; - } - - ASSERT_NOT_REACHED(); - } - - bool operator==(const VarOffset& other) const - { - return m_kind == other.m_kind - && m_offset == other.m_offset; - } - - bool operator!=(const VarOffset& other) const - { - return !(*this == other); - } - - unsigned hash() const - { - return WTF::IntHash<unsigned>::hash((static_cast<unsigned>(m_kind) << 20) + m_offset); - } - - bool isHashTableDeletedValue() const - { - return m_kind == VarKind::Invalid && !m_offset; - } - - void dump(PrintStream&) const; - -private: - VarKind m_kind; - unsigned m_offset; -}; - -struct VarOffsetHash { - static unsigned hash(const VarOffset& key) { return key.hash(); } - static bool equal(const VarOffset& a, const VarOffset& b) { return a == b; } - static const bool safeToCompareToEmptyOrDeleted = true; -}; - -} // namespace JSC - -namespace WTF { - -void printInternal(PrintStream&, JSC::VarKind); - -template<typename T> struct DefaultHash; -template<> struct DefaultHash<JSC::VarOffset> { - typedef JSC::VarOffsetHash Hash; -}; - -template<typename T> struct HashTraits; -template<> struct HashTraits<JSC::VarOffset> : SimpleClassHashTraits<JSC::VarOffset> { - static const bool emptyValueIsZero = false; -}; - -} // namespace WTF - -#endif // VarOffset_h - diff --git a/Source/JavaScriptCore/runtime/Watchdog.cpp b/Source/JavaScriptCore/runtime/Watchdog.cpp index 044552cf9..573260b16 100644 --- a/Source/JavaScriptCore/runtime/Watchdog.cpp +++ b/Source/JavaScriptCore/runtime/Watchdog.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. + * 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 @@ -32,157 +32,168 @@ namespace JSC { -const std::chrono::microseconds Watchdog::noTimeLimit = std::chrono::microseconds::max(); - -static std::chrono::microseconds currentWallClockTime() -{ - auto steadyTimeSinceEpoch = std::chrono::steady_clock::now().time_since_epoch(); - return std::chrono::duration_cast<std::chrono::microseconds>(steadyTimeSinceEpoch); -} +#define NO_LIMIT std::numeric_limits<double>::infinity() Watchdog::Watchdog() : m_timerDidFire(false) - , m_timeLimit(noTimeLimit) - , m_cpuDeadline(noTimeLimit) - , m_wallClockDeadline(noTimeLimit) + , 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) - , m_timerQueue(WorkQueue::create("jsc.watchdog.queue", WorkQueue::Type::Serial, WorkQueue::QOS::Utility)) { - m_timerHandler = [this] { - { - LockHolder locker(m_lock); - this->m_timerDidFire = true; - } - this->deref(); - }; + initTimer(); } -void Watchdog::setTimeLimit(std::chrono::microseconds limit, +Watchdog::~Watchdog() +{ + ASSERT(!isArmed()); + stopCountdown(); + destroyTimer(); +} + +void Watchdog::setTimeLimit(VM& vm, double limit, ShouldTerminateCallback callback, void* data1, void* data2) { - LockHolder locker(m_lock); + bool wasEnabled = isEnabled(); + + if (!m_isStopped) + stopCountdown(); - m_timeLimit = limit; + m_didFire = false; // Reset the watchdog. + + m_limit = limit; m_callback = callback; m_callbackData1 = data1; m_callbackData2 = data2; - if (m_hasEnteredVM && hasTimeLimit()) - startTimer(locker, m_timeLimit); -} - -JS_EXPORT_PRIVATE void Watchdog::terminateSoon() -{ - LockHolder locker(m_lock); + // 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(); + } - m_timeLimit = std::chrono::microseconds(0); - m_cpuDeadline = std::chrono::microseconds(0); - m_wallClockDeadline = std::chrono::microseconds(0); - m_timerDidFire = true; + startCountdownIfNeeded(); } -bool Watchdog::didFireSlow(ExecState* exec) +bool Watchdog::didFire(ExecState* exec) { - { - LockHolder locker(m_lock); - - ASSERT(m_timerDidFire); - m_timerDidFire = false; - - if (currentWallClockTime() < m_wallClockDeadline) - return false; // Just a stale timer firing. Nothing to do. - - // Set m_wallClockDeadline to noTimeLimit here so that we can reject all future - // spurious wakes. - m_wallClockDeadline = noTimeLimit; + if (m_didFire) + return true; - auto cpuTime = currentCPUTime(); - if (cpuTime < m_cpuDeadline) { - auto remainingCPUTime = m_cpuDeadline - cpuTime; - startTimer(locker, remainingCPUTime); - return false; + 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; } - } - // Note: we should not be holding the lock while calling the callbacks. The callbacks may - // call setTimeLimit() which will try to lock as well. + // The m_callback may have set a new limit. So, we may need to restart + // the countdown. + startCountdownIfNeeded(); - // 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) - return true; + } else { + // Case 2: the allowed CPU time has NOT elapsed. - { - LockHolder locker(m_lock); - - // If we get here, then the callback above did not want to terminate execution. As a - // result, the callback may have done one of the following: - // 1. cleared the time limit (i.e. watchdog is disabled), - // 2. set a new time limit via Watchdog::setTimeLimit(), or - // 3. did nothing (i.e. allow another cycle of the current time limit). - // - // In the case of 1, we don't have to do anything. - // In the case of 2, Watchdog::setTimeLimit() would already have started the timer. - // In the case of 3, we need to re-start the timer here. - - ASSERT(m_hasEnteredVM); - bool callbackAlreadyStartedTimer = (m_cpuDeadline != noTimeLimit); - if (hasTimeLimit() && !callbackAlreadyStartedTimer) - startTimer(locker, m_timeLimit); + // 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::hasTimeLimit() +bool Watchdog::isEnabled() { - return (m_timeLimit != noTimeLimit); + return (m_limit != NO_LIMIT); } -void Watchdog::enteredVM() +void Watchdog::fire() { - m_hasEnteredVM = true; - if (hasTimeLimit()) { - LockHolder locker(m_lock); - startTimer(locker, m_timeLimit); - } + m_didFire = true; +} + +void Watchdog::arm() +{ + m_reentryCount++; + if (m_reentryCount == 1) + startCountdownIfNeeded(); } -void Watchdog::exitedVM() +void Watchdog::disarm() { - ASSERT(m_hasEnteredVM); - LockHolder locker(m_lock); - stopTimer(locker); - m_hasEnteredVM = false; + ASSERT(m_reentryCount > 0); + if (m_reentryCount == 1) + stopCountdown(); + m_reentryCount--; } -void Watchdog::startTimer(LockHolder&, std::chrono::microseconds timeLimit) +void Watchdog::startCountdownIfNeeded() { - ASSERT(m_hasEnteredVM); - ASSERT(hasTimeLimit()); - ASSERT(timeLimit <= m_timeLimit); + if (!m_isStopped) + return; // Already started. - m_cpuDeadline = currentCPUTime() + timeLimit; - auto wallClockTime = currentWallClockTime(); - auto wallClockDeadline = wallClockTime + timeLimit; + if (!isArmed()) + return; // Not executing JS script. No need to start. - if ((wallClockTime < m_wallClockDeadline) - && (m_wallClockDeadline <= wallClockDeadline)) - return; // Wait for the current active timer to expire before starting a new one. + if (isEnabled()) { + m_elapsedTime = 0; + m_startTime = currentCPUTime(); + startCountdown(m_limit); + } +} + +void Watchdog::startCountdown(double limit) +{ + ASSERT(m_isStopped); + m_isStopped = false; + startTimer(limit); +} - // Else, the current active timer won't fire soon enough. So, start a new timer. - this->ref(); // m_timerHandler will deref to match later. - m_wallClockDeadline = wallClockDeadline; +void Watchdog::stopCountdown() +{ + if (m_isStopped) + return; + stopTimer(); + m_isStopped = true; +} - m_timerQueue->dispatchAfter(std::chrono::nanoseconds(timeLimit), m_timerHandler); +Watchdog::Scope::Scope(Watchdog& watchdog) + : m_watchdog(watchdog) +{ + m_watchdog.arm(); } -void Watchdog::stopTimer(LockHolder&) +Watchdog::Scope::~Scope() { - m_cpuDeadline = noTimeLimit; + m_watchdog.disarm(); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Watchdog.h b/Source/JavaScriptCore/runtime/Watchdog.h index cfd9fb14b..15784d6e2 100644 --- a/Source/JavaScriptCore/runtime/Watchdog.h +++ b/Source/JavaScriptCore/runtime/Watchdog.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. + * 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 @@ -26,76 +26,91 @@ #ifndef Watchdog_h #define Watchdog_h -#include <wtf/Lock.h> -#include <wtf/Ref.h> -#include <wtf/ThreadSafeRefCounted.h> -#include <wtf/WorkQueue.h> +#if PLATFORM(MAC) || PLATFORM(IOS) +#include <dispatch/dispatch.h> +#endif namespace JSC { class ExecState; class VM; -class Watchdog : public WTF::ThreadSafeRefCounted<Watchdog> { - WTF_MAKE_FAST_ALLOCATED; +class Watchdog { public: class Scope; Watchdog(); + ~Watchdog(); typedef bool (*ShouldTerminateCallback)(ExecState*, void* data1, void* data2); - void setTimeLimit(std::chrono::microseconds limit, ShouldTerminateCallback = 0, void* data1 = 0, void* data2 = 0); - JS_EXPORT_PRIVATE void terminateSoon(); + void setTimeLimit(VM&, double seconds, ShouldTerminateCallback = 0, void* data1 = 0, void* data2 = 0); - bool didFire(ExecState* exec) - { - if (!m_timerDidFire) - return false; - return didFireSlow(exec); - } + // 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 hasTimeLimit(); - void enteredVM(); - void exitedVM(); + bool isEnabled(); - void* timerDidFireAddress() { return &m_timerDidFire; } + // 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. + bool didFire() { return m_didFire; } + JS_EXPORT_PRIVATE void fire(); - static const std::chrono::microseconds noTimeLimit; + void* timerDidFireAddress() { return &m_timerDidFire; } private: - void startTimer(LockHolder&, std::chrono::microseconds timeLimit); - void stopTimer(LockHolder&); - - bool didFireSlow(ExecState*); - - // m_timerDidFire indicates whether the timer fired. The Watchdog + 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; - std::chrono::microseconds m_timeLimit; - - std::chrono::microseconds m_cpuDeadline; - std::chrono::microseconds m_wallClockDeadline; - - // Writes to m_timerDidFire and m_timeLimit, and Reads+Writes to m_cpuDeadline and m_wallClockDeadline - // must be guarded by this lock. - Lock m_lock; + // All time units are in seconds. + double m_limit; + double m_startTime; + double m_elapsedTime; - bool m_hasEnteredVM { false }; + int m_reentryCount; + bool m_isStopped; ShouldTerminateCallback m_callback; void* m_callbackData1; void* m_callbackData2; - Ref<WorkQueue> m_timerQueue; - std::function<void ()> m_timerHandler; +#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 deleted file mode 100644 index e69de29bb..000000000 --- a/Source/JavaScriptCore/runtime/WatchdogMac.cpp +++ /dev/null diff --git a/Source/JavaScriptCore/runtime/WatchdogNone.cpp b/Source/JavaScriptCore/runtime/WatchdogNone.cpp index e69de29bb..615314bb3 100644 --- a/Source/JavaScriptCore/runtime/WatchdogNone.cpp +++ 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 16d3d4400..d9c1fb63e 100644 --- a/Source/JavaScriptCore/runtime/WeakGCMap.h +++ b/Source/JavaScriptCore/runtime/WeakGCMap.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,7 +37,6 @@ namespace JSC { template<typename KeyArg, typename ValueArg, typename HashArg = typename DefaultHash<KeyArg>::Hash, typename KeyTraitsArg = HashTraits<KeyArg>> class WeakGCMap { - WTF_MAKE_FAST_ALLOCATED; typedef Weak<ValueArg> ValueType; typedef HashMap<KeyArg, ValueType, HashArg, KeyTraitsArg> HashMapType; @@ -47,8 +46,10 @@ public: typedef typename HashMapType::iterator iterator; typedef typename HashMapType::const_iterator const_iterator; - explicit WeakGCMap(VM&); - ~WeakGCMap(); + WeakGCMap() + : m_gcThreshold(minGCThreshold) + { + } ValueArg* get(const KeyType& key) const { @@ -57,7 +58,19 @@ public: AddResult set(const KeyType& key, ValueType value) { - return m_map.set(key, WTF::move(value)); + gcMapIfNeeded(); + return m_map.set(key, std::move(value)); + } + + AddResult add(const KeyType& key, ValueType value) + { + gcMapIfNeeded(); + AddResult addResult = m_map.add(key, nullptr); + if (!addResult.iterator->value) { // New value or found a zombie value. + addResult.isNewEntry = true; + addResult.iterator->value = std::move(value); + } + return addResult; } bool remove(const KeyType& key) @@ -70,17 +83,6 @@ public: m_map.clear(); } - bool isEmpty() const - { - const_iterator it = m_map.begin(); - const_iterator end = m_map.end(); - while (it != end) { - if (it->value) - return true; - } - return false; - } - iterator find(const KeyType& key) { iterator it = m_map.find(key); @@ -95,27 +97,43 @@ public: return const_cast<WeakGCMap*>(this)->find(key); } - template<typename Functor> - void forEach(Functor functor) + bool contains(const KeyType& key) const { - for (auto& pair : m_map) { - if (pair.value) - functor(pair.key, pair.value.get()); - } + return find(key) != m_map.end(); } - bool contains(const KeyType& key) const +private: + static const int minGCThreshold = 3; + + void gcMap() { - return find(key) != m_map.end(); + Vector<KeyType, 4> zombies; + + for (iterator it = m_map.begin(), end = m_map.end(); it != end; ++it) { + if (!it->value) + zombies.append(it->key); + } + + for (size_t i = 0; i < zombies.size(); ++i) + m_map.remove(zombies[i]); } - void pruneStaleEntries(); + void gcMapIfNeeded() + { + if (m_map.size() < m_gcThreshold) + return; + + gcMap(); + m_gcThreshold = std::max(minGCThreshold, m_map.size() * 2 - 1); + } -private: HashMapType m_map; - VM& m_vm; + 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/WeakGCMapInlines.h b/Source/JavaScriptCore/runtime/WeakGCMapInlines.h deleted file mode 100644 index b90acc089..000000000 --- a/Source/JavaScriptCore/runtime/WeakGCMapInlines.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2015 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 WeakGCMapInlines_h -#define WeakGCMapInlines_h - -#include "HeapInlines.h" -#include "WeakGCMap.h" - -namespace JSC { - -template<typename KeyArg, typename ValueArg, typename HashArg, typename KeyTraitsArg> -inline WeakGCMap<KeyArg, ValueArg, HashArg, KeyTraitsArg>::WeakGCMap(VM& vm) - : m_vm(vm) -{ - vm.heap.registerWeakGCMap(this, [this]() { - pruneStaleEntries(); - }); -} - -template<typename KeyArg, typename ValueArg, typename HashArg, typename KeyTraitsArg> -inline WeakGCMap<KeyArg, ValueArg, HashArg, KeyTraitsArg>::~WeakGCMap() -{ - m_vm.heap.unregisterWeakGCMap(this); -} - -template<typename KeyArg, typename ValueArg, typename HashArg, typename KeyTraitsArg> -NEVER_INLINE void WeakGCMap<KeyArg, ValueArg, HashArg, KeyTraitsArg>::pruneStaleEntries() -{ - m_map.removeIf([](typename HashMapType::KeyValuePairType& entry) { - return !entry.value; - }); -} - -} // namespace JSC - -#endif // WeakGCMapInlines_h diff --git a/Source/JavaScriptCore/runtime/WeakMapConstructor.cpp b/Source/JavaScriptCore/runtime/WeakMapConstructor.cpp index 23c43330d..f3540faaa 100644 --- a/Source/JavaScriptCore/runtime/WeakMapConstructor.cpp +++ b/Source/JavaScriptCore/runtime/WeakMapConstructor.cpp @@ -26,18 +26,15 @@ #include "config.h" #include "WeakMapConstructor.h" -#include "Error.h" -#include "IteratorOperations.h" #include "JSCJSValueInlines.h" #include "JSCellInlines.h" #include "JSGlobalObject.h" #include "JSWeakMap.h" -#include "StructureInlines.h" #include "WeakMapPrototype.h" namespace JSC { -const ClassInfo WeakMapConstructor::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(WeakMapConstructor) }; +const ClassInfo WeakMapConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(WeakMapConstructor) }; void WeakMapConstructor::finishCreation(VM& vm, WeakMapPrototype* prototype) { @@ -46,87 +43,11 @@ void WeakMapConstructor::finishCreation(VM& vm, WeakMapPrototype* prototype) putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), ReadOnly | DontEnum | DontDelete); } -static EncodedJSValue JSC_HOST_CALL callWeakMap(ExecState* exec) -{ - return JSValue::encode(throwTypeError(exec, ASCIILiteral("WeakMap cannot be called as a function"))); -} - static EncodedJSValue JSC_HOST_CALL constructWeakMap(ExecState* exec) { JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject(); - Structure* weakMapStructure = globalObject->weakMapStructure(); - JSWeakMap* weakMap = JSWeakMap::create(exec, weakMapStructure); - JSValue iterable = exec->argument(0); - if (iterable.isUndefinedOrNull()) - return JSValue::encode(weakMap); - - JSValue adderFunction = weakMap->JSObject::get(exec, exec->propertyNames().set); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - CallData adderFunctionCallData; - CallType adderFunctionCallType = getCallData(adderFunction, adderFunctionCallData); - if (adderFunctionCallType == CallTypeNone) - return JSValue::encode(throwTypeError(exec)); - - JSValue iteratorFunction = iterable.get(exec, exec->propertyNames().iteratorSymbol); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - CallData iteratorFunctionCallData; - CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData); - if (iteratorFunctionCallType == CallTypeNone) - return JSValue::encode(throwTypeError(exec)); - - ArgList iteratorFunctionArguments; - JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - if (!iterator.isObject()) - return JSValue::encode(throwTypeError(exec)); - - while (true) { - JSValue next = iteratorStep(exec, iterator); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - if (next.isFalse()) - return JSValue::encode(weakMap); - - JSValue nextItem = iteratorValue(exec, next); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - if (!nextItem.isObject()) { - throwTypeError(exec); - iteratorClose(exec, iterator); - return JSValue::encode(jsUndefined()); - } - - JSValue key = nextItem.get(exec, 0); - if (exec->hadException()) { - iteratorClose(exec, iterator); - return JSValue::encode(jsUndefined()); - } - - JSValue value = nextItem.get(exec, 1); - if (exec->hadException()) { - iteratorClose(exec, iterator); - return JSValue::encode(jsUndefined()); - } - - MarkedArgumentBuffer arguments; - arguments.append(key); - arguments.append(value); - call(exec, adderFunction, adderFunctionCallType, adderFunctionCallData, weakMap, arguments); - if (exec->hadException()) { - iteratorClose(exec, iterator); - return JSValue::encode(jsUndefined()); - } - } - RELEASE_ASSERT_NOT_REACHED(); - return JSValue::encode(weakMap); + Structure* structure = globalObject->weakMapStructure(); + return JSValue::encode(JSWeakMap::create(exec, structure)); } ConstructType WeakMapConstructor::getConstructData(JSCell*, ConstructData& constructData) @@ -135,10 +56,9 @@ ConstructType WeakMapConstructor::getConstructData(JSCell*, ConstructData& const return ConstructTypeHost; } -CallType WeakMapConstructor::getCallData(JSCell*, CallData& callData) +CallType WeakMapConstructor::getCallData(JSCell*, CallData&) { - callData.native.function = callWeakMap; - return CallTypeHost; + return CallTypeNone; } } diff --git a/Source/JavaScriptCore/runtime/WeakMapData.cpp b/Source/JavaScriptCore/runtime/WeakMapData.cpp index 8ee9de74a..224be8a46 100644 --- a/Source/JavaScriptCore/runtime/WeakMapData.cpp +++ b/Source/JavaScriptCore/runtime/WeakMapData.cpp @@ -36,7 +36,7 @@ namespace JSC { -const ClassInfo WeakMapData::s_info = { "WeakMapData", 0, 0, CREATE_METHOD_TABLE(WeakMapData) }; +const ClassInfo WeakMapData::s_info = { "WeakMapData", 0, 0, 0, CREATE_METHOD_TABLE(WeakMapData) }; WeakMapData::WeakMapData(VM& vm) : Base(vm, vm.weakMapDataStructure.get()) @@ -64,7 +64,7 @@ void WeakMapData::visitChildren(JSCell* cell, SlotVisitor& visitor) // Rough approximation of the external storage needed for the hashtable. // This isn't exact, but it is close enough, and proportional to the actual // external mermory usage. - visitor.reportExtraMemoryVisited(thisObj, thisObj->m_map.capacity() * (sizeof(JSObject*) + sizeof(WriteBarrier<Unknown>))); + visitor.reportExtraMemoryUsage(thisObj, thisObj->m_map.capacity() * (sizeof(JSObject*) + sizeof(WriteBarrier<Unknown>))); } void WeakMapData::set(VM& vm, JSObject* key, JSValue value) diff --git a/Source/JavaScriptCore/runtime/WeakMapData.h b/Source/JavaScriptCore/runtime/WeakMapData.h index cfcd85355..0cb7b735a 100644 --- a/Source/JavaScriptCore/runtime/WeakMapData.h +++ b/Source/JavaScriptCore/runtime/WeakMapData.h @@ -34,10 +34,9 @@ namespace JSC { -class WeakMapData final : public JSCell { +class WeakMapData : public JSCell { public: typedef JSCell Base; - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; static WeakMapData* create(VM& vm) { @@ -48,10 +47,11 @@ public: static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); + return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, StructureFlags), info()); } static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; void set(VM&, JSObject*, JSValue); JSValue get(JSObject*); @@ -61,11 +61,7 @@ public: DECLARE_INFO; - typedef HashMap<JSObject*, WriteBarrier<Unknown>> MapType; - MapType::const_iterator begin() const { return m_map.begin(); } - MapType::const_iterator end() const { return m_map.end(); } - - int size() const { return m_map.size(); } + static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; private: WeakMapData(VM&); @@ -82,10 +78,11 @@ private: private: virtual void visitWeakReferences(SlotVisitor&) override; virtual void finalizeUnconditionally() override; - unsigned m_liveKeyCount; + int m_liveKeyCount; WeakMapData* m_target; }; DeadKeyCleaner m_deadKeyCleaner; + typedef HashMap<JSObject*, WriteBarrier<Unknown>> MapType; MapType m_map; }; diff --git a/Source/JavaScriptCore/runtime/WeakMapPrototype.cpp b/Source/JavaScriptCore/runtime/WeakMapPrototype.cpp index 71c4c4055..3a2f9622a 100644 --- a/Source/JavaScriptCore/runtime/WeakMapPrototype.cpp +++ b/Source/JavaScriptCore/runtime/WeakMapPrototype.cpp @@ -28,13 +28,13 @@ #include "JSCJSValueInlines.h" #include "JSWeakMap.h" -#include "StructureInlines.h" #include "WeakMapData.h" namespace JSC { -const ClassInfo WeakMapPrototype::s_info = { "WeakMap", &Base::s_info, 0, CREATE_METHOD_TABLE(WeakMapPrototype) }; +const ClassInfo WeakMapPrototype::s_info = { "WeakMap", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(WeakMapPrototype) }; +static EncodedJSValue JSC_HOST_CALL protoFuncWeakMapClear(ExecState*); static EncodedJSValue JSC_HOST_CALL protoFuncWeakMapDelete(ExecState*); static EncodedJSValue JSC_HOST_CALL protoFuncWeakMapGet(ExecState*); static EncodedJSValue JSC_HOST_CALL protoFuncWeakMapHas(ExecState*); @@ -46,6 +46,7 @@ void WeakMapPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) ASSERT(inherits(info())); vm.prototypeMap.addPrototype(this); + JSC_NATIVE_FUNCTION(vm.propertyNames->clear, protoFuncWeakMapClear, DontEnum, 0); JSC_NATIVE_FUNCTION(vm.propertyNames->deleteKeyword, protoFuncWeakMapDelete, DontEnum, 1); JSC_NATIVE_FUNCTION(vm.propertyNames->get, protoFuncWeakMapGet, DontEnum, 1); JSC_NATIVE_FUNCTION(vm.propertyNames->has, protoFuncWeakMapHas, DontEnum, 1); @@ -56,14 +57,23 @@ static WeakMapData* getWeakMapData(CallFrame* callFrame, JSValue value) { if (!value.isObject()) { throwTypeError(callFrame, WTF::ASCIILiteral("Called WeakMap function on non-object")); - return nullptr; + return 0; } if (JSWeakMap* weakMap = jsDynamicCast<JSWeakMap*>(value)) return weakMap->weakMapData(); throwTypeError(callFrame, WTF::ASCIILiteral("Called WeakMap function on a non-WeakMap object")); - return nullptr; + return 0; +} + +EncodedJSValue JSC_HOST_CALL protoFuncWeakMapClear(CallFrame* callFrame) +{ + WeakMapData* map = getWeakMapData(callFrame, callFrame->thisValue()); + if (!map) + return JSValue::encode(jsUndefined()); + map->clear(); + return JSValue::encode(jsUndefined()); } EncodedJSValue JSC_HOST_CALL protoFuncWeakMapDelete(CallFrame* callFrame) @@ -72,7 +82,9 @@ EncodedJSValue JSC_HOST_CALL protoFuncWeakMapDelete(CallFrame* callFrame) if (!map) return JSValue::encode(jsUndefined()); JSValue key = callFrame->argument(0); - return JSValue::encode(jsBoolean(key.isObject() && map->remove(asObject(key)))); + if (!key.isObject()) + return JSValue::encode(throwTypeError(callFrame, WTF::ASCIILiteral("A WeakMap cannot have a non-object key"))); + return JSValue::encode(jsBoolean(map->remove(asObject(key)))); } EncodedJSValue JSC_HOST_CALL protoFuncWeakMapGet(CallFrame* callFrame) @@ -82,7 +94,7 @@ EncodedJSValue JSC_HOST_CALL protoFuncWeakMapGet(CallFrame* callFrame) return JSValue::encode(jsUndefined()); JSValue key = callFrame->argument(0); if (!key.isObject()) - return JSValue::encode(jsUndefined()); + return JSValue::encode(throwTypeError(callFrame, WTF::ASCIILiteral("A WeakMap cannot have a non-object key"))); return JSValue::encode(map->get(asObject(key))); } @@ -92,7 +104,9 @@ EncodedJSValue JSC_HOST_CALL protoFuncWeakMapHas(CallFrame* callFrame) if (!map) return JSValue::encode(jsUndefined()); JSValue key = callFrame->argument(0); - return JSValue::encode(jsBoolean(key.isObject() && map->contains(asObject(key)))); + if (!key.isObject()) + return JSValue::encode(throwTypeError(callFrame, WTF::ASCIILiteral("A WeakMap cannot have a non-object key"))); + return JSValue::encode(jsBoolean(map->contains(asObject(key)))); } EncodedJSValue JSC_HOST_CALL protoFuncWeakMapSet(CallFrame* callFrame) diff --git a/Source/JavaScriptCore/runtime/WeakRandom.h b/Source/JavaScriptCore/runtime/WeakRandom.h index 98b23c70d..3cd1016d3 100644 --- a/Source/JavaScriptCore/runtime/WeakRandom.h +++ b/Source/JavaScriptCore/runtime/WeakRandom.h @@ -56,11 +56,11 @@ namespace JSC { class WeakRandom { -friend class JSGlobalObject; // For access to initializeSeed() during replay. public: WeakRandom(unsigned seed) + : m_low(seed ^ 0x49616E42) + , m_high(seed) { - initializeSeed(seed); } // Returns the seed provided that you've never called get() or getUint32(). @@ -85,12 +85,6 @@ private: return m_high; } - void initializeSeed(unsigned seed) - { - m_low = seed ^ 0x49616E42; - m_high = seed; - } - unsigned m_low; unsigned m_high; }; diff --git a/Source/JavaScriptCore/runtime/WeakSetConstructor.cpp b/Source/JavaScriptCore/runtime/WeakSetConstructor.cpp deleted file mode 100644 index f24ea8136..000000000 --- a/Source/JavaScriptCore/runtime/WeakSetConstructor.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2015 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 "WeakSetConstructor.h" - -#include "Error.h" -#include "IteratorOperations.h" -#include "JSCJSValueInlines.h" -#include "JSCellInlines.h" -#include "JSGlobalObject.h" -#include "JSWeakSet.h" -#include "StructureInlines.h" -#include "WeakSetPrototype.h" - -namespace JSC { - -const ClassInfo WeakSetConstructor::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(WeakSetConstructor) }; - -void WeakSetConstructor::finishCreation(VM& vm, WeakSetPrototype* prototype) -{ - Base::finishCreation(vm, prototype->classInfo()->className); - putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, DontEnum | DontDelete | ReadOnly); - putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), ReadOnly | DontEnum | DontDelete); -} - -static EncodedJSValue JSC_HOST_CALL callWeakSet(ExecState* exec) -{ - return JSValue::encode(throwTypeError(exec, ASCIILiteral("WeakSet cannot be called as a function"))); -} - -static EncodedJSValue JSC_HOST_CALL constructWeakSet(ExecState* exec) -{ - JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject(); - Structure* weakSetStructure = globalObject->weakSetStructure(); - JSWeakSet* weakSet = JSWeakSet::create(exec, weakSetStructure); - JSValue iterable = exec->argument(0); - if (iterable.isUndefinedOrNull()) - return JSValue::encode(weakSet); - - JSValue adderFunction = weakSet->JSObject::get(exec, exec->propertyNames().add); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - CallData adderFunctionCallData; - CallType adderFunctionCallType = getCallData(adderFunction, adderFunctionCallData); - if (adderFunctionCallType == CallTypeNone) - return JSValue::encode(throwTypeError(exec)); - - JSValue iteratorFunction = iterable.get(exec, exec->propertyNames().iteratorSymbol); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - CallData iteratorFunctionCallData; - CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData); - if (iteratorFunctionCallType == CallTypeNone) - return JSValue::encode(throwTypeError(exec)); - - ArgList iteratorFunctionArguments; - JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - if (!iterator.isObject()) - return JSValue::encode(throwTypeError(exec)); - - while (true) { - JSValue next = iteratorStep(exec, iterator); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - if (next.isFalse()) - return JSValue::encode(weakSet); - - JSValue nextValue = iteratorValue(exec, next); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - MarkedArgumentBuffer arguments; - arguments.append(nextValue); - call(exec, adderFunction, adderFunctionCallType, adderFunctionCallData, weakSet, arguments); - if (exec->hadException()) { - iteratorClose(exec, iterator); - return JSValue::encode(jsUndefined()); - } - } - RELEASE_ASSERT_NOT_REACHED(); - return JSValue::encode(weakSet); -} - -ConstructType WeakSetConstructor::getConstructData(JSCell*, ConstructData& constructData) -{ - constructData.native.function = constructWeakSet; - return ConstructTypeHost; -} - -CallType WeakSetConstructor::getCallData(JSCell*, CallData& callData) -{ - callData.native.function = callWeakSet; - return CallTypeHost; -} - -} diff --git a/Source/JavaScriptCore/runtime/WeakSetPrototype.cpp b/Source/JavaScriptCore/runtime/WeakSetPrototype.cpp deleted file mode 100644 index b718af74e..000000000 --- a/Source/JavaScriptCore/runtime/WeakSetPrototype.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2015 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 "WeakSetPrototype.h" - -#include "JSCJSValueInlines.h" -#include "JSWeakSet.h" -#include "StructureInlines.h" -#include "WeakMapData.h" - -namespace JSC { - -const ClassInfo WeakSetPrototype::s_info = { "WeakSet", &Base::s_info, 0, CREATE_METHOD_TABLE(WeakSetPrototype) }; - -static EncodedJSValue JSC_HOST_CALL protoFuncWeakSetDelete(ExecState*); -static EncodedJSValue JSC_HOST_CALL protoFuncWeakSetHas(ExecState*); -static EncodedJSValue JSC_HOST_CALL protoFuncWeakSetAdd(ExecState*); - -void WeakSetPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); - vm.prototypeMap.addPrototype(this); - - JSC_NATIVE_FUNCTION(vm.propertyNames->deleteKeyword, protoFuncWeakSetDelete, DontEnum, 1); - JSC_NATIVE_FUNCTION(vm.propertyNames->has, protoFuncWeakSetHas, DontEnum, 1); - JSC_NATIVE_FUNCTION(vm.propertyNames->add, protoFuncWeakSetAdd, DontEnum, 1); -} - -static WeakMapData* getWeakMapData(CallFrame* callFrame, JSValue value) -{ - if (!value.isObject()) { - throwTypeError(callFrame, WTF::ASCIILiteral("Called WeakSet function on non-object")); - return nullptr; - } - - if (JSWeakSet* weakSet = jsDynamicCast<JSWeakSet*>(value)) - return weakSet->weakMapData(); - - throwTypeError(callFrame, WTF::ASCIILiteral("Called WeakSet function on a non-WeakSet object")); - return nullptr; -} - -EncodedJSValue JSC_HOST_CALL protoFuncWeakSetDelete(CallFrame* callFrame) -{ - WeakMapData* map = getWeakMapData(callFrame, callFrame->thisValue()); - if (!map) - return JSValue::encode(jsUndefined()); - JSValue key = callFrame->argument(0); - return JSValue::encode(jsBoolean(key.isObject() && map->remove(asObject(key)))); -} - -EncodedJSValue JSC_HOST_CALL protoFuncWeakSetHas(CallFrame* callFrame) -{ - WeakMapData* map = getWeakMapData(callFrame, callFrame->thisValue()); - if (!map) - return JSValue::encode(jsUndefined()); - JSValue key = callFrame->argument(0); - return JSValue::encode(jsBoolean(key.isObject() && map->contains(asObject(key)))); -} - -EncodedJSValue JSC_HOST_CALL protoFuncWeakSetAdd(CallFrame* callFrame) -{ - WeakMapData* map = getWeakMapData(callFrame, callFrame->thisValue()); - if (!map) - return JSValue::encode(jsUndefined()); - JSValue key = callFrame->argument(0); - if (!key.isObject()) - return JSValue::encode(throwTypeError(callFrame, WTF::ASCIILiteral("Attempted to add a non-object key to a WeakSet"))); - map->set(callFrame->vm(), asObject(key), jsUndefined()); - return JSValue::encode(callFrame->thisValue()); -} - -} diff --git a/Source/JavaScriptCore/runtime/WriteBarrier.h b/Source/JavaScriptCore/runtime/WriteBarrier.h index 0f70e1ea0..06161cd98 100644 --- a/Source/JavaScriptCore/runtime/WriteBarrier.h +++ b/Source/JavaScriptCore/runtime/WriteBarrier.h @@ -71,7 +71,13 @@ 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(VM&, const JSCell* owner, T* value); + void set(VM& vm, const JSCell* owner, T* value) + { + ASSERT(value); + ASSERT(!Options::enableConcurrentJIT() || !isCompilationThread()); + validateCell(value); + setEarlyValue(vm, owner, value); + } // This is meant to be used like operator=, but is called copyFrom instead, in // order to kindly inform the C++ compiler that its advice is not appreciated. @@ -80,11 +86,20 @@ public: m_cell = other.m_cell; } - void setMayBeNull(VM&, const JSCell* owner, T* value); + void setMayBeNull(VM& vm, const JSCell* owner, T* value) + { + if (value) + validateCell(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(VM&, 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); + } T* get() const { @@ -113,7 +128,8 @@ public: T** slot() { return reinterpret_cast<T**>(&m_cell); } - explicit operator bool() const { return m_cell; } + typedef T* (WriteBarrierBase::*UnspecifiedBoolType); + operator UnspecifiedBoolType*() const { return m_cell ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; } bool operator!() const { return !m_cell; } @@ -125,7 +141,9 @@ public: this->m_cell = reinterpret_cast<JSCell*>(value); } +#if ENABLE(GC_VALIDATION) T* unvalidatedGet() const { return reinterpret_cast<T*>(static_cast<void*>(m_cell)); } +#endif private: JSCell* m_cell; @@ -133,7 +151,13 @@ private: template <> class WriteBarrierBase<Unknown> { public: - void set(VM&, const JSCell* owner, JSValue); + void set(VM&, const JSCell* owner, JSValue value) + { + ASSERT(!Options::enableConcurrentJIT() || !isCompilationThread()); + m_value = JSValue::encode(value); + Heap::writeBarrier(owner, value); + } + void setWithoutWriteBarrier(JSValue value) { m_value = JSValue::encode(value); @@ -145,12 +169,10 @@ public: } void clear() { m_value = JSValue::encode(JSValue()); } void setUndefined() { m_value = JSValue::encode(jsUndefined()); } - void setStartingValue(JSValue value) { m_value = JSValue::encode(value); } bool isNumber() const { return get().isNumber(); } bool isObject() const { return get().isObject(); } bool isNull() const { return get().isNull(); } bool isGetterSetter() const { return get().isGetterSetter(); } - bool isCustomGetterSetter() const { return get().isCustomGetterSetter(); } JSValue* slot() { @@ -165,7 +187,8 @@ public: int32_t* tagPointer() { return &bitwise_cast<EncodedValueDescriptor*>(&m_value)->asBits.tag; } int32_t* payloadPointer() { return &bitwise_cast<EncodedValueDescriptor*>(&m_value)->asBits.payload; } - explicit operator bool() const { return !!get(); } + typedef JSValue (WriteBarrierBase::*UnspecifiedBoolType); + operator UnspecifiedBoolType*() const { return get() ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; } bool operator!() const { return !get(); } private: @@ -173,7 +196,6 @@ private: }; template <typename T> class WriteBarrier : public WriteBarrierBase<T> { - WTF_MAKE_FAST_ALLOCATED; public: WriteBarrier() { @@ -198,18 +220,12 @@ public: } }; -enum UndefinedWriteBarrierTagType { UndefinedWriteBarrierTag }; template <> class WriteBarrier<Unknown> : public WriteBarrierBase<Unknown> { - WTF_MAKE_FAST_ALLOCATED; public: WriteBarrier() { this->setWithoutWriteBarrier(JSValue()); } - WriteBarrier(UndefinedWriteBarrierTagType) - { - this->setWithoutWriteBarrier(jsUndefined()); - } WriteBarrier(VM& vm, const JSCell* owner, JSValue value) { diff --git a/Source/JavaScriptCore/runtime/WriteBarrierInlines.h b/Source/JavaScriptCore/runtime/WriteBarrierInlines.h deleted file mode 100644 index 8271e48d6..000000000 --- a/Source/JavaScriptCore/runtime/WriteBarrierInlines.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2014 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 WriteBarrierInlines_h -#define WriteBarrierInlines_h - -#include "VM.h" -#include "WriteBarrier.h" - -namespace JSC { - -template <typename T> -inline void WriteBarrierBase<T>::set(VM& vm, const JSCell* owner, T* value) -{ - ASSERT(value); - ASSERT(!Options::enableConcurrentJIT() || !isCompilationThread()); - validateCell(value); - setEarlyValue(vm, owner, value); -} - -template <typename T> -inline void WriteBarrierBase<T>::setMayBeNull(VM& vm, const JSCell* owner, T* value) -{ - if (value) - validateCell(value); - setEarlyValue(vm, owner, value); -} - -template <typename T> -inline void WriteBarrierBase<T>::setEarlyValue(VM& vm, const JSCell* owner, T* value) -{ - this->m_cell = reinterpret_cast<JSCell*>(value); - vm.heap.writeBarrier(owner, this->m_cell); -} - -inline void WriteBarrierBase<Unknown>::set(VM& vm, const JSCell* owner, JSValue value) -{ - ASSERT(!Options::enableConcurrentJIT() || !isCompilationThread()); - m_value = JSValue::encode(value); - vm.heap.writeBarrier(owner, value); -} - -} // namespace JSC - -#endif // WriteBarrierInlines_h |
