diff options
Diffstat (limited to 'src/3rdparty/javascriptcore/JavaScriptCore/runtime')
166 files changed, 30234 insertions, 0 deletions
diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArgList.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArgList.cpp new file mode 100644 index 0000000..0b5d958 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArgList.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 "ArgList.h" + +#include "JSValue.h" +#include "JSCell.h" + +using std::min; + +namespace JSC { + +void ArgList::getSlice(int startIndex, ArgList& result) const +{ + if (startIndex <= 0 || static_cast<unsigned>(startIndex) >= m_argCount) { + result = ArgList(m_args, 0); + return; + } + result = ArgList(m_args + startIndex, m_argCount - startIndex); +} + +void MarkedArgumentBuffer::markLists(ListSet& markSet) +{ + ListSet::iterator end = markSet.end(); + for (ListSet::iterator it = markSet.begin(); it != end; ++it) { + MarkedArgumentBuffer* list = *it; + + iterator end2 = list->end(); + for (iterator it2 = list->begin(); it2 != end2; ++it2) + if (!(*it2).marked()) + (*it2).mark(); + } +} + +void MarkedArgumentBuffer::slowAppend(JSValue v) +{ + // As long as our size stays within our Vector's inline + // capacity, all our values are allocated on the stack, and + // therefore don't need explicit marking. Once our size exceeds + // our Vector's inline capacity, though, our values move to the + // heap, where they do need explicit marking. + if (!m_markSet) { + // We can only register for explicit marking once we know which heap + // is the current one, i.e., when a non-immediate value is appended. + if (Heap* heap = Heap::heap(v)) { + ListSet& markSet = heap->markListSet(); + markSet.add(this); + m_markSet = &markSet; + } + } + + if (m_vector.size() < m_vector.capacity()) { + m_vector.uncheckedAppend(v); + return; + } + + // 4x growth would be excessive for a normal vector, but it's OK for Lists + // because they're short-lived. + m_vector.reserveCapacity(m_vector.capacity() * 4); + + m_vector.uncheckedAppend(v); + m_buffer = m_vector.data(); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArgList.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArgList.h new file mode 100644 index 0000000..0899e85 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArgList.h @@ -0,0 +1,230 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 2007, 2008, 2009 Apple Computer, Inc. + * + * 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 ArgList_h +#define ArgList_h + +#include "JSImmediate.h" +#include "Register.h" + +#include <wtf/HashSet.h> +#include <wtf/Noncopyable.h> +#include <wtf/Vector.h> + +namespace JSC { + + class MarkedArgumentBuffer : public Noncopyable { + private: + static const unsigned inlineCapacity = 8; + typedef Vector<Register, inlineCapacity> VectorType; + typedef HashSet<MarkedArgumentBuffer*> ListSet; + + public: + typedef VectorType::iterator iterator; + typedef VectorType::const_iterator const_iterator; + + // Constructor for a read-write list, to which you may append values. + // FIXME: Remove all clients of this API, then remove this API. + MarkedArgumentBuffer() + : m_isUsingInlineBuffer(true) + , m_markSet(0) +#ifndef NDEBUG + , m_isReadOnly(false) +#endif + { + m_buffer = m_vector.data(); + m_size = 0; + } + + // Constructor for a read-only list whose data has already been allocated elsewhere. + MarkedArgumentBuffer(Register* buffer, size_t size) + : m_buffer(buffer) + , m_size(size) + , m_isUsingInlineBuffer(true) + , m_markSet(0) +#ifndef NDEBUG + , m_isReadOnly(true) +#endif + { + } + + void initialize(Register* buffer, size_t size) + { + ASSERT(!m_markSet); + ASSERT(isEmpty()); + + m_buffer = buffer; + m_size = size; +#ifndef NDEBUG + m_isReadOnly = true; +#endif + } + + ~MarkedArgumentBuffer() + { + if (m_markSet) + m_markSet->remove(this); + } + + size_t size() const { return m_size; } + bool isEmpty() const { return !m_size; } + + JSValue at(size_t i) const + { + if (i < m_size) + return m_buffer[i].jsValue(); + return jsUndefined(); + } + + void clear() + { + m_vector.clear(); + m_buffer = 0; + m_size = 0; + } + + void append(JSValue v) + { + ASSERT(!m_isReadOnly); + + if (m_isUsingInlineBuffer && m_size < inlineCapacity) { + m_vector.uncheckedAppend(v); + ++m_size; + } else { + // Putting this case all in one function measurably improves + // the performance of the fast "just append to inline buffer" case. + slowAppend(v); + ++m_size; + m_isUsingInlineBuffer = false; + } + } + + void removeLast() + { + ASSERT(m_size); + m_size--; + m_vector.removeLast(); + } + + JSValue last() + { + ASSERT(m_size); + return m_buffer[m_size - 1].jsValue(); + } + + iterator begin() { return m_buffer; } + iterator end() { return m_buffer + m_size; } + + const_iterator begin() const { return m_buffer; } + const_iterator end() const { return m_buffer + m_size; } + + static void markLists(ListSet&); + + private: + void slowAppend(JSValue); + + Register* m_buffer; + size_t m_size; + bool m_isUsingInlineBuffer; + + VectorType m_vector; + ListSet* m_markSet; +#ifndef NDEBUG + bool m_isReadOnly; +#endif + + private: + // Prohibits new / delete, which would break GC. + friend class JSGlobalData; + + void* operator new(size_t size) + { + return fastMalloc(size); + } + void operator delete(void* p) + { + fastFree(p); + } + + void* operator new[](size_t); + void operator delete[](void*); + + void* operator new(size_t, void*); + void operator delete(void*, size_t); + }; + + class ArgList { + friend class JIT; + public: + typedef JSValue* iterator; + typedef const JSValue* const_iterator; + + ArgList() + : m_args(0) + , m_argCount(0) + { + } + + ArgList(JSValue* args, unsigned argCount) + : m_args(args) + , m_argCount(argCount) + { + } + + ArgList(Register* args, int argCount) + : m_args(reinterpret_cast<JSValue*>(args)) + , m_argCount(argCount) + { + ASSERT(argCount >= 0); + } + + ArgList(const MarkedArgumentBuffer& args) + : m_args(reinterpret_cast<JSValue*>(const_cast<Register*>(args.begin()))) + , m_argCount(args.size()) + { + } + + JSValue at(size_t idx) const + { + if (idx < m_argCount) + return m_args[idx]; + return jsUndefined(); + } + + bool isEmpty() const { return !m_argCount; } + + size_t size() const { return m_argCount; } + + iterator begin() { return m_args; } + iterator end() { return m_args + m_argCount; } + + const_iterator begin() const { return m_args; } + const_iterator end() const { return m_args + m_argCount; } + + void getSlice(int startIndex, ArgList& result) const; + private: + JSValue* m_args; + size_t m_argCount; + }; + +} // namespace JSC + +#endif // ArgList_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Arguments.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Arguments.cpp new file mode 100644 index 0000000..7cb4fe9 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Arguments.cpp @@ -0,0 +1,284 @@ +/* + * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) + * Copyright (C) 2007 Maks Orlovich + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "Arguments.h" + +#include "JSActivation.h" +#include "JSFunction.h" +#include "JSGlobalObject.h" + +using namespace std; + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(Arguments); + +const ClassInfo Arguments::info = { "Arguments", 0, 0, 0 }; + +Arguments::~Arguments() +{ + if (d->extraArguments != d->extraArgumentsFixedBuffer) + delete [] d->extraArguments; +} + +void Arguments::mark() +{ + JSObject::mark(); + + if (d->registerArray) { + for (unsigned i = 0; i < d->numParameters; ++i) { + if (!d->registerArray[i].marked()) + d->registerArray[i].mark(); + } + } + + if (d->extraArguments) { + unsigned numExtraArguments = d->numArguments - d->numParameters; + for (unsigned i = 0; i < numExtraArguments; ++i) { + if (!d->extraArguments[i].marked()) + d->extraArguments[i].mark(); + } + } + + if (!d->callee->marked()) + d->callee->mark(); + + if (d->activation && !d->activation->marked()) + d->activation->mark(); +} + +void Arguments::copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize) +{ + if (UNLIKELY(d->overrodeLength)) { + unsigned length = min(get(exec, exec->propertyNames().length).toUInt32(exec), maxSize); + for (unsigned i = 0; i < length; i++) + buffer[i] = get(exec, i); + return; + } + + if (LIKELY(!d->deletedArguments)) { + unsigned parametersLength = min(min(d->numParameters, d->numArguments), maxSize); + unsigned i = 0; + for (; i < parametersLength; ++i) + buffer[i] = d->registers[d->firstParameterIndex + i].jsValue(); + for (; i < d->numArguments; ++i) + buffer[i] = d->extraArguments[i - d->numParameters].jsValue(); + return; + } + + unsigned parametersLength = min(min(d->numParameters, d->numArguments), maxSize); + unsigned i = 0; + for (; i < parametersLength; ++i) { + if (!d->deletedArguments[i]) + buffer[i] = d->registers[d->firstParameterIndex + i].jsValue(); + else + buffer[i] = get(exec, i); + } + for (; i < d->numArguments; ++i) { + if (!d->deletedArguments[i]) + buffer[i] = d->extraArguments[i - d->numParameters].jsValue(); + else + buffer[i] = get(exec, i); + } +} + +void Arguments::fillArgList(ExecState* exec, MarkedArgumentBuffer& args) +{ + if (UNLIKELY(d->overrodeLength)) { + unsigned length = get(exec, exec->propertyNames().length).toUInt32(exec); + for (unsigned i = 0; i < length; i++) + args.append(get(exec, i)); + return; + } + + if (LIKELY(!d->deletedArguments)) { + if (LIKELY(!d->numParameters)) { + args.initialize(d->extraArguments, d->numArguments); + return; + } + + if (d->numParameters == d->numArguments) { + args.initialize(&d->registers[d->firstParameterIndex], d->numArguments); + return; + } + + unsigned parametersLength = min(d->numParameters, d->numArguments); + unsigned i = 0; + for (; i < parametersLength; ++i) + args.append(d->registers[d->firstParameterIndex + i].jsValue()); + for (; i < d->numArguments; ++i) + args.append(d->extraArguments[i - d->numParameters].jsValue()); + return; + } + + unsigned parametersLength = min(d->numParameters, d->numArguments); + unsigned i = 0; + for (; i < parametersLength; ++i) { + if (!d->deletedArguments[i]) + args.append(d->registers[d->firstParameterIndex + i].jsValue()); + else + args.append(get(exec, i)); + } + for (; i < d->numArguments; ++i) { + if (!d->deletedArguments[i]) + args.append(d->extraArguments[i - d->numParameters].jsValue()); + else + args.append(get(exec, i)); + } +} + +bool Arguments::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& slot) +{ + if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) { + if (i < d->numParameters) { + slot.setRegisterSlot(&d->registers[d->firstParameterIndex + i]); + } else + slot.setValue(d->extraArguments[i - d->numParameters].jsValue()); + return true; + } + + return JSObject::getOwnPropertySlot(exec, Identifier(exec, UString::from(i)), slot); +} + +bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +{ + bool isArrayIndex; + unsigned i = propertyName.toArrayIndex(&isArrayIndex); + if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) { + if (i < d->numParameters) { + slot.setRegisterSlot(&d->registers[d->firstParameterIndex + i]); + } else + slot.setValue(d->extraArguments[i - d->numParameters].jsValue()); + return true; + } + + if (propertyName == exec->propertyNames().length && LIKELY(!d->overrodeLength)) { + slot.setValue(jsNumber(exec, d->numArguments)); + return true; + } + + if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) { + slot.setValue(d->callee); + return true; + } + + return JSObject::getOwnPropertySlot(exec, propertyName, slot); +} + +void Arguments::put(ExecState* exec, unsigned i, JSValue value, PutPropertySlot& slot) +{ + if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) { + if (i < d->numParameters) + d->registers[d->firstParameterIndex + i] = JSValue(value); + else + d->extraArguments[i - d->numParameters] = JSValue(value); + return; + } + + JSObject::put(exec, Identifier(exec, UString::from(i)), value, slot); +} + +void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) +{ + bool isArrayIndex; + unsigned i = propertyName.toArrayIndex(&isArrayIndex); + if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) { + if (i < d->numParameters) + d->registers[d->firstParameterIndex + i] = JSValue(value); + else + d->extraArguments[i - d->numParameters] = JSValue(value); + return; + } + + if (propertyName == exec->propertyNames().length && !d->overrodeLength) { + d->overrodeLength = true; + putDirect(propertyName, value, DontEnum); + return; + } + + if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) { + d->overrodeCallee = true; + putDirect(propertyName, value, DontEnum); + return; + } + + JSObject::put(exec, propertyName, value, slot); +} + +bool Arguments::deleteProperty(ExecState* exec, unsigned i, bool checkDontDelete) +{ + if (i < d->numArguments) { + if (!d->deletedArguments) { + d->deletedArguments.set(new bool[d->numArguments]); + memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments); + } + if (!d->deletedArguments[i]) { + d->deletedArguments[i] = true; + return true; + } + } + + return JSObject::deleteProperty(exec, Identifier(exec, UString::from(i)), checkDontDelete); +} + +bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName, bool checkDontDelete) +{ + bool isArrayIndex; + unsigned i = propertyName.toArrayIndex(&isArrayIndex); + if (isArrayIndex && i < d->numArguments) { + if (!d->deletedArguments) { + d->deletedArguments.set(new bool[d->numArguments]); + memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments); + } + if (!d->deletedArguments[i]) { + d->deletedArguments[i] = true; + return true; + } + } + + if (propertyName == exec->propertyNames().length && !d->overrodeLength) { + d->overrodeLength = true; + return true; + } + + if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) { + d->overrodeCallee = true; + return true; + } + + return JSObject::deleteProperty(exec, propertyName, checkDontDelete); +} + +bool Arguments::getPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const +{ + if ((propertyName == exec->propertyNames().length) + || (propertyName == exec->propertyNames().callee)) { + attributes = DontEnum; + return true; + } + return JSObject::getPropertyAttributes(exec, propertyName, attributes); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Arguments.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Arguments.h new file mode 100644 index 0000000..dc54dac --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Arguments.h @@ -0,0 +1,247 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) + * Copyright (C) 2007 Maks Orlovich + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef Arguments_h +#define Arguments_h + +#include "JSActivation.h" +#include "JSFunction.h" +#include "JSGlobalObject.h" +#include "Interpreter.h" + +namespace JSC { + + struct ArgumentsData : Noncopyable { + JSActivation* activation; + + unsigned numParameters; + ptrdiff_t firstParameterIndex; + unsigned numArguments; + + Register* registers; + OwnArrayPtr<Register> registerArray; + + Register* extraArguments; + OwnArrayPtr<bool> deletedArguments; + Register extraArgumentsFixedBuffer[4]; + + JSObject* callee; + bool overrodeLength : 1; + bool overrodeCallee : 1; + }; + + + class Arguments : public JSObject { + public: + enum NoParametersType { NoParameters }; + + Arguments(CallFrame*); + Arguments(CallFrame*, NoParametersType); + virtual ~Arguments(); + + static const ClassInfo info; + + virtual void mark(); + + void fillArgList(ExecState*, MarkedArgumentBuffer&); + + uint32_t numProvidedArguments(ExecState* exec) const + { + if (UNLIKELY(d->overrodeLength)) + return get(exec, exec->propertyNames().length).toUInt32(exec); + return d->numArguments; + } + + void copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize); + void copyRegisters(); + bool isTornOff() const { return d->registerArray; } + void setActivation(JSActivation* activation) + { + d->activation = activation; + d->registers = &activation->registerAt(0); + } + + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType)); + } + + private: + void getArgumentsData(CallFrame*, JSObject*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc); + virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); + virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); + virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); + virtual void put(ExecState*, unsigned propertyName, JSValue, PutPropertySlot&); + virtual bool deleteProperty(ExecState*, const Identifier& propertyName, bool checkDontDelete = true); + virtual bool deleteProperty(ExecState*, unsigned propertyName, bool checkDontDelete = true); + virtual bool getPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned& attributes) const; + + virtual const ClassInfo* classInfo() const { return &info; } + + void init(CallFrame*); + + OwnPtr<ArgumentsData> d; + }; + + Arguments* asArguments(JSValue); + + inline Arguments* asArguments(JSValue value) + { + ASSERT(asObject(value)->inherits(&Arguments::info)); + return static_cast<Arguments*>(asObject(value)); + } + + ALWAYS_INLINE void Arguments::getArgumentsData(CallFrame* callFrame, JSObject*& callee, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc) + { + callee = callFrame->callee(); + + int numParameters; + if (callee->isObject(&JSFunction::info)) { + CodeBlock* codeBlock = &JSC::asFunction(callee)->body()->generatedBytecode(); + numParameters = codeBlock->m_numParameters; + } else { + numParameters = 0; + } + argc = callFrame->argumentCount(); + + if (argc <= numParameters) + argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numParameters + 1; // + 1 to skip "this" + else + argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numParameters - argc + 1; // + 1 to skip "this" + + argc -= 1; // - 1 to skip "this" + firstParameterIndex = -RegisterFile::CallFrameHeaderSize - numParameters + 1; // + 1 to skip "this" + } + + inline Arguments::Arguments(CallFrame* callFrame) + : JSObject(callFrame->lexicalGlobalObject()->argumentsStructure()) + , d(new ArgumentsData) + { + JSObject* callee; + ptrdiff_t firstParameterIndex; + Register* argv; + int numArguments; + getArgumentsData(callFrame, callee, firstParameterIndex, argv, numArguments); + + if (callee->isObject(&JSFunction::info)) + d->numParameters = JSC::asFunction(callee)->body()->parameterCount(); + else + d->numParameters = 0; + d->firstParameterIndex = firstParameterIndex; + d->numArguments = numArguments; + + d->activation = 0; + d->registers = callFrame->registers(); + + Register* extraArguments; + if (d->numArguments <= d->numParameters) + extraArguments = 0; + else { + unsigned numExtraArguments = d->numArguments - d->numParameters; + if (numExtraArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(Register)) + extraArguments = new Register[numExtraArguments]; + else + extraArguments = d->extraArgumentsFixedBuffer; + for (unsigned i = 0; i < numExtraArguments; ++i) + extraArguments[i] = argv[d->numParameters + i]; + } + + d->extraArguments = extraArguments; + + d->callee = callee; + d->overrodeLength = false; + d->overrodeCallee = false; + } + + inline Arguments::Arguments(CallFrame* callFrame, NoParametersType) + : JSObject(callFrame->lexicalGlobalObject()->argumentsStructure()) + , d(new ArgumentsData) + { + if (callFrame->callee() && callFrame->callee()->isObject(&JSC::JSFunction::info)) + ASSERT(!asFunction(callFrame->callee())->body()->parameterCount()); + + unsigned numArguments = callFrame->argumentCount() - 1; + + d->numParameters = 0; + d->numArguments = numArguments; + d->activation = 0; + + Register* extraArguments; + if (numArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(Register)) + extraArguments = new Register[numArguments]; + else + extraArguments = d->extraArgumentsFixedBuffer; + + Register* argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numArguments - 1; + if (callFrame->callee() && !callFrame->callee()->isObject(&JSC::JSFunction::info)) + ++argv; // ### off-by-one issue with native functions + for (unsigned i = 0; i < numArguments; ++i) + extraArguments[i] = argv[i]; + + d->extraArguments = extraArguments; + + d->callee = callFrame->callee(); + d->overrodeLength = false; + d->overrodeCallee = false; + } + + inline void Arguments::copyRegisters() + { + ASSERT(!isTornOff()); + + if (!d->numParameters) + return; + + int registerOffset = d->numParameters + RegisterFile::CallFrameHeaderSize; + size_t registerArraySize = d->numParameters; + + Register* registerArray = new Register[registerArraySize]; + memcpy(registerArray, d->registers - registerOffset, registerArraySize * sizeof(Register)); + d->registerArray.set(registerArray); + d->registers = registerArray + registerOffset; + } + + // This JSActivation function is defined here so it can get at Arguments::setRegisters. + inline void JSActivation::copyRegisters(Arguments* arguments) + { + ASSERT(!d()->registerArray); + + size_t numParametersMinusThis = d()->functionBody->generatedBytecode().m_numParameters - 1; + size_t numVars = d()->functionBody->generatedBytecode().m_numVars; + size_t numLocals = numVars + numParametersMinusThis; + + if (!numLocals) + return; + + int registerOffset = numParametersMinusThis + RegisterFile::CallFrameHeaderSize; + size_t registerArraySize = numLocals + RegisterFile::CallFrameHeaderSize; + + Register* registerArray = copyRegisterArray(d()->registers - registerOffset, registerArraySize); + setRegisters(registerArray + registerOffset, registerArray); + if (arguments && !arguments->isTornOff()) + static_cast<Arguments*>(arguments)->setActivation(this); + } + +} // namespace JSC + +#endif // Arguments_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayConstructor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayConstructor.cpp new file mode 100644 index 0000000..e96bdfc --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayConstructor.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2003 Peter Kelly (pmk@post.com) + * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.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 + * + */ + +#include "config.h" +#include "ArrayConstructor.h" + +#include "ArrayPrototype.h" +#include "JSArray.h" +#include "JSFunction.h" +#include "Lookup.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(ArrayConstructor); + +ArrayConstructor::ArrayConstructor(ExecState* exec, PassRefPtr<Structure> structure, ArrayPrototype* arrayPrototype) + : InternalFunction(&exec->globalData(), structure, Identifier(exec, arrayPrototype->classInfo()->className)) +{ + // ECMA 15.4.3.1 Array.prototype + putDirectWithoutTransition(exec->propertyNames().prototype, arrayPrototype, DontEnum | DontDelete | ReadOnly); + + // no. of arguments for constructor + putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 1), ReadOnly | DontEnum | DontDelete); +} + +static JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgList& args) +{ + // a single numeric argument denotes the array size (!) + if (args.size() == 1 && args.at(0).isNumber()) { + uint32_t n = args.at(0).toUInt32(exec); + if (n != args.at(0).toNumber(exec)) + return throwError(exec, RangeError, "Array size is not a small enough positive integer."); + return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), n); + } + + // otherwise the array is constructed with the arguments in it + return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), args); +} + +static JSObject* constructWithArrayConstructor(ExecState* exec, JSObject*, const ArgList& args) +{ + return constructArrayWithSizeQuirk(exec, args); +} + +// ECMA 15.4.2 +ConstructType ArrayConstructor::getConstructData(ConstructData& constructData) +{ + constructData.native.function = constructWithArrayConstructor; + return ConstructTypeHost; +} + +static JSValue JSC_HOST_CALL callArrayConstructor(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return constructArrayWithSizeQuirk(exec, args); +} + +// ECMA 15.6.1 +CallType ArrayConstructor::getCallData(CallData& callData) +{ + // equivalent to 'new Array(....)' + callData.native.function = callArrayConstructor; + return CallTypeHost; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayConstructor.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayConstructor.h new file mode 100644 index 0000000..8300d8c --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayConstructor.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 ArrayConstructor_h +#define ArrayConstructor_h + +#include "InternalFunction.h" + +namespace JSC { + + class ArrayPrototype; + + class ArrayConstructor : public InternalFunction { + public: + ArrayConstructor(ExecState*, PassRefPtr<Structure>, ArrayPrototype*); + + virtual ConstructType getConstructData(ConstructData&); + virtual CallType getCallData(CallData&); + }; + +} // namespace JSC + +#endif // ArrayConstructor_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayPrototype.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayPrototype.cpp new file mode 100644 index 0000000..807e59a --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -0,0 +1,1055 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2003 Peter Kelly (pmk@post.com) + * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.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 + * + */ + +#include "config.h" +#include "ArrayPrototype.h" + +#include "CodeBlock.h" +#include "CachedCall.h" +#include "Interpreter.h" +#include "JIT.h" +#include "ObjectPrototype.h" +#include "Lookup.h" +#include "Operations.h" +#include <algorithm> +#include <wtf/Assertions.h> +#include <wtf/HashSet.h> + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(ArrayPrototype); + +static JSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState*, JSObject*, JSValue, const ArgList&); + +} + +#include "ArrayPrototype.lut.h" + +namespace JSC { + +static inline bool isNumericCompareFunction(CallType callType, const CallData& callData) +{ + if (callType != CallTypeJS) + return false; + +#if ENABLE(JIT) + // If the JIT is enabled then we need to preserve the invariant that every + // function with a CodeBlock also has JIT code. + callData.js.functionBody->jitCode(callData.js.scopeChain); + CodeBlock& codeBlock = callData.js.functionBody->generatedBytecode(); +#else + CodeBlock& codeBlock = callData.js.functionBody->bytecode(callData.js.scopeChain); +#endif + + return codeBlock.isNumericCompareFunction(); +} + +// ------------------------------ ArrayPrototype ---------------------------- + +const ClassInfo ArrayPrototype::info = {"Array", &JSArray::info, 0, ExecState::arrayTable}; + +/* Source for ArrayPrototype.lut.h +@begin arrayTable 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 +@end +*/ + +// ECMA 15.4.4 +ArrayPrototype::ArrayPrototype(PassRefPtr<Structure> structure) + : JSArray(structure) +{ +} + +bool ArrayPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +{ + return getStaticFunctionSlot<JSArray>(exec, ExecState::arrayTable(exec), this, propertyName, slot); +} + +// ------------------------------ Array Functions ---------------------------- + +// Helper function +static JSValue getProperty(ExecState* exec, JSObject* obj, unsigned index) +{ + PropertySlot slot(obj); + if (!obj->getPropertySlot(exec, index, slot)) + return JSValue(); + return slot.getValue(exec, index); +} + +static void putProperty(ExecState* exec, JSObject* obj, const Identifier& propertyName, JSValue value) +{ + PutPropertySlot slot; + obj->put(exec, propertyName, value, slot); +} + +JSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&JSArray::info)) + return throwError(exec, TypeError); + JSObject* thisObj = asArray(thisValue); + + HashSet<JSObject*>& arrayVisitedElements = exec->globalData().arrayVisitedElements; + if (arrayVisitedElements.size() >= MaxSecondaryThreadReentryDepth) { + if (!isMainThread() || arrayVisitedElements.size() >= MaxMainThreadReentryDepth) + return throwError(exec, RangeError, "Maximum call stack size exceeded."); + } + + bool alreadyVisited = !arrayVisitedElements.add(thisObj).second; + if (alreadyVisited) + return jsEmptyString(exec); // return an empty string, avoiding infinite recursion. + + Vector<UChar, 256> strBuffer; + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + for (unsigned k = 0; k < length; k++) { + if (k >= 1) + strBuffer.append(','); + if (!strBuffer.data()) { + JSObject* error = Error::create(exec, GeneralError, "Out of memory"); + exec->setException(error); + break; + } + + JSValue element = thisObj->get(exec, k); + if (element.isUndefinedOrNull()) + continue; + + UString str = element.toString(exec); + strBuffer.append(str.data(), str.size()); + + if (!strBuffer.data()) { + JSObject* error = Error::create(exec, GeneralError, "Out of memory"); + exec->setException(error); + } + + if (exec->hadException()) + break; + } + arrayVisitedElements.remove(thisObj); + return jsString(exec, UString(strBuffer.data(), strBuffer.data() ? strBuffer.size() : 0)); +} + +JSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&JSArray::info)) + return throwError(exec, TypeError); + JSObject* thisObj = asArray(thisValue); + + HashSet<JSObject*>& arrayVisitedElements = exec->globalData().arrayVisitedElements; + if (arrayVisitedElements.size() >= MaxSecondaryThreadReentryDepth) { + if (!isMainThread() || arrayVisitedElements.size() >= MaxMainThreadReentryDepth) + return throwError(exec, RangeError, "Maximum call stack size exceeded."); + } + + bool alreadyVisited = !arrayVisitedElements.add(thisObj).second; + if (alreadyVisited) + return jsEmptyString(exec); // return an empty string, avoding infinite recursion. + + Vector<UChar, 256> strBuffer; + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + for (unsigned k = 0; k < length; k++) { + if (k >= 1) + strBuffer.append(','); + if (!strBuffer.data()) { + JSObject* error = Error::create(exec, GeneralError, "Out of memory"); + exec->setException(error); + break; + } + + JSValue element = thisObj->get(exec, k); + if (element.isUndefinedOrNull()) + continue; + + JSObject* o = element.toObject(exec); + JSValue conversionFunction = o->get(exec, exec->propertyNames().toLocaleString); + UString str; + CallData callData; + CallType callType = conversionFunction.getCallData(callData); + if (callType != CallTypeNone) + str = call(exec, conversionFunction, callType, callData, element, exec->emptyList()).toString(exec); + else + str = element.toString(exec); + strBuffer.append(str.data(), str.size()); + + if (!strBuffer.data()) { + JSObject* error = Error::create(exec, GeneralError, "Out of memory"); + exec->setException(error); + } + + if (exec->hadException()) + break; + } + arrayVisitedElements.remove(thisObj); + return jsString(exec, UString(strBuffer.data(), strBuffer.data() ? strBuffer.size() : 0)); +} + +JSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + JSObject* thisObj = thisValue.toThisObject(exec); + + HashSet<JSObject*>& arrayVisitedElements = exec->globalData().arrayVisitedElements; + if (arrayVisitedElements.size() >= MaxSecondaryThreadReentryDepth) { + if (!isMainThread() || arrayVisitedElements.size() >= MaxMainThreadReentryDepth) + return throwError(exec, RangeError, "Maximum call stack size exceeded."); + } + + bool alreadyVisited = !arrayVisitedElements.add(thisObj).second; + if (alreadyVisited) + return jsEmptyString(exec); // return an empty string, avoding infinite recursion. + + Vector<UChar, 256> strBuffer; + + UChar comma = ','; + UString separator = args.at(0).isUndefined() ? UString(&comma, 1) : args.at(0).toString(exec); + + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + for (unsigned k = 0; k < length; k++) { + if (k >= 1) + strBuffer.append(separator.data(), separator.size()); + if (!strBuffer.data()) { + JSObject* error = Error::create(exec, GeneralError, "Out of memory"); + exec->setException(error); + break; + } + + JSValue element = thisObj->get(exec, k); + if (element.isUndefinedOrNull()) + continue; + + UString str = element.toString(exec); + strBuffer.append(str.data(), str.size()); + + if (!strBuffer.data()) { + JSObject* error = Error::create(exec, GeneralError, "Out of memory"); + exec->setException(error); + } + + if (exec->hadException()) + break; + } + arrayVisitedElements.remove(thisObj); + return jsString(exec, UString(strBuffer.data(), strBuffer.data() ? strBuffer.size() : 0)); +} + +JSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + JSArray* arr = constructEmptyArray(exec); + int n = 0; + JSValue curArg = thisValue.toThisObject(exec); + ArgList::const_iterator it = args.begin(); + ArgList::const_iterator end = args.end(); + while (1) { + if (curArg.isObject(&JSArray::info)) { + unsigned length = curArg.get(exec, exec->propertyNames().length).toUInt32(exec); + JSObject* curObject = curArg.toObject(exec); + for (unsigned k = 0; k < length; ++k) { + if (JSValue v = getProperty(exec, curObject, k)) + arr->put(exec, n, v); + n++; + } + } else { + arr->put(exec, n, curArg); + n++; + } + if (it == end) + break; + curArg = (*it); + ++it; + } + arr->setLength(n); + return arr; +} + +JSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (isJSArray(&exec->globalData(), thisValue)) + return asArray(thisValue)->pop(); + + JSObject* thisObj = thisValue.toThisObject(exec); + JSValue result; + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (length == 0) { + putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(exec, length)); + result = jsUndefined(); + } else { + result = thisObj->get(exec, length - 1); + thisObj->deleteProperty(exec, length - 1); + putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(exec, length - 1)); + } + return result; +} + +JSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + if (isJSArray(&exec->globalData(), thisValue) && args.size() == 1) { + JSArray* array = asArray(thisValue); + array->push(exec, *args.begin()); + return jsNumber(exec, array->length()); + } + + JSObject* thisObj = thisValue.toThisObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + for (unsigned n = 0; n < args.size(); n++) + thisObj->put(exec, length + n, args.at(n)); + length += args.size(); + putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(exec, length)); + return jsNumber(exec, length); +} + +JSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + JSObject* thisObj = thisValue.toThisObject(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + unsigned middle = length / 2; + + for (unsigned k = 0; k < middle; k++) { + unsigned lk1 = length - k - 1; + JSValue obj2 = getProperty(exec, thisObj, lk1); + JSValue obj = getProperty(exec, thisObj, k); + + if (obj2) + thisObj->put(exec, k, obj2); + else + thisObj->deleteProperty(exec, k); + + if (obj) + thisObj->put(exec, lk1, obj); + else + thisObj->deleteProperty(exec, lk1); + } + return thisObj; +} + +JSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + JSObject* thisObj = thisValue.toThisObject(exec); + JSValue result; + + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (length == 0) { + putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(exec, length)); + result = jsUndefined(); + } else { + result = thisObj->get(exec, 0); + for (unsigned k = 1; k < length; k++) { + if (JSValue obj = getProperty(exec, thisObj, k)) + thisObj->put(exec, k - 1, obj); + else + thisObj->deleteProperty(exec, k - 1); + } + thisObj->deleteProperty(exec, length - 1); + putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(exec, length - 1)); + } + return result; +} + +JSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + // http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 or 15.4.4.10 + + JSObject* thisObj = thisValue.toThisObject(exec); + + // We return a new array + JSArray* resObj = constructEmptyArray(exec); + JSValue result = resObj; + double begin = args.at(0).toInteger(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (begin >= 0) { + if (begin > length) + begin = length; + } else { + begin += length; + if (begin < 0) + begin = 0; + } + double end; + if (args.at(1).isUndefined()) + end = length; + else { + end = args.at(1).toInteger(exec); + if (end < 0) { + end += length; + if (end < 0) + end = 0; + } else { + if (end > length) + end = length; + } + } + + int n = 0; + int b = static_cast<int>(begin); + int e = static_cast<int>(end); + for (int k = b; k < e; k++, n++) { + if (JSValue v = getProperty(exec, thisObj, k)) + resObj->put(exec, n, v); + } + resObj->setLength(n); + return result; +} + +JSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + JSObject* thisObj = thisValue.toThisObject(exec); + + JSValue function = args.at(0); + CallData callData; + CallType callType = function.getCallData(callData); + + if (thisObj->classInfo() == &JSArray::info) { + if (isNumericCompareFunction(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 thisObj; + } + + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + + if (!length) + return thisObj; + + // "Min" sort. Not the fastest, but definitely less code than heapsort + // or quicksort, and much less swapping than bubblesort/insertionsort. + for (unsigned i = 0; i < length - 1; ++i) { + JSValue iObj = thisObj->get(exec, i); + unsigned themin = i; + JSValue minObj = iObj; + for (unsigned j = i + 1; j < length; ++j) { + JSValue jObj = thisObj->get(exec, j); + double compareResult; + 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, exec->globalThisValue(), l).toNumber(exec); + } else + compareResult = (jObj.toString(exec) < minObj.toString(exec)) ? -1 : 1; + + if (compareResult < 0) { + themin = j; + minObj = jObj; + } + } + // Swap themin and i + if (themin > i) { + thisObj->put(exec, i, minObj); + thisObj->put(exec, themin, iObj); + } + } + return thisObj; +} + +JSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + JSObject* thisObj = thisValue.toThisObject(exec); + + // 15.4.4.12 + JSArray* resObj = constructEmptyArray(exec); + JSValue result = resObj; + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (!args.size()) + return jsUndefined(); + int begin = args.at(0).toUInt32(exec); + if (begin < 0) + begin = std::max<int>(begin + length, 0); + else + begin = std::min<int>(begin, length); + + unsigned deleteCount; + if (args.size() > 1) + deleteCount = std::min<int>(std::max<int>(args.at(1).toUInt32(exec), 0), length - begin); + else + deleteCount = length - begin; + + for (unsigned k = 0; k < deleteCount; k++) { + if (JSValue v = getProperty(exec, thisObj, k + begin)) + resObj->put(exec, k, v); + } + resObj->setLength(deleteCount); + + unsigned additionalArgs = std::max<int>(args.size() - 2, 0); + if (additionalArgs != deleteCount) { + if (additionalArgs < deleteCount) { + for (unsigned k = begin; k < length - deleteCount; ++k) { + if (JSValue v = getProperty(exec, thisObj, k + deleteCount)) + thisObj->put(exec, k + additionalArgs, v); + else + thisObj->deleteProperty(exec, k + additionalArgs); + } + for (unsigned k = length; k > length - deleteCount + additionalArgs; --k) + thisObj->deleteProperty(exec, k - 1); + } else { + for (unsigned k = length - deleteCount; (int)k > begin; --k) { + if (JSValue obj = getProperty(exec, thisObj, k + deleteCount - 1)) + thisObj->put(exec, k + additionalArgs - 1, obj); + else + thisObj->deleteProperty(exec, k + additionalArgs - 1); + } + } + } + for (unsigned k = 0; k < additionalArgs; ++k) + thisObj->put(exec, k + begin, args.at(k + 2)); + + putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(exec, length - deleteCount + additionalArgs)); + return result; +} + +JSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + JSObject* thisObj = thisValue.toThisObject(exec); + + // 15.4.4.13 + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + unsigned nrArgs = args.size(); + if (nrArgs) { + for (unsigned k = length; k > 0; --k) { + if (JSValue v = getProperty(exec, thisObj, k - 1)) + thisObj->put(exec, k + nrArgs - 1, v); + else + thisObj->deleteProperty(exec, k + nrArgs - 1); + } + } + for (unsigned k = 0; k < nrArgs; ++k) + thisObj->put(exec, k, args.at(k)); + JSValue result = jsNumber(exec, length + nrArgs); + putProperty(exec, thisObj, exec->propertyNames().length, result); + return result; +} + +JSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + JSObject* thisObj = thisValue.toThisObject(exec); + + JSValue function = args.at(0); + CallData callData; + CallType callType = function.getCallData(callData); + if (callType == CallTypeNone) + return throwError(exec, TypeError); + + JSObject* applyThis = args.at(1).isUndefinedOrNull() ? exec->globalThisValue() : args.at(1).toObject(exec); + JSArray* resultArray = constructEmptyArray(exec); + + unsigned filterIndex = 0; + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + unsigned k = 0; + if (callType == CallTypeJS && isJSArray(&exec->globalData(), thisObj)) { + JSFunction* f = asFunction(function); + JSArray* array = asArray(thisObj); + CachedCall cachedCall(exec, f, 3, exec->exceptionSlot()); + for (; k < length && !exec->hadException(); ++k) { + if (!array->canGetIndex(k)) + break; + JSValue v = array->getIndex(k); + cachedCall.setThis(applyThis); + cachedCall.setArgument(0, v); + cachedCall.setArgument(1, jsNumber(exec, k)); + cachedCall.setArgument(2, thisObj); + + JSValue result = cachedCall.call(); + if (result.toBoolean(exec)) + resultArray->put(exec, filterIndex++, v); + } + if (k == length) + return resultArray; + } + for (; k < length && !exec->hadException(); ++k) { + PropertySlot slot(thisObj); + + if (!thisObj->getPropertySlot(exec, k, slot)) + continue; + + JSValue v = slot.getValue(exec, k); + + MarkedArgumentBuffer eachArguments; + + eachArguments.append(v); + eachArguments.append(jsNumber(exec, k)); + eachArguments.append(thisObj); + + JSValue result = call(exec, function, callType, callData, applyThis, eachArguments); + + if (result.toBoolean(exec)) + resultArray->put(exec, filterIndex++, v); + } + return resultArray; +} + +JSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + JSObject* thisObj = thisValue.toThisObject(exec); + + JSValue function = args.at(0); + CallData callData; + CallType callType = function.getCallData(callData); + if (callType == CallTypeNone) + return throwError(exec, TypeError); + + JSObject* applyThis = args.at(1).isUndefinedOrNull() ? exec->globalThisValue() : args.at(1).toObject(exec); + + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + + JSArray* resultArray = constructEmptyArray(exec, length); + unsigned k = 0; + if (callType == CallTypeJS && isJSArray(&exec->globalData(), thisObj)) { + JSFunction* f = asFunction(function); + JSArray* array = asArray(thisObj); + CachedCall cachedCall(exec, f, 3, exec->exceptionSlot()); + for (; k < length && !exec->hadException(); ++k) { + if (UNLIKELY(!array->canGetIndex(k))) + break; + + cachedCall.setThis(applyThis); + cachedCall.setArgument(0, array->getIndex(k)); + cachedCall.setArgument(1, jsNumber(exec, k)); + cachedCall.setArgument(2, thisObj); + + resultArray->JSArray::put(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); + + MarkedArgumentBuffer eachArguments; + + eachArguments.append(v); + eachArguments.append(jsNumber(exec, k)); + eachArguments.append(thisObj); + + JSValue result = call(exec, function, callType, callData, applyThis, eachArguments); + resultArray->put(exec, k, result); + } + + return 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 + +JSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + JSObject* thisObj = thisValue.toThisObject(exec); + + JSValue function = args.at(0); + CallData callData; + CallType callType = function.getCallData(callData); + if (callType == CallTypeNone) + return throwError(exec, TypeError); + + JSObject* applyThis = args.at(1).isUndefinedOrNull() ? exec->globalThisValue() : args.at(1).toObject(exec); + + JSValue result = jsBoolean(true); + + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + unsigned k = 0; + if (callType == CallTypeJS && isJSArray(&exec->globalData(), thisObj)) { + JSFunction* f = asFunction(function); + JSArray* array = asArray(thisObj); + CachedCall cachedCall(exec, f, 3, exec->exceptionSlot()); + for (; k < length && !exec->hadException(); ++k) { + if (UNLIKELY(!array->canGetIndex(k))) + break; + + cachedCall.setThis(applyThis); + cachedCall.setArgument(0, array->getIndex(k)); + cachedCall.setArgument(1, jsNumber(exec, k)); + cachedCall.setArgument(2, thisObj); + + if (!cachedCall.call().toBoolean(exec)) + return 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(exec, k)); + eachArguments.append(thisObj); + + bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments).toBoolean(exec); + + if (!predicateResult) { + result = jsBoolean(false); + break; + } + } + + return result; +} + +JSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + JSObject* thisObj = thisValue.toThisObject(exec); + + JSValue function = args.at(0); + CallData callData; + CallType callType = function.getCallData(callData); + if (callType == CallTypeNone) + return throwError(exec, TypeError); + + JSObject* applyThis = args.at(1).isUndefinedOrNull() ? exec->globalThisValue() : args.at(1).toObject(exec); + + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + unsigned k = 0; + if (callType == CallTypeJS && isJSArray(&exec->globalData(), thisObj)) { + JSFunction* f = asFunction(function); + JSArray* array = asArray(thisObj); + CachedCall cachedCall(exec, f, 3, exec->exceptionSlot()); + for (; k < length && !exec->hadException(); ++k) { + if (UNLIKELY(!array->canGetIndex(k))) + break; + + cachedCall.setThis(applyThis); + cachedCall.setArgument(0, array->getIndex(k)); + cachedCall.setArgument(1, jsNumber(exec, 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(exec, k)); + eachArguments.append(thisObj); + + call(exec, function, callType, callData, applyThis, eachArguments); + } + return jsUndefined(); +} + +JSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + JSObject* thisObj = thisValue.toThisObject(exec); + + JSValue function = args.at(0); + CallData callData; + CallType callType = function.getCallData(callData); + if (callType == CallTypeNone) + return throwError(exec, TypeError); + + JSObject* applyThis = args.at(1).isUndefinedOrNull() ? exec->globalThisValue() : args.at(1).toObject(exec); + + JSValue result = jsBoolean(false); + + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + unsigned k = 0; + if (callType == CallTypeJS && isJSArray(&exec->globalData(), thisObj)) { + JSFunction* f = asFunction(function); + JSArray* array = asArray(thisObj); + CachedCall cachedCall(exec, f, 3, exec->exceptionSlot()); + for (; k < length && !exec->hadException(); ++k) { + if (UNLIKELY(!array->canGetIndex(k))) + break; + + cachedCall.setThis(applyThis); + cachedCall.setArgument(0, array->getIndex(k)); + cachedCall.setArgument(1, jsNumber(exec, k)); + cachedCall.setArgument(2, thisObj); + + if (cachedCall.call().toBoolean(exec)) + return 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(exec, k)); + eachArguments.append(thisObj); + + bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments).toBoolean(exec); + + if (predicateResult) { + result = jsBoolean(true); + break; + } + } + return result; +} + +JSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + JSObject* thisObj = thisValue.toThisObject(exec); + + JSValue function = args.at(0); + CallData callData; + CallType callType = function.getCallData(callData); + if (callType == CallTypeNone) + return throwError(exec, TypeError); + + unsigned i = 0; + JSValue rv; + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (!length && args.size() == 1) + return throwError(exec, TypeError); + JSArray* array = 0; + if (isJSArray(&exec->globalData(), thisObj)) + array = asArray(thisObj); + + if (args.size() >= 2) + rv = args.at(1); + else if (array && array->canGetIndex(0)){ + rv = array->getIndex(0); + i = 1; + } else { + for (i = 0; i < length; i++) { + rv = getProperty(exec, thisObj, i); + if (rv) + break; + } + if (!rv) + return throwError(exec, TypeError); + i++; + } + + if (callType == CallTypeJS && array) { + CachedCall cachedCall(exec, asFunction(function), 4, exec->exceptionSlot()); + for (; i < length && !exec->hadException(); ++i) { + cachedCall.setThis(jsNull()); + cachedCall.setArgument(0, rv); + JSValue v; + if (LIKELY(array->canGetIndex(i))) + v = array->getIndex(i); + else + break; // length has been made unsafe while we enumerate fallback to slow path + cachedCall.setArgument(1, v); + cachedCall.setArgument(2, jsNumber(exec, i)); + cachedCall.setArgument(3, array); + rv = cachedCall.call(); + } + if (i == length) // only return if we reached the end of the array + return rv; + } + + for (; i < length && !exec->hadException(); ++i) { + JSValue prop = getProperty(exec, thisObj, i); + if (!prop) + continue; + + MarkedArgumentBuffer eachArguments; + eachArguments.append(rv); + eachArguments.append(prop); + eachArguments.append(jsNumber(exec, i)); + eachArguments.append(thisObj); + + rv = call(exec, function, callType, callData, jsNull(), eachArguments); + } + return rv; +} + +JSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + JSObject* thisObj = thisValue.toThisObject(exec); + + JSValue function = args.at(0); + CallData callData; + CallType callType = function.getCallData(callData); + if (callType == CallTypeNone) + return throwError(exec, TypeError); + + unsigned i = 0; + JSValue rv; + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (!length && args.size() == 1) + return throwError(exec, TypeError); + JSArray* array = 0; + if (isJSArray(&exec->globalData(), thisObj)) + array = asArray(thisObj); + + if (args.size() >= 2) + rv = args.at(1); + else if (array && array->canGetIndex(length - 1)){ + rv = array->getIndex(length - 1); + i = 1; + } else { + for (i = 0; i < length; i++) { + rv = getProperty(exec, thisObj, length - i - 1); + if (rv) + break; + } + if (!rv) + return throwError(exec, TypeError); + i++; + } + + if (callType == CallTypeJS && array) { + CachedCall cachedCall(exec, asFunction(function), 4, exec->exceptionSlot()); + for (; i < length && !exec->hadException(); ++i) { + unsigned idx = length - i - 1; + cachedCall.setThis(jsNull()); + cachedCall.setArgument(0, rv); + if (UNLIKELY(!array->canGetIndex(idx))) + break; // length has been made unsafe while we enumerate fallback to slow path + cachedCall.setArgument(1, array->getIndex(idx)); + cachedCall.setArgument(2, jsNumber(exec, idx)); + cachedCall.setArgument(3, array); + rv = cachedCall.call(); + } + if (i == length) // only return if we reached the end of the array + return rv; + } + + for (; i < length && !exec->hadException(); ++i) { + unsigned idx = length - i - 1; + JSValue prop = getProperty(exec, thisObj, idx); + if (!prop) + continue; + + MarkedArgumentBuffer eachArguments; + eachArguments.append(rv); + eachArguments.append(prop); + eachArguments.append(jsNumber(exec, idx)); + eachArguments.append(thisObj); + + rv = call(exec, function, callType, callData, jsNull(), eachArguments); + } + return rv; +} + +JSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + // JavaScript 1.5 Extension by Mozilla + // Documentation: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf + + JSObject* thisObj = thisValue.toThisObject(exec); + + unsigned index = 0; + double d = args.at(1).toInteger(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + if (d < 0) + d += length; + if (d > 0) { + if (d > length) + index = length; + else + index = static_cast<unsigned>(d); + } + + JSValue searchElement = args.at(0); + for (; index < length; ++index) { + JSValue e = getProperty(exec, thisObj, index); + if (!e) + continue; + if (JSValue::strictEqual(searchElement, e)) + return jsNumber(exec, index); + } + + return jsNumber(exec, -1); +} + +JSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + // JavaScript 1.6 Extension by Mozilla + // Documentation: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf + + JSObject* thisObj = thisValue.toThisObject(exec); + + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + int index = length - 1; + double d = args.at(1).toIntegerPreserveNaN(exec); + + if (d < 0) { + d += length; + if (d < 0) + return jsNumber(exec, -1); + } + if (d < length) + index = static_cast<int>(d); + + JSValue searchElement = args.at(0); + for (; index >= 0; --index) { + JSValue e = getProperty(exec, thisObj, index); + if (!e) + continue; + if (JSValue::strictEqual(searchElement, e)) + return jsNumber(exec, index); + } + + return jsNumber(exec, -1); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayPrototype.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayPrototype.h new file mode 100644 index 0000000..2165089 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayPrototype.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef ArrayPrototype_h +#define ArrayPrototype_h + +#include "JSArray.h" +#include "Lookup.h" + +namespace JSC { + + class ArrayPrototype : public JSArray { + public: + explicit ArrayPrototype(PassRefPtr<Structure>); + + bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + }; + +} // namespace JSC + +#endif // ArrayPrototype_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BatchedTransitionOptimizer.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BatchedTransitionOptimizer.h new file mode 100644 index 0000000..b9f738f --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BatchedTransitionOptimizer.h @@ -0,0 +1,55 @@ +// -*- mode: c++; c-basic-offset: 4 -*- +/* + * 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 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 BatchedTransitionOptimizer_h +#define BatchedTransitionOptimizer_h + +#include <wtf/Noncopyable.h> +#include "JSObject.h" + +namespace JSC { + + class BatchedTransitionOptimizer : public Noncopyable { + public: + BatchedTransitionOptimizer(JSObject* object) + : m_object(object) + { + if (!m_object->structure()->isDictionary()) + m_object->setStructure(Structure::toDictionaryTransition(m_object->structure())); + } + + ~BatchedTransitionOptimizer() + { + m_object->setStructure(Structure::fromDictionaryTransition(m_object->structure())); + } + + private: + JSObject* m_object; + }; + +} // namespace JSC + +#endif // BatchedTransitionOptimizer_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanConstructor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanConstructor.cpp new file mode 100644 index 0000000..9fcba37 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanConstructor.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "BooleanConstructor.h" + +#include "BooleanPrototype.h" +#include "JSGlobalObject.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(BooleanConstructor); + +BooleanConstructor::BooleanConstructor(ExecState* exec, PassRefPtr<Structure> structure, BooleanPrototype* booleanPrototype) + : InternalFunction(&exec->globalData(), structure, Identifier(exec, booleanPrototype->classInfo()->className)) +{ + putDirectWithoutTransition(exec->propertyNames().prototype, booleanPrototype, DontEnum | DontDelete | ReadOnly); + + // no. of arguments for constructor + putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 1), ReadOnly | DontDelete | DontEnum); +} + +// ECMA 15.6.2 +JSObject* constructBoolean(ExecState* exec, const ArgList& args) +{ + BooleanObject* obj = new (exec) BooleanObject(exec->lexicalGlobalObject()->booleanObjectStructure()); + obj->setInternalValue(jsBoolean(args.at(0).toBoolean(exec))); + return obj; +} + +static JSObject* constructWithBooleanConstructor(ExecState* exec, JSObject*, const ArgList& args) +{ + return constructBoolean(exec, args); +} + +ConstructType BooleanConstructor::getConstructData(ConstructData& constructData) +{ + constructData.native.function = constructWithBooleanConstructor; + return ConstructTypeHost; +} + +// ECMA 15.6.1 +static JSValue JSC_HOST_CALL callBooleanConstructor(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return jsBoolean(args.at(0).toBoolean(exec)); +} + +CallType BooleanConstructor::getCallData(CallData& callData) +{ + callData.native.function = callBooleanConstructor; + return CallTypeHost; +} + +JSObject* constructBooleanFromImmediateBoolean(ExecState* exec, JSValue immediateBooleanValue) +{ + BooleanObject* obj = new (exec) BooleanObject(exec->lexicalGlobalObject()->booleanObjectStructure()); + obj->setInternalValue(immediateBooleanValue); + return obj; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanConstructor.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanConstructor.h new file mode 100644 index 0000000..d9f51ab --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanConstructor.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 BooleanConstructor_h +#define BooleanConstructor_h + +#include "InternalFunction.h" + +namespace JSC { + + class BooleanPrototype; + + class BooleanConstructor : public InternalFunction { + public: + BooleanConstructor(ExecState*, PassRefPtr<Structure>, BooleanPrototype*); + + private: + virtual ConstructType getConstructData(ConstructData&); + virtual CallType getCallData(CallData&); + }; + + JSObject* constructBooleanFromImmediateBoolean(ExecState*, JSValue); + JSObject* constructBoolean(ExecState*, const ArgList&); + +} // namespace JSC + +#endif // BooleanConstructor_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanObject.cpp new file mode 100644 index 0000000..01f695a --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanObject.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "BooleanObject.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(BooleanObject); + +const ClassInfo BooleanObject::info = { "Boolean", 0, 0, 0 }; + +BooleanObject::BooleanObject(PassRefPtr<Structure> structure) + : JSWrapperObject(structure) +{ +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanObject.h new file mode 100644 index 0000000..cfd55fe --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanObject.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 BooleanObject_h +#define BooleanObject_h + +#include "JSWrapperObject.h" + +namespace JSC { + + class BooleanObject : public JSWrapperObject { + public: + explicit BooleanObject(PassRefPtr<Structure>); + + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + }; + + BooleanObject* asBooleanObject(JSValue); + + inline BooleanObject* asBooleanObject(JSValue value) + { + ASSERT(asObject(value)->inherits(&BooleanObject::info)); + return static_cast<BooleanObject*>(asObject(value)); + } + +} // namespace JSC + +#endif // BooleanObject_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanPrototype.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanPrototype.cpp new file mode 100644 index 0000000..703a568 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanPrototype.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "BooleanPrototype.h" + +#include "Error.h" +#include "JSFunction.h" +#include "JSString.h" +#include "ObjectPrototype.h" +#include "PrototypeFunction.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(BooleanPrototype); + +// Functions +static JSValue JSC_HOST_CALL booleanProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL booleanProtoFuncValueOf(ExecState*, JSObject*, JSValue, const ArgList&); + +// ECMA 15.6.4 + +BooleanPrototype::BooleanPrototype(ExecState* exec, PassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) + : BooleanObject(structure) +{ + setInternalValue(jsBoolean(false)); + + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().toString, booleanProtoFuncToString), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().valueOf, booleanProtoFuncValueOf), DontEnum); +} + + +// ------------------------------ Functions -------------------------- + +// ECMA 15.6.4.2 + 15.6.4.3 + +JSValue JSC_HOST_CALL booleanProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (thisValue == jsBoolean(false)) + return jsNontrivialString(exec, "false"); + + if (thisValue == jsBoolean(true)) + return jsNontrivialString(exec, "true"); + + if (!thisValue.isObject(&BooleanObject::info)) + return throwError(exec, TypeError); + + if (asBooleanObject(thisValue)->internalValue() == jsBoolean(false)) + return jsNontrivialString(exec, "false"); + + ASSERT(asBooleanObject(thisValue)->internalValue() == jsBoolean(true)); + return jsNontrivialString(exec, "true"); +} + +JSValue JSC_HOST_CALL booleanProtoFuncValueOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (thisValue.isBoolean()) + return thisValue; + + if (!thisValue.isObject(&BooleanObject::info)) + return throwError(exec, TypeError); + + return asBooleanObject(thisValue)->internalValue(); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanPrototype.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanPrototype.h new file mode 100644 index 0000000..16f80b5 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanPrototype.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 BooleanPrototype_h +#define BooleanPrototype_h + +#include "BooleanObject.h" + +namespace JSC { + + class BooleanPrototype : public BooleanObject { + public: + BooleanPrototype(ExecState*, PassRefPtr<Structure>, Structure* prototypeFunctionStructure); + }; + +} // namespace JSC + +#endif // BooleanPrototype_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CallData.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CallData.cpp new file mode 100644 index 0000000..c89ebf8 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CallData.cpp @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#include "config.h" +#include "CallData.h" + +#include "JSFunction.h" +#include "JSGlobalObject.h" + +#ifdef QT_BUILD_SCRIPT_LIB +#include "Debugger.h" +#include "DebuggerCallFrame.h" +#endif + +namespace JSC { + +#ifdef QT_BUILD_SCRIPT_LIB +JSValue JSC::NativeFuncWrapper::operator() (ExecState* exec, JSObject* jsobj, JSValue thisValue, const ArgList& argList) const +{ + Debugger* debugger = exec->lexicalGlobalObject()->debugger(); + if (debugger) + debugger->callEvent(DebuggerCallFrame(exec), -1, -1); + + JSValue returnValue = ptr(exec, jsobj, thisValue, argList); + + if (debugger) + debugger->functionExit(returnValue, -1); + + return returnValue; +} +#endif + + +JSValue call(ExecState* exec, JSValue functionObject, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args) +{ + if (callType == CallTypeHost) + return callData.native.function(exec, asObject(functionObject), thisValue, args); + ASSERT(callType == CallTypeJS); + // FIXME: Can this be done more efficiently using the callData? + return asFunction(functionObject)->call(exec, thisValue, args); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CallData.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CallData.h new file mode 100644 index 0000000..541779c --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CallData.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CallData_h +#define CallData_h + +#include "NativeFunctionWrapper.h" + +namespace JSC { + + class ArgList; + class ExecState; + class FunctionBodyNode; + class JSObject; + class JSValue; + class ScopeChainNode; + + enum CallType { + CallTypeNone, + CallTypeHost, + CallTypeJS + }; + + typedef JSValue (JSC_HOST_CALL *NativeFunction)(ExecState*, JSObject*, JSValue thisValue, const ArgList&); + +#ifdef QT_BUILD_SCRIPT_LIB + class NativeFuncWrapper + { + NativeFunction ptr; + public: + inline NativeFuncWrapper& operator=(NativeFunction func) + { + ptr = func; + return *this; + } + inline operator NativeFunction() const {return ptr;} + inline operator bool() const {return ptr;} + + JSValue operator()(ExecState* exec, JSObject* jsobj, JSValue thisValue, const ArgList& argList) const; + }; +#endif + +#if defined(QT_BUILD_SCRIPT_LIB) && PLATFORM(SOLARIS) + struct +#else + union +#endif + CallData { + struct { +#ifndef QT_BUILD_SCRIPT_LIB + NativeFunction function; +#else + NativeFuncWrapper function; +#endif + } native; + struct { + FunctionBodyNode* functionBody; + ScopeChainNode* scopeChain; + } js; + }; + + JSValue call(ExecState*, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&); + +} // namespace JSC + +#endif // CallData_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ClassInfo.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ClassInfo.h new file mode 100644 index 0000000..097fb09 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ClassInfo.h @@ -0,0 +1,62 @@ +/* + * 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 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef ClassInfo_h +#define ClassInfo_h + +#include "CallFrame.h" + +namespace JSC { + + struct HashEntry; + struct HashTable; + + struct ClassInfo { + /** + * A string denoting the class name. Example: "Window". + */ + const char* className; + + /** + * Pointer to the class information of the base class. + * 0L if 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 thread-specific value. + */ + const HashTable* propHashTable(ExecState* exec) const + { + if (classPropHashTableGetterFunction) + return classPropHashTableGetterFunction(exec); + return staticPropHashTable; + } + + const HashTable* staticPropHashTable; + typedef const HashTable* (*ClassPropHashTableGetterFunction)(ExecState*); + const ClassPropHashTableGetterFunction classPropHashTableGetterFunction; + }; + +} // namespace JSC + +#endif // ClassInfo_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.cpp new file mode 100644 index 0000000..d7fbce8 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.cpp @@ -0,0 +1,1376 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "Collector.h" + +#include "ArgList.h" +#include "CallFrame.h" +#include "CollectorHeapIterator.h" +#include "Interpreter.h" +#include "JSGlobalObject.h" +#include "JSLock.h" +#include "JSONObject.h" +#include "JSString.h" +#include "JSValue.h" +#include "Nodes.h" +#include "Tracing.h" +#include <algorithm> +#include <setjmp.h> +#include <stdlib.h> +#include <wtf/FastMalloc.h> +#include <wtf/HashCountedSet.h> +#include <wtf/UnusedParam.h> +#include <wtf/VMTags.h> + +#if PLATFORM(DARWIN) + +#include <mach/mach_init.h> +#include <mach/mach_port.h> +#include <mach/task.h> +#include <mach/thread_act.h> +#include <mach/vm_map.h> + +#elif PLATFORM(SYMBIAN) +#include <e32std.h> +#include <e32cmn.h> +#include <unistd.h> + +#elif PLATFORM(WIN_OS) + +#include <windows.h> + +#elif PLATFORM(UNIX) + +#include <stdlib.h> +#include <sys/mman.h> +#include <unistd.h> + +#if defined(QT_LINUXBASE) +#include <dlfcn.h> +#endif + +#if defined(__UCLIBC__) +// versions of uClibc 0.9.28 and below do not have +// pthread_getattr_np or pthread_attr_getstack. +#if __UCLIBC_MAJOR__ == 0 && \ + (__UCLIBC_MINOR__ < 9 || \ + (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ <= 30)) +#define UCLIBC_USE_PROC_SELF_MAPS 1 +#include <stdio_ext.h> +extern int *__libc_stack_end; +#endif +#endif + +#if PLATFORM(SOLARIS) +#include <thread.h> +#else +#include <pthread.h> +#endif + +#if HAVE(PTHREAD_NP_H) +#include <pthread_np.h> +#endif + +#if PLATFORM(QNX) +#include <fcntl.h> +#include <sys/procfs.h> +#include <stdio.h> +#include <errno.h> +#endif + +#endif + +#define DEBUG_COLLECTOR 0 +#define COLLECT_ON_EVERY_ALLOCATION 0 + +using std::max; + +namespace JSC { + +// tunable parameters + +const size_t SPARE_EMPTY_BLOCKS = 2; +const size_t GROWTH_FACTOR = 2; +const size_t LOW_WATER_FACTOR = 4; +const size_t ALLOCATIONS_PER_COLLECTION = 4000; +// This value has to be a macro to be used in max() without introducing +// a PIC branch in Mach-O binaries, see <rdar://problem/5971391>. +#define MIN_ARRAY_SIZE (static_cast<size_t>(14)) + +#if PLATFORM(SYMBIAN) +const size_t MAX_NUM_BLOCKS = 256; // Max size of collector heap set to 16 MB +static RHeap* userChunk = 0; +#endif + +static void freeHeap(CollectorHeap*); + +#if ENABLE(JSC_MULTIPLE_THREADS) + +#if PLATFORM(DARWIN) +typedef mach_port_t PlatformThread; +#elif PLATFORM(WIN_OS) +struct PlatformThread { + PlatformThread(DWORD _id, HANDLE _handle) : id(_id), handle(_handle) {} + DWORD id; + HANDLE handle; +}; +#endif + +class Heap::Thread { +public: + Thread(pthread_t pthread, const PlatformThread& platThread, void* base) + : posixThread(pthread) + , platformThread(platThread) + , stackBase(base) + { + } + + Thread* next; + pthread_t posixThread; + PlatformThread platformThread; + void* stackBase; +}; + +#endif + +Heap::Heap(JSGlobalData* globalData) + : m_markListSet(0) +#if ENABLE(JSC_MULTIPLE_THREADS) + , m_registeredThreads(0) + , m_currentThreadRegistrar(0) +#endif + , m_globalData(globalData) +{ + ASSERT(globalData); + +#if PLATFORM(SYMBIAN) + // Symbian OpenC supports mmap but currently not the MAP_ANON flag. + // Using fastMalloc() does not properly align blocks on 64k boundaries + // and previous implementation was flawed/incomplete. + // UserHeap::ChunkHeap allows allocation of continuous memory and specification + // of alignment value for (symbian) cells within that heap. + // + // Clarification and mapping of terminology: + // RHeap (created by UserHeap::ChunkHeap below) is continuos memory chunk, + // which can dynamically grow up to 8 MB, + // that holds all CollectorBlocks of this session (static). + // Each symbian cell within RHeap maps to a 64kb aligned CollectorBlock. + // JSCell objects are maintained as usual within CollectorBlocks. + if (!userChunk) { + userChunk = UserHeap::ChunkHeap(0, 0, MAX_NUM_BLOCKS * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); + if (!userChunk) + CRASH(); + } +#endif // PLATFORM(SYMBIAN) + + memset(&primaryHeap, 0, sizeof(CollectorHeap)); + memset(&numberHeap, 0, sizeof(CollectorHeap)); +} + +Heap::~Heap() +{ + // The destroy function must already have been called, so assert this. + ASSERT(!m_globalData); +} + +void Heap::destroy() +{ + JSLock lock(SilenceAssertionsOnly); + + if (!m_globalData) + return; + + // The global object is not GC protected at this point, so sweeping may delete it + // (and thus the global data) before other objects that may use the global data. + RefPtr<JSGlobalData> protect(m_globalData); + + delete m_markListSet; + m_markListSet = 0; + + sweep<PrimaryHeap>(); + // No need to sweep number heap, because the JSNumber destructor doesn't do anything. + + ASSERT(!primaryHeap.numLiveObjects); + + freeHeap(&primaryHeap); + freeHeap(&numberHeap); + +#if ENABLE(JSC_MULTIPLE_THREADS) + if (m_currentThreadRegistrar) { + int error = pthread_key_delete(m_currentThreadRegistrar); + ASSERT_UNUSED(error, !error); + } + + MutexLocker registeredThreadsLock(m_registeredThreadsMutex); + for (Heap::Thread* t = m_registeredThreads; t;) { + Heap::Thread* next = t->next; + delete t; + t = next; + } +#endif + + m_globalData = 0; +} + +template <HeapType heapType> +static NEVER_INLINE CollectorBlock* allocateBlock() +{ + // Disable the use of vm_map for the Qt build on Darwin, because when compiled on 10.4 + // it crashes on 10.5 +#if PLATFORM(DARWIN) && !PLATFORM(QT) + vm_address_t address = 0; + // FIXME: tag the region as a JavaScriptCore heap when we get a registered VM tag: <rdar://problem/6054788>. + vm_map(current_task(), &address, BLOCK_SIZE, BLOCK_OFFSET_MASK, VM_FLAGS_ANYWHERE | VM_TAG_FOR_COLLECTOR_MEMORY, MEMORY_OBJECT_NULL, 0, FALSE, VM_PROT_DEFAULT, VM_PROT_DEFAULT, VM_INHERIT_DEFAULT); +#elif PLATFORM(SYMBIAN) + // Allocate a 64 kb aligned CollectorBlock + unsigned char* mask = reinterpret_cast<unsigned char*>(userChunk->Alloc(BLOCK_SIZE)); + if (!mask) + CRASH(); + uintptr_t address = reinterpret_cast<uintptr_t>(mask); + + memset(reinterpret_cast<void*>(address), 0, BLOCK_SIZE); +#elif PLATFORM(WIN_OS) + // windows virtual address granularity is naturally 64k + LPVOID address = VirtualAlloc(NULL, BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); +#elif HAVE(POSIX_MEMALIGN) + void* address; + posix_memalign(&address, BLOCK_SIZE, BLOCK_SIZE); + memset(address, 0, BLOCK_SIZE); +#else + +#if ENABLE(JSC_MULTIPLE_THREADS) +#error Need to initialize pagesize safely. +#endif + static size_t pagesize = getpagesize(); + + size_t extra = 0; + if (BLOCK_SIZE > pagesize) + extra = BLOCK_SIZE - pagesize; + + void* mmapResult = mmap(NULL, BLOCK_SIZE + extra, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); + uintptr_t address = reinterpret_cast<uintptr_t>(mmapResult); + + size_t adjust = 0; + if ((address & BLOCK_OFFSET_MASK) != 0) + adjust = BLOCK_SIZE - (address & BLOCK_OFFSET_MASK); + + if (adjust > 0) + munmap(reinterpret_cast<char*>(address), adjust); + + if (adjust < extra) + munmap(reinterpret_cast<char*>(address + adjust + BLOCK_SIZE), extra - adjust); + + address += adjust; + memset(reinterpret_cast<void*>(address), 0, BLOCK_SIZE); +#endif + reinterpret_cast<CollectorBlock*>(address)->type = heapType; + return reinterpret_cast<CollectorBlock*>(address); +} + +static void freeBlock(CollectorBlock* block) +{ + // Disable the use of vm_deallocate for the Qt build on Darwin, because when compiled on 10.4 + // it crashes on 10.5 +#if PLATFORM(DARWIN) && !PLATFORM(QT) + vm_deallocate(current_task(), reinterpret_cast<vm_address_t>(block), BLOCK_SIZE); +#elif PLATFORM(SYMBIAN) + userChunk->Free(reinterpret_cast<TAny*>(block)); +#elif PLATFORM(WIN_OS) + VirtualFree(block, 0, MEM_RELEASE); +#elif HAVE(POSIX_MEMALIGN) + free(block); +#else + munmap(reinterpret_cast<char*>(block), BLOCK_SIZE); +#endif +} + +static void freeHeap(CollectorHeap* heap) +{ + for (size_t i = 0; i < heap->usedBlocks; ++i) + if (heap->blocks[i]) + freeBlock(heap->blocks[i]); + fastFree(heap->blocks); + memset(heap, 0, sizeof(CollectorHeap)); +} + +void Heap::recordExtraCost(size_t cost) +{ + // Our frequency of garbage collection tries to balance memory use against speed + // by collecting based on the number of newly created values. However, for values + // that hold on to a great deal of memory that's not in the form of other JS values, + // that is not good enough - in some cases a lot of those objects can pile up and + // use crazy amounts of memory without a GC happening. So we track these extra + // memory costs. Only unusually large objects are noted, and we only keep track + // of this extra cost until the next GC. In garbage collected languages, most values + // are either very short lived temporaries, or have extremely long lifetimes. So + // if a large value survives one garbage collection, there is not much point to + // collecting more frequently as long as it stays alive. + // NOTE: we target the primaryHeap unconditionally as JSNumber doesn't modify cost + + primaryHeap.extraCost += cost; +} + +template <HeapType heapType> ALWAYS_INLINE void* Heap::heapAllocate(size_t s) +{ + typedef typename HeapConstants<heapType>::Block Block; + typedef typename HeapConstants<heapType>::Cell Cell; + + CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap; + ASSERT(JSLock::lockCount() > 0); + ASSERT(JSLock::currentThreadIsHoldingLock()); + ASSERT_UNUSED(s, s <= HeapConstants<heapType>::cellSize); + + ASSERT(heap.operationInProgress == NoOperation); + ASSERT(heapType == PrimaryHeap || heap.extraCost == 0); + // FIXME: If another global variable access here doesn't hurt performance + // too much, we could CRASH() in NDEBUG builds, which could help ensure we + // don't spend any time debugging cases where we allocate inside an object's + // deallocation code. + +#if COLLECT_ON_EVERY_ALLOCATION + collect(); +#endif + + size_t numLiveObjects = heap.numLiveObjects; + size_t usedBlocks = heap.usedBlocks; + size_t i = heap.firstBlockWithPossibleSpace; + + // if we have a huge amount of extra cost, we'll try to collect even if we still have + // free cells left. + if (heapType == PrimaryHeap && heap.extraCost > ALLOCATIONS_PER_COLLECTION) { + size_t numLiveObjectsAtLastCollect = heap.numLiveObjectsAtLastCollect; + size_t numNewObjects = numLiveObjects - numLiveObjectsAtLastCollect; + const size_t newCost = numNewObjects + heap.extraCost; + if (newCost >= ALLOCATIONS_PER_COLLECTION && newCost >= numLiveObjectsAtLastCollect) + goto collect; + } + + ASSERT(heap.operationInProgress == NoOperation); +#ifndef NDEBUG + // FIXME: Consider doing this in NDEBUG builds too (see comment above). + heap.operationInProgress = Allocation; +#endif + +scan: + Block* targetBlock; + size_t targetBlockUsedCells; + if (i != usedBlocks) { + targetBlock = reinterpret_cast<Block*>(heap.blocks[i]); + targetBlockUsedCells = targetBlock->usedCells; + ASSERT(targetBlockUsedCells <= HeapConstants<heapType>::cellsPerBlock); + while (targetBlockUsedCells == HeapConstants<heapType>::cellsPerBlock) { + if (++i == usedBlocks) + goto collect; + targetBlock = reinterpret_cast<Block*>(heap.blocks[i]); + targetBlockUsedCells = targetBlock->usedCells; + ASSERT(targetBlockUsedCells <= HeapConstants<heapType>::cellsPerBlock); + } + heap.firstBlockWithPossibleSpace = i; + } else { + +collect: + size_t numLiveObjectsAtLastCollect = heap.numLiveObjectsAtLastCollect; + size_t numNewObjects = numLiveObjects - numLiveObjectsAtLastCollect; + const size_t newCost = numNewObjects + heap.extraCost; + + if (newCost >= ALLOCATIONS_PER_COLLECTION && newCost >= numLiveObjectsAtLastCollect) { +#ifndef NDEBUG + heap.operationInProgress = NoOperation; +#endif + bool collected = collect(); +#ifndef NDEBUG + heap.operationInProgress = Allocation; +#endif + if (collected) { + numLiveObjects = heap.numLiveObjects; + usedBlocks = heap.usedBlocks; + i = heap.firstBlockWithPossibleSpace; + goto scan; + } + } + + // didn't find a block, and GC didn't reclaim anything, need to allocate a new block + size_t numBlocks = heap.numBlocks; + if (usedBlocks == numBlocks) { + static const size_t maxNumBlocks = ULONG_MAX / sizeof(CollectorBlock*) / GROWTH_FACTOR; + if (numBlocks > maxNumBlocks) + CRASH(); + numBlocks = max(MIN_ARRAY_SIZE, numBlocks * GROWTH_FACTOR); + heap.numBlocks = numBlocks; + heap.blocks = static_cast<CollectorBlock**>(fastRealloc(heap.blocks, numBlocks * sizeof(CollectorBlock*))); + } + + targetBlock = reinterpret_cast<Block*>(allocateBlock<heapType>()); + targetBlock->freeList = targetBlock->cells; + targetBlock->heap = this; + targetBlockUsedCells = 0; + heap.blocks[usedBlocks] = reinterpret_cast<CollectorBlock*>(targetBlock); + heap.usedBlocks = usedBlocks + 1; + heap.firstBlockWithPossibleSpace = usedBlocks; + } + + // find a free spot in the block and detach it from the free list + Cell* newCell = targetBlock->freeList; + + // "next" field is a cell offset -- 0 means next cell, so a zeroed block is already initialized + targetBlock->freeList = (newCell + 1) + newCell->u.freeCell.next; + + targetBlock->usedCells = static_cast<uint32_t>(targetBlockUsedCells + 1); + heap.numLiveObjects = numLiveObjects + 1; + +#ifndef NDEBUG + // FIXME: Consider doing this in NDEBUG builds too (see comment above). + heap.operationInProgress = NoOperation; +#endif + + return newCell; +} + +void* Heap::allocate(size_t s) +{ + return heapAllocate<PrimaryHeap>(s); +} + +void* Heap::allocateNumber(size_t s) +{ + return heapAllocate<NumberHeap>(s); +} + +#if PLATFORM(WINCE) +void* g_stackBase = 0; + +inline bool isPageWritable(void* page) +{ + MEMORY_BASIC_INFORMATION memoryInformation; + DWORD result = VirtualQuery(page, &memoryInformation, sizeof(memoryInformation)); + + // return false on error, including ptr outside memory + if (result != sizeof(memoryInformation)) + return false; + + DWORD protect = memoryInformation.Protect & ~(PAGE_GUARD | PAGE_NOCACHE); + return protect == PAGE_READWRITE + || protect == PAGE_WRITECOPY + || protect == PAGE_EXECUTE_READWRITE + || protect == PAGE_EXECUTE_WRITECOPY; +} + +static void* getStackBase(void* previousFrame) +{ + // find the address of this stack frame by taking the address of a local variable + bool isGrowingDownward; + void* thisFrame = (void*)(&isGrowingDownward); + + isGrowingDownward = previousFrame < &thisFrame; + static DWORD pageSize = 0; + if (!pageSize) { + SYSTEM_INFO systemInfo; + GetSystemInfo(&systemInfo); + pageSize = systemInfo.dwPageSize; + } + + // scan all of memory starting from this frame, and return the last writeable page found + register char* currentPage = (char*)((DWORD)thisFrame & ~(pageSize - 1)); + if (isGrowingDownward) { + while (currentPage > 0) { + // check for underflow + if (currentPage >= (char*)pageSize) + currentPage -= pageSize; + else + currentPage = 0; + if (!isPageWritable(currentPage)) + return currentPage + pageSize; + } + return 0; + } else { + while (true) { + // guaranteed to complete because isPageWritable returns false at end of memory + currentPage += pageSize; + if (!isPageWritable(currentPage)) + return currentPage; + } + } +} +#endif +#if PLATFORM(HPUX) +struct hpux_get_stack_base_data +{ + pthread_t thread; + _pthread_stack_info info; +}; + +static void *hpux_get_stack_base_internal(void *d) +{ + hpux_get_stack_base_data *data = static_cast<hpux_get_stack_base_data *>(d); + + // _pthread_stack_info_np requires the target thread to be suspended + // in order to get information about it + pthread_suspend(data->thread); + + // _pthread_stack_info_np returns an errno code in case of failure + // or zero on success + if (_pthread_stack_info_np(data->thread, &data->info)) { + // failed + return 0; + } + + pthread_continue(data->thread); + return data; +} + +static void *hpux_get_stack_base() +{ + hpux_get_stack_base_data data; + data.thread = pthread_self(); + + // We cannot get the stack information for the current thread + // So we start a new thread to get that information and return it to us + pthread_t other; + pthread_create(&other, 0, hpux_get_stack_base_internal, &data); + + void *result; + pthread_join(other, &result); + if (result) + return data.info.stk_stack_base; + return 0; +} +#endif + +static inline void* currentThreadStackBase() +{ +#if PLATFORM(DARWIN) + pthread_t thread = pthread_self(); + return pthread_get_stackaddr_np(thread); +#elif PLATFORM(WIN_OS) && PLATFORM(X86) && COMPILER(MSVC) + // offset 0x18 from the FS segment register gives a pointer to + // the thread information block for the current thread + NT_TIB* pTib; + __asm { + MOV EAX, FS:[18h] + MOV pTib, EAX + } + return static_cast<void*>(pTib->StackBase); +#elif PLATFORM(WIN_OS) && PLATFORM(X86_64) && COMPILER(MSVC) + PNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb()); + return reinterpret_cast<void*>(pTib->StackBase); +#elif PLATFORM(WIN_OS) && PLATFORM(X86) && COMPILER(GCC) + // offset 0x18 from the FS segment register gives a pointer to + // the thread information block for the current thread + NT_TIB* pTib; + asm ( "movl %%fs:0x18, %0\n" + : "=r" (pTib) + ); + return static_cast<void*>(pTib->StackBase); +#elif PLATFORM(HPUX) + return hpux_get_stack_base(); +#elif PLATFORM(SOLARIS) + stack_t s; + thr_stksegment(&s); + return s.ss_sp; +#elif PLATFORM(AIX) + pthread_t thread = pthread_self(); + struct __pthrdsinfo threadinfo; + char regbuf[256]; + int regbufsize = sizeof regbuf; + + if (pthread_getthrds_np(&thread, PTHRDSINFO_QUERY_ALL, + &threadinfo, sizeof threadinfo, + ®buf, ®bufsize) == 0) + return threadinfo.__pi_stackaddr; + + return 0; +#elif PLATFORM(OPENBSD) + pthread_t thread = pthread_self(); + stack_t stack; + pthread_stackseg_np(thread, &stack); + return stack.ss_sp; +#elif PLATFORM(SYMBIAN) + static void* stackBase = 0; + if (stackBase == 0) { + TThreadStackInfo info; + RThread thread; + thread.StackInfo(info); + stackBase = (void*)info.iBase; + } + return (void*)stackBase; +#elif PLATFORM(UNIX) +#ifdef UCLIBC_USE_PROC_SELF_MAPS + // Read /proc/self/maps and locate the line whose address + // range contains __libc_stack_end. + FILE *file = fopen("/proc/self/maps", "r"); + if (!file) + return 0; + __fsetlocking(file, FSETLOCKING_BYCALLER); + char *line = NULL; + size_t lineLen = 0; + while (!feof_unlocked(file)) { + if (getdelim(&line, &lineLen, '\n', file) <= 0) + break; + + long from; + long to; + if (sscanf (line, "%lx-%lx", &from, &to) != 2) + continue; + if (from <= (long)__libc_stack_end && (long)__libc_stack_end < to) { + fclose(file); + free(line); +#ifdef _STACK_GROWS_UP + return (void *)from; +#else + return (void *)to; +#endif + } + } + fclose(file); + free(line); + return 0; +#else + static void* stackBase = 0; + static size_t stackSize = 0; + static pthread_t stackThread; + pthread_t thread = pthread_self(); + if (stackBase == 0 || thread != stackThread) { +#if PLATFORM(QNX) + int fd; + struct _debug_thread_info tinfo; + memset(&tinfo, 0, sizeof(tinfo)); + tinfo.tid = pthread_self(); + fd = open("/proc/self", O_RDONLY); + if (fd == -1) { +#ifndef NDEBUG + perror("Unable to open /proc/self:"); +#endif + return 0; + } + devctl(fd, DCMD_PROC_TIDSTATUS, &tinfo, sizeof(tinfo), NULL); + close(fd); + stackBase = (void*)tinfo.stkbase; + stackSize = tinfo.stksize; + ASSERT(stackBase); +#else +#if defined(QT_LINUXBASE) + // LinuxBase is missing pthread_getattr_np - resolve it once at runtime instead + // see http://bugs.linuxbase.org/show_bug.cgi?id=2364 + typedef int (*GetAttrPtr)(pthread_t, pthread_attr_t *); + static int (*pthread_getattr_np_ptr)(pthread_t, pthread_attr_t *) = 0; + if (!pthread_getattr_np_ptr) + *(void **)&pthread_getattr_np_ptr = dlsym(RTLD_DEFAULT, "pthread_getattr_np"); +#endif + pthread_attr_t sattr; + pthread_attr_init(&sattr); +#if HAVE(PTHREAD_NP_H) || PLATFORM(NETBSD) + // e.g. on FreeBSD 5.4, neundorf@kde.org + pthread_attr_get_np(thread, &sattr); +#elif defined(QT_LINUXBASE) + if (pthread_getattr_np_ptr) + pthread_getattr_np_ptr(thread, &sattr); +#else + // FIXME: this function is non-portable; other POSIX systems may have different np alternatives + pthread_getattr_np(thread, &sattr); +#endif + int rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize); + (void)rc; // FIXME: Deal with error code somehow? Seems fatal. + ASSERT(stackBase); + pthread_attr_destroy(&sattr); +#endif + stackThread = thread; + } + return static_cast<char*>(stackBase) + stackSize; +#endif +#elif PLATFORM(WINCE) + if (g_stackBase) + return g_stackBase; + else { + int dummy; + return getStackBase(&dummy); + } +#else +#error Need a way to get the stack base on this platform +#endif +} + +#if ENABLE(JSC_MULTIPLE_THREADS) + +static inline PlatformThread getCurrentPlatformThread() +{ +#if PLATFORM(DARWIN) + return pthread_mach_thread_np(pthread_self()); +#elif PLATFORM(WIN_OS) + HANDLE threadHandle = pthread_getw32threadhandle_np(pthread_self()); + return PlatformThread(GetCurrentThreadId(), threadHandle); +#endif +} + +void Heap::makeUsableFromMultipleThreads() +{ + if (m_currentThreadRegistrar) + return; + + int error = pthread_key_create(&m_currentThreadRegistrar, unregisterThread); + if (error) + CRASH(); +} + +void Heap::registerThread() +{ + if (!m_currentThreadRegistrar || pthread_getspecific(m_currentThreadRegistrar)) + return; + + pthread_setspecific(m_currentThreadRegistrar, this); + Heap::Thread* thread = new Heap::Thread(pthread_self(), getCurrentPlatformThread(), currentThreadStackBase()); + + MutexLocker lock(m_registeredThreadsMutex); + + thread->next = m_registeredThreads; + m_registeredThreads = thread; +} + +void Heap::unregisterThread(void* p) +{ + if (p) + static_cast<Heap*>(p)->unregisterThread(); +} + +void Heap::unregisterThread() +{ + pthread_t currentPosixThread = pthread_self(); + + MutexLocker lock(m_registeredThreadsMutex); + + if (pthread_equal(currentPosixThread, m_registeredThreads->posixThread)) { + Thread* t = m_registeredThreads; + m_registeredThreads = m_registeredThreads->next; + delete t; + } else { + Heap::Thread* last = m_registeredThreads; + Heap::Thread* t; + for (t = m_registeredThreads->next; t; t = t->next) { + if (pthread_equal(t->posixThread, currentPosixThread)) { + last->next = t->next; + break; + } + last = t; + } + ASSERT(t); // If t is NULL, we never found ourselves in the list. + delete t; + } +} + +#else // ENABLE(JSC_MULTIPLE_THREADS) + +void Heap::registerThread() +{ +} + +#endif + +#define IS_POINTER_ALIGNED(p) (((intptr_t)(p) & (sizeof(char*) - 1)) == 0) + +// cell size needs to be a power of two for this to be valid +#define IS_HALF_CELL_ALIGNED(p) (((intptr_t)(p) & (CELL_MASK >> 1)) == 0) + +void Heap::markConservatively(void* start, void* end) +{ + if (start > end) { + void* tmp = start; + start = end; + end = tmp; + } + + ASSERT((static_cast<char*>(end) - static_cast<char*>(start)) < 0x1000000); + ASSERT(IS_POINTER_ALIGNED(start)); + ASSERT(IS_POINTER_ALIGNED(end)); + + char** p = static_cast<char**>(start); + char** e = static_cast<char**>(end); + + size_t usedPrimaryBlocks = primaryHeap.usedBlocks; + size_t usedNumberBlocks = numberHeap.usedBlocks; + CollectorBlock** primaryBlocks = primaryHeap.blocks; + CollectorBlock** numberBlocks = numberHeap.blocks; + + const size_t lastCellOffset = sizeof(CollectorCell) * (CELLS_PER_BLOCK - 1); + + while (p != e) { + char* x = *p++; + if (IS_HALF_CELL_ALIGNED(x) && x) { + uintptr_t xAsBits = reinterpret_cast<uintptr_t>(x); + xAsBits &= CELL_ALIGN_MASK; + uintptr_t offset = xAsBits & BLOCK_OFFSET_MASK; + CollectorBlock* blockAddr = reinterpret_cast<CollectorBlock*>(xAsBits - offset); + // Mark the the number heap, we can mark these Cells directly to avoid the virtual call cost + for (size_t block = 0; block < usedNumberBlocks; block++) { + if ((numberBlocks[block] == blockAddr) & (offset <= lastCellOffset)) { + Heap::markCell(reinterpret_cast<JSCell*>(xAsBits)); + goto endMarkLoop; + } + } + + // Mark the primary heap + for (size_t block = 0; block < usedPrimaryBlocks; block++) { + if ((primaryBlocks[block] == blockAddr) & (offset <= lastCellOffset)) { + if (reinterpret_cast<CollectorCell*>(xAsBits)->u.freeCell.zeroIfFree != 0) { + JSCell* imp = reinterpret_cast<JSCell*>(xAsBits); + if (!imp->marked()) + imp->mark(); + } + break; + } + } + endMarkLoop: + ; + } + } +} + +void NEVER_INLINE Heap::markCurrentThreadConservativelyInternal() +{ + void* dummy; + void* stackPointer = &dummy; + void* stackBase = currentThreadStackBase(); + markConservatively(stackPointer, stackBase); +} + +void Heap::markCurrentThreadConservatively() +{ + // setjmp forces volatile registers onto the stack + jmp_buf registers; +#if COMPILER(MSVC) +#pragma warning(push) +#pragma warning(disable: 4611) +#endif + setjmp(registers); +#if COMPILER(MSVC) +#pragma warning(pop) +#endif + + markCurrentThreadConservativelyInternal(); +} + +#if ENABLE(JSC_MULTIPLE_THREADS) + +static inline void suspendThread(const PlatformThread& platformThread) +{ +#if PLATFORM(DARWIN) + thread_suspend(platformThread); +#elif PLATFORM(WIN_OS) + SuspendThread(platformThread.handle); +#else +#error Need a way to suspend threads on this platform +#endif +} + +static inline void resumeThread(const PlatformThread& platformThread) +{ +#if PLATFORM(DARWIN) + thread_resume(platformThread); +#elif PLATFORM(WIN_OS) + ResumeThread(platformThread.handle); +#else +#error Need a way to resume threads on this platform +#endif +} + +typedef unsigned long usword_t; // word size, assumed to be either 32 or 64 bit + +#if PLATFORM(DARWIN) + +#if PLATFORM(X86) +typedef i386_thread_state_t PlatformThreadRegisters; +#elif PLATFORM(X86_64) +typedef x86_thread_state64_t PlatformThreadRegisters; +#elif PLATFORM(PPC) +typedef ppc_thread_state_t PlatformThreadRegisters; +#elif PLATFORM(PPC64) +typedef ppc_thread_state64_t PlatformThreadRegisters; +#elif PLATFORM(ARM) +typedef arm_thread_state_t PlatformThreadRegisters; +#else +#error Unknown Architecture +#endif + +#elif PLATFORM(WIN_OS)&& PLATFORM(X86) +typedef CONTEXT PlatformThreadRegisters; +#else +#error Need a thread register struct for this platform +#endif + +static size_t getPlatformThreadRegisters(const PlatformThread& platformThread, PlatformThreadRegisters& regs) +{ +#if PLATFORM(DARWIN) + +#if PLATFORM(X86) + unsigned user_count = sizeof(regs)/sizeof(int); + thread_state_flavor_t flavor = i386_THREAD_STATE; +#elif PLATFORM(X86_64) + unsigned user_count = x86_THREAD_STATE64_COUNT; + thread_state_flavor_t flavor = x86_THREAD_STATE64; +#elif PLATFORM(PPC) + unsigned user_count = PPC_THREAD_STATE_COUNT; + thread_state_flavor_t flavor = PPC_THREAD_STATE; +#elif PLATFORM(PPC64) + unsigned user_count = PPC_THREAD_STATE64_COUNT; + thread_state_flavor_t flavor = PPC_THREAD_STATE64; +#elif PLATFORM(ARM) + unsigned user_count = ARM_THREAD_STATE_COUNT; + thread_state_flavor_t flavor = ARM_THREAD_STATE; +#else +#error Unknown Architecture +#endif + + kern_return_t result = thread_get_state(platformThread, flavor, (thread_state_t)®s, &user_count); + if (result != KERN_SUCCESS) { + WTFReportFatalError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, + "JavaScript garbage collection failed because thread_get_state returned an error (%d). This is probably the result of running inside Rosetta, which is not supported.", result); + CRASH(); + } + return user_count * sizeof(usword_t); +// end PLATFORM(DARWIN) + +#elif PLATFORM(WIN_OS) && PLATFORM(X86) + regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS; + GetThreadContext(platformThread.handle, ®s); + return sizeof(CONTEXT); +#else +#error Need a way to get thread registers on this platform +#endif +} + +static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs) +{ +#if PLATFORM(DARWIN) + +#if __DARWIN_UNIX03 + +#if PLATFORM(X86) + return reinterpret_cast<void*>(regs.__esp); +#elif PLATFORM(X86_64) + return reinterpret_cast<void*>(regs.__rsp); +#elif PLATFORM(PPC) || PLATFORM(PPC64) + return reinterpret_cast<void*>(regs.__r1); +#elif PLATFORM(ARM) + return reinterpret_cast<void*>(regs.__sp); +#else +#error Unknown Architecture +#endif + +#else // !__DARWIN_UNIX03 + +#if PLATFORM(X86) + return reinterpret_cast<void*>(regs.esp); +#elif PLATFORM(X86_64) + return reinterpret_cast<void*>(regs.rsp); +#elif (PLATFORM(PPC) || PLATFORM(PPC64)) + return reinterpret_cast<void*>(regs.r1); +#else +#error Unknown Architecture +#endif + +#endif // __DARWIN_UNIX03 + +// end PLATFORM(DARWIN) +#elif PLATFORM(X86) && PLATFORM(WIN_OS) + return reinterpret_cast<void*>((uintptr_t) regs.Esp); +#else +#error Need a way to get the stack pointer for another thread on this platform +#endif +} + +void Heap::markOtherThreadConservatively(Thread* thread) +{ + suspendThread(thread->platformThread); + + PlatformThreadRegisters regs; + size_t regSize = getPlatformThreadRegisters(thread->platformThread, regs); + + // mark the thread's registers + markConservatively(static_cast<void*>(®s), static_cast<void*>(reinterpret_cast<char*>(®s) + regSize)); + + void* stackPointer = otherThreadStackPointer(regs); + markConservatively(stackPointer, thread->stackBase); + + resumeThread(thread->platformThread); +} + +#endif + +void Heap::markStackObjectsConservatively() +{ + markCurrentThreadConservatively(); + +#if ENABLE(JSC_MULTIPLE_THREADS) + + if (m_currentThreadRegistrar) { + + MutexLocker lock(m_registeredThreadsMutex); + +#ifndef NDEBUG + // Forbid malloc during the mark phase. Marking a thread suspends it, so + // a malloc inside mark() would risk a deadlock with a thread that had been + // suspended while holding the malloc lock. + fastMallocForbid(); +#endif + // It is safe to access the registeredThreads list, because we earlier asserted that locks are being held, + // and since this is a shared heap, they are real locks. + for (Thread* thread = m_registeredThreads; thread; thread = thread->next) { + if (!pthread_equal(thread->posixThread, pthread_self())) + markOtherThreadConservatively(thread); + } +#ifndef NDEBUG + fastMallocAllow(); +#endif + } +#endif +} + +void Heap::setGCProtectNeedsLocking() +{ + // Most clients do not need to call this, with the notable exception of WebCore. + // Clients that use shared heap have JSLock protection, while others are supposed + // to do explicit locking. WebCore violates this contract in Database code, + // which calls gcUnprotect from a secondary thread. + if (!m_protectedValuesMutex) + m_protectedValuesMutex.set(new Mutex); +} + +void Heap::protect(JSValue k) +{ + ASSERT(k); + ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance); + + if (!k.isCell()) + return; + + if (m_protectedValuesMutex) + m_protectedValuesMutex->lock(); + + m_protectedValues.add(k.asCell()); + + if (m_protectedValuesMutex) + m_protectedValuesMutex->unlock(); +} + +void Heap::unprotect(JSValue k) +{ + ASSERT(k); + ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance); + + if (!k.isCell()) + return; + + if (m_protectedValuesMutex) + m_protectedValuesMutex->lock(); + + m_protectedValues.remove(k.asCell()); + + if (m_protectedValuesMutex) + m_protectedValuesMutex->unlock(); +} + +Heap* Heap::heap(JSValue v) +{ + if (!v.isCell()) + return 0; + return Heap::cellBlock(v.asCell())->heap; +} + +void Heap::markProtectedObjects() +{ + if (m_protectedValuesMutex) + m_protectedValuesMutex->lock(); + + ProtectCountSet::iterator end = m_protectedValues.end(); + for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) { + JSCell* val = it->first; + if (!val->marked()) + val->mark(); + } + + if (m_protectedValuesMutex) + m_protectedValuesMutex->unlock(); +} + +template <HeapType heapType> size_t Heap::sweep() +{ + typedef typename HeapConstants<heapType>::Block Block; + typedef typename HeapConstants<heapType>::Cell Cell; + + // SWEEP: delete everything with a zero refcount (garbage) and unmark everything else + CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap; + + size_t emptyBlocks = 0; + size_t numLiveObjects = heap.numLiveObjects; + + for (size_t block = 0; block < heap.usedBlocks; block++) { + Block* curBlock = reinterpret_cast<Block*>(heap.blocks[block]); + + size_t usedCells = curBlock->usedCells; + Cell* freeList = curBlock->freeList; + + if (usedCells == HeapConstants<heapType>::cellsPerBlock) { + // special case with a block where all cells are used -- testing indicates this happens often + for (size_t i = 0; i < HeapConstants<heapType>::cellsPerBlock; i++) { + if (!curBlock->marked.get(i >> HeapConstants<heapType>::bitmapShift)) { + Cell* cell = curBlock->cells + i; + + if (heapType != NumberHeap) { + JSCell* imp = reinterpret_cast<JSCell*>(cell); + // special case for allocated but uninitialized object + // (We don't need this check earlier because nothing prior this point + // assumes the object has a valid vptr.) + if (cell->u.freeCell.zeroIfFree == 0) + continue; + + imp->~JSCell(); + } + + --usedCells; + --numLiveObjects; + + // put cell on the free list + cell->u.freeCell.zeroIfFree = 0; + cell->u.freeCell.next = freeList - (cell + 1); + freeList = cell; + } + } + } else { + size_t minimumCellsToProcess = usedCells; + for (size_t i = 0; (i < minimumCellsToProcess) & (i < HeapConstants<heapType>::cellsPerBlock); i++) { + Cell* cell = curBlock->cells + i; + if (cell->u.freeCell.zeroIfFree == 0) { + ++minimumCellsToProcess; + } else { + if (!curBlock->marked.get(i >> HeapConstants<heapType>::bitmapShift)) { + if (heapType != NumberHeap) { + JSCell* imp = reinterpret_cast<JSCell*>(cell); + imp->~JSCell(); + } + --usedCells; + --numLiveObjects; + + // put cell on the free list + cell->u.freeCell.zeroIfFree = 0; + cell->u.freeCell.next = freeList - (cell + 1); + freeList = cell; + } + } + } + } + + curBlock->usedCells = static_cast<uint32_t>(usedCells); + curBlock->freeList = freeList; + curBlock->marked.clearAll(); + + if (usedCells == 0) { + emptyBlocks++; + if (emptyBlocks > SPARE_EMPTY_BLOCKS) { +#if !DEBUG_COLLECTOR + freeBlock(reinterpret_cast<CollectorBlock*>(curBlock)); +#endif + // swap with the last block so we compact as we go + heap.blocks[block] = heap.blocks[heap.usedBlocks - 1]; + heap.usedBlocks--; + block--; // Don't move forward a step in this case + + if (heap.numBlocks > MIN_ARRAY_SIZE && heap.usedBlocks < heap.numBlocks / LOW_WATER_FACTOR) { + heap.numBlocks = heap.numBlocks / GROWTH_FACTOR; + heap.blocks = static_cast<CollectorBlock**>(fastRealloc(heap.blocks, heap.numBlocks * sizeof(CollectorBlock*))); + } + } + } + } + + if (heap.numLiveObjects != numLiveObjects) + heap.firstBlockWithPossibleSpace = 0; + + heap.numLiveObjects = numLiveObjects; + heap.numLiveObjectsAtLastCollect = numLiveObjects; + heap.extraCost = 0; + return numLiveObjects; +} + +bool Heap::collect() +{ +#ifndef NDEBUG + if (m_globalData->isSharedInstance) { + ASSERT(JSLock::lockCount() > 0); + ASSERT(JSLock::currentThreadIsHoldingLock()); + } +#endif + + ASSERT((primaryHeap.operationInProgress == NoOperation) | (numberHeap.operationInProgress == NoOperation)); + if ((primaryHeap.operationInProgress != NoOperation) | (numberHeap.operationInProgress != NoOperation)) + CRASH(); + + JAVASCRIPTCORE_GC_BEGIN(); + primaryHeap.operationInProgress = Collection; + numberHeap.operationInProgress = Collection; + + // MARK: first mark all referenced objects recursively starting out from the set of root objects + + markStackObjectsConservatively(); + markProtectedObjects(); +#if QT_BUILD_SCRIPT_LIB + if (m_globalData->clientData) + m_globalData->clientData->mark(); +#endif + if (m_markListSet && m_markListSet->size()) + MarkedArgumentBuffer::markLists(*m_markListSet); + if (m_globalData->exception && !m_globalData->exception.marked()) + m_globalData->exception.mark(); + m_globalData->interpreter->registerFile().markCallFrames(this); + m_globalData->smallStrings.mark(); + if (m_globalData->scopeNodeBeingReparsed) + m_globalData->scopeNodeBeingReparsed->mark(); + if (m_globalData->firstStringifierToMark) + JSONObject::markStringifiers(m_globalData->firstStringifierToMark); + + JAVASCRIPTCORE_GC_MARKED(); + + size_t originalLiveObjects = primaryHeap.numLiveObjects + numberHeap.numLiveObjects; + size_t numLiveObjects = sweep<PrimaryHeap>(); + numLiveObjects += sweep<NumberHeap>(); + + primaryHeap.operationInProgress = NoOperation; + numberHeap.operationInProgress = NoOperation; + JAVASCRIPTCORE_GC_END(originalLiveObjects, numLiveObjects); + + return numLiveObjects < originalLiveObjects; +} + +size_t Heap::objectCount() +{ + return primaryHeap.numLiveObjects + numberHeap.numLiveObjects - m_globalData->smallStrings.count(); +} + +template <HeapType heapType> +static void addToStatistics(Heap::Statistics& statistics, const CollectorHeap& heap) +{ + typedef HeapConstants<heapType> HC; + for (size_t i = 0; i < heap.usedBlocks; ++i) { + if (heap.blocks[i]) { + statistics.size += BLOCK_SIZE; + statistics.free += (HC::cellsPerBlock - heap.blocks[i]->usedCells) * HC::cellSize; + } + } +} + +Heap::Statistics Heap::statistics() const +{ + Statistics statistics = { 0, 0 }; + JSC::addToStatistics<PrimaryHeap>(statistics, primaryHeap); + JSC::addToStatistics<NumberHeap>(statistics, numberHeap); + return statistics; +} + +size_t Heap::globalObjectCount() +{ + size_t count = 0; + if (JSGlobalObject* head = m_globalData->head) { + JSGlobalObject* o = head; + do { + ++count; + o = o->next(); + } while (o != head); + } + return count; +} + +size_t Heap::protectedGlobalObjectCount() +{ + if (m_protectedValuesMutex) + m_protectedValuesMutex->lock(); + + size_t count = 0; + if (JSGlobalObject* head = m_globalData->head) { + JSGlobalObject* o = head; + do { + if (m_protectedValues.contains(o)) + ++count; + o = o->next(); + } while (o != head); + } + + if (m_protectedValuesMutex) + m_protectedValuesMutex->unlock(); + + return count; +} + +size_t Heap::protectedObjectCount() +{ + if (m_protectedValuesMutex) + m_protectedValuesMutex->lock(); + + size_t result = m_protectedValues.size(); + + if (m_protectedValuesMutex) + m_protectedValuesMutex->unlock(); + + return result; +} + +static const char* typeName(JSCell* cell) +{ + if (cell->isString()) + return "string"; + if (cell->isNumber()) + return "number"; + if (cell->isGetterSetter()) + return "gettersetter"; + ASSERT(cell->isObject()); + const ClassInfo* info = static_cast<JSObject*>(cell)->classInfo(); + return info ? info->className : "Object"; +} + +HashCountedSet<const char*>* Heap::protectedObjectTypeCounts() +{ + HashCountedSet<const char*>* counts = new HashCountedSet<const char*>; + + if (m_protectedValuesMutex) + m_protectedValuesMutex->lock(); + + ProtectCountSet::iterator end = m_protectedValues.end(); + for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) + counts->add(typeName(it->first)); + + if (m_protectedValuesMutex) + m_protectedValuesMutex->unlock(); + + return counts; +} + +bool Heap::isBusy() +{ + return (primaryHeap.operationInProgress != NoOperation) | (numberHeap.operationInProgress != NoOperation); +} + +Heap::iterator Heap::primaryHeapBegin() +{ + return iterator(primaryHeap.blocks, primaryHeap.blocks + primaryHeap.usedBlocks); +} + +Heap::iterator Heap::primaryHeapEnd() +{ + return iterator(primaryHeap.blocks + primaryHeap.usedBlocks, primaryHeap.blocks + primaryHeap.usedBlocks); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.h new file mode 100644 index 0000000..852ac59 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.h @@ -0,0 +1,287 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef Collector_h +#define Collector_h + +#include <stddef.h> +#include <string.h> +#include <wtf/HashCountedSet.h> +#include <wtf/HashSet.h> +#include <wtf/Noncopyable.h> +#include <wtf/OwnPtr.h> +#include <wtf/Threading.h> + +// This is supremely lame that we require pthreads to build on windows. +#if ENABLE(JSC_MULTIPLE_THREADS) +#include <pthread.h> +#endif + +#define ASSERT_CLASS_FITS_IN_CELL(class) COMPILE_ASSERT(sizeof(class) <= CELL_SIZE, class_fits_in_cell) + +namespace JSC { + + class MarkedArgumentBuffer; + class CollectorBlock; + class JSCell; + class JSGlobalData; + class JSValue; + + enum OperationInProgress { NoOperation, Allocation, Collection }; + enum HeapType { PrimaryHeap, NumberHeap }; + + template <HeapType> class CollectorHeapIterator; + + struct CollectorHeap { + CollectorBlock** blocks; + size_t numBlocks; + size_t usedBlocks; + size_t firstBlockWithPossibleSpace; + + size_t numLiveObjects; + size_t numLiveObjectsAtLastCollect; + size_t extraCost; + + OperationInProgress operationInProgress; + }; + + class Heap : public Noncopyable { + public: + class Thread; + typedef CollectorHeapIterator<PrimaryHeap> iterator; + + void destroy(); + +#ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE + // We can inline these functions because everything is compiled as + // one file, so the heapAllocate template definitions are available. + // However, allocateNumber is used via jsNumberCell outside JavaScriptCore. + // Thus allocateNumber needs to provide a non-inline version too. + void* inlineAllocateNumber(size_t s) { return heapAllocate<NumberHeap>(s); } + void* inlineAllocate(size_t s) { return heapAllocate<PrimaryHeap>(s); } +#endif + void* allocateNumber(size_t); + void* allocate(size_t); + + bool collect(); + bool isBusy(); // true if an allocation or collection is in progress + + static const size_t minExtraCostSize = 256; + + void reportExtraMemoryCost(size_t cost); + + size_t objectCount(); + struct Statistics { + size_t size; + size_t free; + }; + Statistics statistics() const; + + void setGCProtectNeedsLocking(); + void protect(JSValue); + void unprotect(JSValue); + + static Heap* heap(JSValue); // 0 for immediate values + + size_t globalObjectCount(); + size_t protectedObjectCount(); + size_t protectedGlobalObjectCount(); + HashCountedSet<const char*>* protectedObjectTypeCounts(); + + void registerThread(); // Only needs to be called by clients that can use the same heap from multiple threads. + + static bool isCellMarked(const JSCell*); + static void markCell(JSCell*); + + void markConservatively(void* start, void* end); + + HashSet<MarkedArgumentBuffer*>& markListSet() { if (!m_markListSet) m_markListSet = new HashSet<MarkedArgumentBuffer*>; return *m_markListSet; } + + JSGlobalData* globalData() const { return m_globalData; } + static bool isNumber(JSCell*); + + // Iterators for the object heap. + iterator primaryHeapBegin(); + iterator primaryHeapEnd(); + + private: + template <HeapType heapType> void* heapAllocate(size_t); + template <HeapType heapType> size_t sweep(); + static CollectorBlock* cellBlock(const JSCell*); + static size_t cellOffset(const JSCell*); + + friend class JSGlobalData; + Heap(JSGlobalData*); + ~Heap(); + + void recordExtraCost(size_t); + void markProtectedObjects(); + void markCurrentThreadConservatively(); + void markCurrentThreadConservativelyInternal(); + void markOtherThreadConservatively(Thread*); + void markStackObjectsConservatively(); + + typedef HashCountedSet<JSCell*> ProtectCountSet; + + CollectorHeap primaryHeap; + CollectorHeap numberHeap; + + OwnPtr<Mutex> m_protectedValuesMutex; // Only non-null if the client explicitly requested it via setGCPrtotectNeedsLocking(). + ProtectCountSet m_protectedValues; + + HashSet<MarkedArgumentBuffer*>* m_markListSet; + +#if ENABLE(JSC_MULTIPLE_THREADS) + void makeUsableFromMultipleThreads(); + + static void unregisterThread(void*); + void unregisterThread(); + + Mutex m_registeredThreadsMutex; + Thread* m_registeredThreads; + pthread_key_t m_currentThreadRegistrar; +#endif + + JSGlobalData* m_globalData; + }; + + // tunable parameters + template<size_t bytesPerWord> struct CellSize; + + // cell size needs to be a power of two for certain optimizations in collector.cpp + template<> struct CellSize<sizeof(uint32_t)> { static const size_t m_value = 32; }; // 32-bit + template<> struct CellSize<sizeof(uint64_t)> { static const size_t m_value = 64; }; // 64-bit + const size_t BLOCK_SIZE = 16 * 4096; // 64k + + // derived constants + const size_t BLOCK_OFFSET_MASK = BLOCK_SIZE - 1; + const size_t BLOCK_MASK = ~BLOCK_OFFSET_MASK; + const size_t MINIMUM_CELL_SIZE = CellSize<sizeof(void*)>::m_value; + const size_t CELL_ARRAY_LENGTH = (MINIMUM_CELL_SIZE / sizeof(double)) + (MINIMUM_CELL_SIZE % sizeof(double) != 0 ? sizeof(double) : 0); + const size_t CELL_SIZE = CELL_ARRAY_LENGTH * sizeof(double); + const size_t SMALL_CELL_SIZE = CELL_SIZE / 2; + const size_t CELL_MASK = CELL_SIZE - 1; + const size_t CELL_ALIGN_MASK = ~CELL_MASK; + const size_t CELLS_PER_BLOCK = (BLOCK_SIZE * 8 - sizeof(uint32_t) * 8 - sizeof(void *) * 8 - 2 * (7 + 3 * 8)) / (CELL_SIZE * 8 + 2); + const size_t SMALL_CELLS_PER_BLOCK = 2 * CELLS_PER_BLOCK; + const size_t BITMAP_SIZE = (CELLS_PER_BLOCK + 7) / 8; + const size_t BITMAP_WORDS = (BITMAP_SIZE + 3) / sizeof(uint32_t); + + struct CollectorBitmap { + uint32_t bits[BITMAP_WORDS]; + bool get(size_t n) const { return !!(bits[n >> 5] & (1 << (n & 0x1F))); } + void set(size_t n) { bits[n >> 5] |= (1 << (n & 0x1F)); } + void clear(size_t n) { bits[n >> 5] &= ~(1 << (n & 0x1F)); } + void clearAll() { memset(bits, 0, sizeof(bits)); } + }; + + struct CollectorCell { + union { + double memory[CELL_ARRAY_LENGTH]; + struct { + void* zeroIfFree; + ptrdiff_t next; + } freeCell; + } u; + }; + + struct SmallCollectorCell { + union { + double memory[CELL_ARRAY_LENGTH / 2]; + struct { + void* zeroIfFree; + ptrdiff_t next; + } freeCell; + } u; + }; + + class CollectorBlock { + public: + CollectorCell cells[CELLS_PER_BLOCK]; + uint32_t usedCells; + CollectorCell* freeList; + CollectorBitmap marked; + Heap* heap; + HeapType type; + }; + + class SmallCellCollectorBlock { + public: + SmallCollectorCell cells[SMALL_CELLS_PER_BLOCK]; + uint32_t usedCells; + SmallCollectorCell* freeList; + CollectorBitmap marked; + Heap* heap; + HeapType type; + }; + + template <HeapType heapType> struct HeapConstants; + + template <> struct HeapConstants<PrimaryHeap> { + static const size_t cellSize = CELL_SIZE; + static const size_t cellsPerBlock = CELLS_PER_BLOCK; + static const size_t bitmapShift = 0; + typedef CollectorCell Cell; + typedef CollectorBlock Block; + }; + + template <> struct HeapConstants<NumberHeap> { + static const size_t cellSize = SMALL_CELL_SIZE; + static const size_t cellsPerBlock = SMALL_CELLS_PER_BLOCK; + static const size_t bitmapShift = 1; + typedef SmallCollectorCell Cell; + typedef SmallCellCollectorBlock Block; + }; + + inline CollectorBlock* Heap::cellBlock(const JSCell* cell) + { + return reinterpret_cast<CollectorBlock*>(reinterpret_cast<uintptr_t>(cell) & BLOCK_MASK); + } + + inline bool Heap::isNumber(JSCell* cell) + { + return Heap::cellBlock(cell)->type == NumberHeap; + } + + inline size_t Heap::cellOffset(const JSCell* cell) + { + return (reinterpret_cast<uintptr_t>(cell) & BLOCK_OFFSET_MASK) / CELL_SIZE; + } + + inline bool Heap::isCellMarked(const JSCell* cell) + { + return cellBlock(cell)->marked.get(cellOffset(cell)); + } + + inline void Heap::markCell(JSCell* cell) + { + cellBlock(cell)->marked.set(cellOffset(cell)); + } + + inline void Heap::reportExtraMemoryCost(size_t cost) + { + if (cost > minExtraCostSize) + recordExtraCost(cost / (CELL_SIZE * 2)); + } + +} // namespace JSC + +#endif /* Collector_h */ diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CollectorHeapIterator.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CollectorHeapIterator.h new file mode 100644 index 0000000..e38a852 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CollectorHeapIterator.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. + */ + +#include "config.h" +#include "Collector.h" + +#ifndef CollectorHeapIterator_h +#define CollectorHeapIterator_h + +namespace JSC { + + template <HeapType heapType> class CollectorHeapIterator { + public: + CollectorHeapIterator(CollectorBlock** block, CollectorBlock** endBlock); + + bool operator!=(const CollectorHeapIterator<heapType>& other) { return m_block != other.m_block || m_cell != other.m_cell; } + CollectorHeapIterator<heapType>& operator++(); + JSCell* operator*() const; + + private: + typedef typename HeapConstants<heapType>::Block Block; + typedef typename HeapConstants<heapType>::Cell Cell; + + Block** m_block; + Block** m_endBlock; + Cell* m_cell; + Cell* m_endCell; + }; + + template <HeapType heapType> + CollectorHeapIterator<heapType>::CollectorHeapIterator(CollectorBlock** block, CollectorBlock** endBlock) + : m_block(reinterpret_cast<Block**>(block)) + , m_endBlock(reinterpret_cast<Block**>(endBlock)) + , m_cell(m_block == m_endBlock ? 0 : (*m_block)->cells) + , m_endCell(m_block == m_endBlock ? 0 : (*m_block)->cells + HeapConstants<heapType>::cellsPerBlock) + { + if (m_cell && m_cell->u.freeCell.zeroIfFree == 0) + ++*this; + } + + template <HeapType heapType> + CollectorHeapIterator<heapType>& CollectorHeapIterator<heapType>::operator++() + { + do { + for (++m_cell; m_cell != m_endCell; ++m_cell) + if (m_cell->u.freeCell.zeroIfFree != 0) { + return *this; + } + + if (++m_block != m_endBlock) { + m_cell = (*m_block)->cells; + m_endCell = (*m_block)->cells + HeapConstants<heapType>::cellsPerBlock; + } + } while(m_block != m_endBlock); + + m_cell = 0; + return *this; + } + + template <HeapType heapType> + JSCell* CollectorHeapIterator<heapType>::operator*() const + { + return reinterpret_cast<JSCell*>(m_cell); + } + +} // namespace JSC + +#endif // CollectorHeapIterator_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CommonIdentifiers.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CommonIdentifiers.cpp new file mode 100644 index 0000000..3837817 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CommonIdentifiers.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2003, 2007, 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 + * 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 "CommonIdentifiers.h" + +namespace JSC { + +static const char* const nullCString = 0; + +#define INITIALIZE_PROPERTY_NAME(name) , name(globalData, #name) + +CommonIdentifiers::CommonIdentifiers(JSGlobalData* globalData) + : nullIdentifier(globalData, nullCString) + , emptyIdentifier(globalData, "") + , underscoreProto(globalData, "__proto__") + , thisIdentifier(globalData, "this") + JSC_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PROPERTY_NAME) +{ +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CommonIdentifiers.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CommonIdentifiers.h new file mode 100644 index 0000000..7b275bd --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CommonIdentifiers.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2003, 2007, 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 + * 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 CommonIdentifiers_h +#define CommonIdentifiers_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(__defineGetter__) \ + macro(__defineSetter__) \ + macro(__lookupGetter__) \ + macro(__lookupSetter__) \ + macro(apply) \ + macro(arguments) \ + macro(call) \ + macro(callee) \ + macro(caller) \ + macro(compile) \ + macro(constructor) \ + macro(eval) \ + macro(exec) \ + macro(fromCharCode) \ + macro(global) \ + macro(hasOwnProperty) \ + macro(ignoreCase) \ + macro(index) \ + macro(input) \ + macro(isPrototypeOf) \ + macro(length) \ + macro(message) \ + macro(multiline) \ + macro(name) \ + macro(now) \ + macro(parse) \ + macro(propertyIsEnumerable) \ + macro(prototype) \ + macro(source) \ + macro(test) \ + macro(toExponential) \ + macro(toFixed) \ + macro(toISOString) \ + macro(toJSON) \ + macro(toLocaleString) \ + macro(toPrecision) \ + macro(toString) \ + macro(UTC) \ + macro(valueOf) \ + macro(displayName) + +namespace JSC { + + class CommonIdentifiers : public Noncopyable { + private: + CommonIdentifiers(JSGlobalData*); + friend class JSGlobalData; + + public: + const Identifier nullIdentifier; + const Identifier emptyIdentifier; + const Identifier underscoreProto; + const Identifier thisIdentifier; + +#define JSC_IDENTIFIER_DECLARE_PROPERTY_NAME_GLOBAL(name) const Identifier name; + JSC_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(JSC_IDENTIFIER_DECLARE_PROPERTY_NAME_GLOBAL) +#undef JSC_IDENTIFIER_DECLARE_PROPERTY_NAME_GLOBAL + }; + +} // namespace JSC + +#endif // CommonIdentifiers_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Completion.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Completion.cpp new file mode 100644 index 0000000..04c9a2e --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Completion.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003, 2007 Apple Inc. + * + * 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 "Completion.h" + +#include "CallFrame.h" +#include "JSGlobalObject.h" +#include "JSLock.h" +#include "Interpreter.h" +#include "Parser.h" +#include "Debugger.h" +#include <stdio.h> + +#ifdef QT_BUILD_SCRIPT_LIB +#include "DebuggerCallFrame.h" +#include "SourcePoolQt.h" +#endif + +#if !PLATFORM(WIN_OS) +#include <unistd.h> +#endif + +namespace JSC { + +Completion checkSyntax(ExecState* exec, const SourceCode& source) +{ + JSLock lock(exec); + + int errLine; + UString errMsg; + + RefPtr<ProgramNode> progNode = exec->globalData().parser->parse<ProgramNode>(exec, exec->dynamicGlobalObject()->debugger(), source, &errLine, &errMsg); + if (!progNode) + return Completion(Throw, Error::create(exec, SyntaxError, errMsg, errLine, source.provider()->asID(), source.provider()->url())); + return Completion(Normal); +} + +Completion evaluate(ExecState* exec, ScopeChain& scopeChain, const SourceCode& source, JSValue thisValue) +{ + JSLock lock(exec); + + intptr_t sourceId = source.provider()->asID(); + int errLine; + UString errMsg; + RefPtr<ProgramNode> programNode = exec->globalData().parser->parse<ProgramNode>(exec, exec->dynamicGlobalObject()->debugger(), source, &errLine, &errMsg); + + if (!programNode) { + JSValue error = Error::create(exec, SyntaxError, errMsg, errLine, sourceId, source.provider()->url()); + return Completion(Throw, error); + } + + JSObject* thisObj = (!thisValue || thisValue.isUndefinedOrNull()) ? exec->dynamicGlobalObject() : thisValue.toObject(exec); + + JSValue exception; + JSValue result = exec->interpreter()->execute(programNode.get(), exec, scopeChain.node(), thisObj, &exception); + + if (exception) { + if (exception.isObject() && asObject(exception)->isWatchdogException()) + return Completion(Interrupted, exception); + return Completion(Throw, exception); + } + + return Completion(Normal, result); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Completion.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Completion.h new file mode 100644 index 0000000..41c9a64 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Completion.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003, 2007 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef Completion_h +#define Completion_h + +#include "JSValue.h" + +namespace JSC { + + class ExecState; + class ScopeChain; + class SourceCode; + + enum ComplType { Normal, Break, Continue, ReturnValue, Throw, Interrupted }; + + /* + * Completion objects are used to convey the return status and value + * from functions. + */ + class Completion { + public: + Completion(ComplType type = Normal, JSValue value = JSValue()) + : m_type(type) + , m_value(value) + { + } + + ComplType complType() const { return m_type; } + JSValue value() const { return m_value; } + void setValue(JSValue v) { m_value = v; } + bool isValueCompletion() const { return m_value; } + + private: + ComplType m_type; + JSValue m_value; + }; + + Completion checkSyntax(ExecState*, const SourceCode&); + Completion evaluate(ExecState*, ScopeChain&, const SourceCode&, JSValue thisValue = JSValue()); + +} // namespace JSC + +#endif // Completion_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ConstructData.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ConstructData.cpp new file mode 100644 index 0000000..3dfc918 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ConstructData.cpp @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#include "config.h" +#include "ConstructData.h" + +#include "JSFunction.h" + + +#ifdef QT_BUILD_SCRIPT_LIB +#include "Debugger.h" +#include "DebuggerCallFrame.h" +#include "JSGlobalObject.h" +#endif + +namespace JSC { + +#ifdef QT_BUILD_SCRIPT_LIB +JSObject* JSC::NativeConstrWrapper::operator() (ExecState* exec, JSObject* jsobj, const ArgList& argList) const +{ + Debugger* debugger = exec->lexicalGlobalObject()->debugger(); + if (debugger) + debugger->callEvent(DebuggerCallFrame(exec), -1, -1); + + JSObject* returnValue = ptr(exec, jsobj, argList); + + if ((debugger) && (callDebuggerFunctionExit)) + debugger->functionExit(JSValue(returnValue), -1); + + return returnValue; +} +#endif + +JSObject* construct(ExecState* exec, JSValue callee, ConstructType constructType, const ConstructData& constructData, const ArgList& args) +{ + if (constructType == ConstructTypeHost) + return constructData.native.function(exec, asObject(callee), args); + ASSERT(constructType == ConstructTypeJS); + // FIXME: Can this be done more efficiently using the constructData? + return asFunction(callee)->construct(exec, args); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ConstructData.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ConstructData.h new file mode 100644 index 0000000..477399c --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ConstructData.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ConstructData_h +#define ConstructData_h + +namespace JSC { + + class ArgList; + class ExecState; + class FunctionBodyNode; + class JSObject; + class JSValue; + class ScopeChainNode; + + enum ConstructType { + ConstructTypeNone, + ConstructTypeHost, + ConstructTypeJS + }; + + typedef JSObject* (*NativeConstructor)(ExecState*, JSObject*, const ArgList&); + +#ifdef QT_BUILD_SCRIPT_LIB + class NativeConstrWrapper + { + NativeConstructor ptr; + //Hack. If this variable is true and if debugger is attached at the end of + //operator() execution functionExit event will be created (in most cases it will be default) + //This variable was created because of FunctionWrapper::proxyCall method that change result + //on fly. Event shuld be created with original value so the method should call it itself. + bool callDebuggerFunctionExit; + public: + inline NativeConstrWrapper& operator=(NativeConstructor func) + { + callDebuggerFunctionExit = true; + ptr = func; + return *this; + } + inline operator NativeConstructor() const {return ptr;} + inline operator bool() const {return ptr;} + + inline void doNotCallDebuggerFunctionExit() {callDebuggerFunctionExit = false;} + JSObject* operator()(ExecState*, JSObject*, const ArgList&) const; + }; +#endif + +#if defined(QT_BUILD_SCRIPT_LIB) && PLATFORM(SOLARIS) + struct +#else + union +#endif + ConstructData { + struct { +#ifndef QT_BUILD_SCRIPT_LIB + NativeConstructor function; +#else + NativeConstrWrapper function; +#endif + } native; + struct { + FunctionBodyNode* functionBody; + ScopeChainNode* scopeChain; + } js; + }; + + JSObject* construct(ExecState*, JSValue constructor, ConstructType, const ConstructData&, const ArgList&); + +} // namespace JSC + +#endif // ConstructData_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConstructor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConstructor.cpp new file mode 100644 index 0000000..6d7d934 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConstructor.cpp @@ -0,0 +1,183 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + */ + +#include "config.h" +#include "DateConstructor.h" + +#include "DateConversion.h" +#include "DateInstance.h" +#include "DatePrototype.h" +#include "JSFunction.h" +#include "JSGlobalObject.h" +#include "JSString.h" +#include "ObjectPrototype.h" +#include "PrototypeFunction.h" +#include <math.h> +#include <time.h> +#include <wtf/DateMath.h> +#include <wtf/MathExtras.h> + +#if PLATFORM(WINCE) && !PLATFORM(QT) +extern "C" time_t time(time_t* timer); //provided by libce +#endif + +#if HAVE(SYS_TIME_H) +#include <sys/time.h> +#endif + +#if HAVE(SYS_TIMEB_H) +#include <sys/timeb.h> +#endif + +using namespace WTF; + +namespace JSC { + +// TODO: MakeTime (15.9.11.1) etc. ? + +ASSERT_CLASS_FITS_IN_CELL(DateConstructor); + +static JSValue JSC_HOST_CALL dateParse(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateNow(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateUTC(ExecState*, JSObject*, JSValue, const ArgList&); + +DateConstructor::DateConstructor(ExecState* exec, PassRefPtr<Structure> structure, Structure* prototypeFunctionStructure, DatePrototype* datePrototype) + : InternalFunction(&exec->globalData(), structure, Identifier(exec, datePrototype->classInfo()->className)) +{ + putDirectWithoutTransition(exec->propertyNames().prototype, datePrototype, DontEnum|DontDelete|ReadOnly); + + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().parse, dateParse), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 7, exec->propertyNames().UTC, dateUTC), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().now, dateNow), DontEnum); + + putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 7), ReadOnly | DontEnum | DontDelete); +} + +// ECMA 15.9.3 +JSObject* constructDate(ExecState* exec, const ArgList& args) +{ + int numArgs = args.size(); + + double value; + + if (numArgs == 0) // new Date() ECMA 15.9.3.3 + value = getCurrentUTCTime(); + else if (numArgs == 1) { + if (args.at(0).isObject(&DateInstance::info)) + value = asDateInstance(args.at(0))->internalNumber(); + else { + JSValue primitive = args.at(0).toPrimitive(exec); + if (primitive.isString()) + value = parseDate(primitive.getString()); + else + value = primitive.toNumber(exec); + } + } else { + if (isnan(args.at(0).toNumber(exec)) + || isnan(args.at(1).toNumber(exec)) + || (numArgs >= 3 && isnan(args.at(2).toNumber(exec))) + || (numArgs >= 4 && isnan(args.at(3).toNumber(exec))) + || (numArgs >= 5 && isnan(args.at(4).toNumber(exec))) + || (numArgs >= 6 && isnan(args.at(5).toNumber(exec))) + || (numArgs >= 7 && isnan(args.at(6).toNumber(exec)))) + value = NaN; + else { + GregorianDateTime t; + int year = args.at(0).toInt32(exec); + t.year = (year >= 0 && year <= 99) ? year : year - 1900; + t.month = args.at(1).toInt32(exec); + t.monthDay = (numArgs >= 3) ? args.at(2).toInt32(exec) : 1; + t.hour = args.at(3).toInt32(exec); + t.minute = args.at(4).toInt32(exec); + t.second = args.at(5).toInt32(exec); + t.isDST = -1; + double ms = (numArgs >= 7) ? args.at(6).toNumber(exec) : 0; + value = gregorianDateTimeToMS(t, ms, false); + } + } + + DateInstance* result = new (exec) DateInstance(exec->lexicalGlobalObject()->dateStructure()); + result->setInternalValue(jsNumber(exec, timeClip(value))); + return result; +} + +static JSObject* constructWithDateConstructor(ExecState* exec, JSObject*, const ArgList& args) +{ + return constructDate(exec, args); +} + +ConstructType DateConstructor::getConstructData(ConstructData& constructData) +{ + constructData.native.function = constructWithDateConstructor; + return ConstructTypeHost; +} + +// ECMA 15.9.2 +static JSValue JSC_HOST_CALL callDate(ExecState* exec, JSObject*, JSValue, const ArgList&) +{ + time_t localTime = time(0); + tm localTM; + getLocalTime(&localTime, &localTM); + GregorianDateTime ts(localTM); + return jsNontrivialString(exec, formatDate(ts) + " " + formatTime(ts, false)); +} + +CallType DateConstructor::getCallData(CallData& callData) +{ + callData.native.function = callDate; + return CallTypeHost; +} + +static JSValue JSC_HOST_CALL dateParse(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return jsNumber(exec, parseDate(args.at(0).toString(exec))); +} + +static JSValue JSC_HOST_CALL dateNow(ExecState* exec, JSObject*, JSValue, const ArgList&) +{ + return jsNumber(exec, getCurrentUTCTime()); +} + +static JSValue JSC_HOST_CALL dateUTC(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + int n = args.size(); + if (isnan(args.at(0).toNumber(exec)) + || isnan(args.at(1).toNumber(exec)) + || (n >= 3 && isnan(args.at(2).toNumber(exec))) + || (n >= 4 && isnan(args.at(3).toNumber(exec))) + || (n >= 5 && isnan(args.at(4).toNumber(exec))) + || (n >= 6 && isnan(args.at(5).toNumber(exec))) + || (n >= 7 && isnan(args.at(6).toNumber(exec)))) + return jsNaN(exec); + + GregorianDateTime t; + int year = args.at(0).toInt32(exec); + t.year = (year >= 0 && year <= 99) ? year : year - 1900; + t.month = args.at(1).toInt32(exec); + t.monthDay = (n >= 3) ? args.at(2).toInt32(exec) : 1; + t.hour = args.at(3).toInt32(exec); + t.minute = args.at(4).toInt32(exec); + t.second = args.at(5).toInt32(exec); + double ms = (n >= 7) ? args.at(6).toNumber(exec) : 0; + return jsNumber(exec, gregorianDateTimeToMS(t, ms, true)); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConstructor.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConstructor.h new file mode 100644 index 0000000..dcef3cc --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConstructor.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 DateConstructor_h +#define DateConstructor_h + +#include "InternalFunction.h" + +namespace JSC { + + class DatePrototype; + + class DateConstructor : public InternalFunction { + public: + DateConstructor(ExecState*, PassRefPtr<Structure>, Structure* prototypeFunctionStructure, DatePrototype*); + + private: + virtual ConstructType getConstructData(ConstructData&); + virtual CallType getCallData(CallData&); + }; + + JSObject* constructDate(ExecState*, const ArgList&); + +} // namespace JSC + +#endif // DateConstructor_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConversion.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConversion.cpp new file mode 100644 index 0000000..a725478 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConversion.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * + * Alternatively, the contents of this file may be used under the terms + * of either the Mozilla Public License Version 1.1, found at + * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public + * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html + * (the "GPL"), in which case the provisions of the MPL or the GPL are + * applicable instead of those above. If you wish to allow use of your + * version of this file only under the terms of one of those two + * licenses (the MPL or the GPL) and not to allow others to use your + * version of this file under the LGPL, indicate your decision by + * deletingthe provisions above and replace them with the notice and + * other provisions required by the MPL or the GPL, as the case may be. + * If you do not delete the provisions above, a recipient may use your + * version of this file under any of the LGPL, the MPL or the GPL. + */ + +#include "config.h" +#include "DateConversion.h" + +#include "UString.h" +#include <wtf/DateMath.h> +#include <wtf/StringExtras.h> + +using namespace WTF; + +namespace JSC { + +double parseDate(const UString &date) +{ + return parseDateFromNullTerminatedCharacters(date.UTF8String().c_str()); +} + +UString formatDate(const GregorianDateTime &t) +{ + char buffer[100]; + snprintf(buffer, sizeof(buffer), "%s %s %02d %04d", + weekdayName[(t.weekDay + 6) % 7], + monthName[t.month], t.monthDay, t.year + 1900); + return buffer; +} + +UString formatDateUTCVariant(const GregorianDateTime &t) +{ + char buffer[100]; + snprintf(buffer, sizeof(buffer), "%s, %02d %s %04d", + weekdayName[(t.weekDay + 6) % 7], + t.monthDay, monthName[t.month], t.year + 1900); + return buffer; +} + +UString formatTime(const GregorianDateTime &t, bool utc) +{ + char buffer[100]; + if (utc) { + snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT", t.hour, t.minute, t.second); + } else { + int offset = abs(gmtoffset(t)); + char timeZoneName[70]; + struct tm gtm = t; + strftime(timeZoneName, sizeof(timeZoneName), "%Z", >m); + + if (timeZoneName[0]) { + snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d (%s)", + t.hour, t.minute, t.second, + gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60, timeZoneName); + } else { + snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d", + t.hour, t.minute, t.second, + gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60); + } + } + return UString(buffer); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConversion.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConversion.h new file mode 100644 index 0000000..0d12815 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConversion.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + */ + +#ifndef DateConversion_h +#define DateConversion_h + +namespace WTF { + struct GregorianDateTime; +} + +namespace JSC { + +class UString; + +double parseDate(const UString&); +UString formatDate(const WTF::GregorianDateTime&); +UString formatDateUTCVariant(const WTF::GregorianDateTime&); +UString formatTime(const WTF::GregorianDateTime&, bool inputIsUTC); + +} // namespace JSC + +#endif // DateConversion_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateInstance.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateInstance.cpp new file mode 100644 index 0000000..62791ae --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateInstance.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + */ + +#include "config.h" +#include "DateInstance.h" + +#include <math.h> +#include <wtf/DateMath.h> +#include <wtf/MathExtras.h> + +using namespace WTF; + +namespace JSC { + +struct DateInstance::Cache { + double m_gregorianDateTimeCachedForMS; + GregorianDateTime m_cachedGregorianDateTime; + double m_gregorianDateTimeUTCCachedForMS; + GregorianDateTime m_cachedGregorianDateTimeUTC; +}; + +const ClassInfo DateInstance::info = {"Date", 0, 0, 0}; + +DateInstance::DateInstance(PassRefPtr<Structure> structure) + : JSWrapperObject(structure) + , m_cache(0) +{ +} + +DateInstance::~DateInstance() +{ + delete m_cache; +} + +void DateInstance::msToGregorianDateTime(double milli, bool outputIsUTC, GregorianDateTime& t) const +{ + if (!m_cache) { + m_cache = new Cache; + m_cache->m_gregorianDateTimeCachedForMS = NaN; + m_cache->m_gregorianDateTimeUTCCachedForMS = NaN; + } + + if (outputIsUTC) { + if (m_cache->m_gregorianDateTimeUTCCachedForMS != milli) { + WTF::msToGregorianDateTime(milli, true, m_cache->m_cachedGregorianDateTimeUTC); + m_cache->m_gregorianDateTimeUTCCachedForMS = milli; + } + t.copyFrom(m_cache->m_cachedGregorianDateTimeUTC); + } else { + if (m_cache->m_gregorianDateTimeCachedForMS != milli) { + WTF::msToGregorianDateTime(milli, false, m_cache->m_cachedGregorianDateTime); + m_cache->m_gregorianDateTimeCachedForMS = milli; + } + t.copyFrom(m_cache->m_cachedGregorianDateTime); + } +} + +bool DateInstance::getTime(GregorianDateTime& t, int& offset) const +{ + double milli = internalNumber(); + if (isnan(milli)) + return false; + + msToGregorianDateTime(milli, false, t); + offset = gmtoffset(t); + return true; +} + +bool DateInstance::getUTCTime(GregorianDateTime& t) const +{ + double milli = internalNumber(); + if (isnan(milli)) + return false; + + msToGregorianDateTime(milli, true, t); + return true; +} + +bool DateInstance::getTime(double& milli, int& offset) const +{ + milli = internalNumber(); + if (isnan(milli)) + return false; + + GregorianDateTime t; + msToGregorianDateTime(milli, false, t); + offset = gmtoffset(t); + return true; +} + +bool DateInstance::getUTCTime(double& milli) const +{ + milli = internalNumber(); + if (isnan(milli)) + return false; + + return true; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateInstance.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateInstance.h new file mode 100644 index 0000000..3b73521 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateInstance.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 DateInstance_h +#define DateInstance_h + +#include "JSWrapperObject.h" + +namespace WTF { + struct GregorianDateTime; +} + +namespace JSC { + + class DateInstance : public JSWrapperObject { + public: + explicit DateInstance(PassRefPtr<Structure>); + virtual ~DateInstance(); + + double internalNumber() const { return internalValue().uncheckedGetNumber(); } + + bool getTime(WTF::GregorianDateTime&, int& offset) const; + bool getUTCTime(WTF::GregorianDateTime&) const; + bool getTime(double& milliseconds, int& offset) const; + bool getUTCTime(double& milliseconds) const; + + static const ClassInfo info; + + void msToGregorianDateTime(double, bool outputIsUTC, WTF::GregorianDateTime&) const; + + private: + virtual const ClassInfo* classInfo() const { return &info; } + + using JSWrapperObject::internalValue; + + struct Cache; + mutable Cache* m_cache; + }; + + 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/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DatePrototype.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DatePrototype.cpp new file mode 100644 index 0000000..e2482f4 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DatePrototype.cpp @@ -0,0 +1,1105 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Torch Mobile, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + */ + +#include "config.h" +#include "DatePrototype.h" + +#include "DateConversion.h" +#include "Error.h" +#include "JSString.h" +#include "ObjectPrototype.h" +#include "DateInstance.h" +#include <float.h> + +#if !PLATFORM(MAC) && HAVE(LANGINFO_H) +#include <langinfo.h> +#endif + +#include <limits.h> +#include <locale.h> +#include <math.h> +#include <time.h> +#include <wtf/Assertions.h> +#include <wtf/DateMath.h> +#include <wtf/MathExtras.h> +#include <wtf/StringExtras.h> +#include <wtf/UnusedParam.h> + +#if HAVE(SYS_PARAM_H) +#include <sys/param.h> +#endif + +#if HAVE(SYS_TIME_H) +#include <sys/time.h> +#endif + +#if HAVE(SYS_TIMEB_H) +#include <sys/timeb.h> +#endif + +#if PLATFORM(MAC) +#include <CoreFoundation/CoreFoundation.h> +#endif + +#if PLATFORM(WINCE) && !PLATFORM(QT) +extern "C" size_t strftime(char * const s, const size_t maxsize, const char * const format, const struct tm * const t); //provided by libce +#endif + +using namespace WTF; + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(DatePrototype); + +static JSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*, JSObject*, JSValue, const ArgList&); + +static JSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState*, JSObject*, JSValue, const ArgList&); + +} + +#include "DatePrototype.lut.h" + +namespace JSC { + +enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime }; + +#if PLATFORM(MAC) + +// FIXME: Since this is superior to the strftime-based version, why limit this to PLATFORM(MAC)? +// Instead we should consider using this whenever PLATFORM(CF) is true. + +static CFDateFormatterStyle styleFromArgString(const UString& string, CFDateFormatterStyle defaultStyle) +{ + if (string == "short") + return kCFDateFormatterShortStyle; + if (string == "medium") + return kCFDateFormatterMediumStyle; + if (string == "long") + return kCFDateFormatterLongStyle; + if (string == "full") + return kCFDateFormatterFullStyle; + return defaultStyle; +} + +static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format, const ArgList& args) +{ + CFDateFormatterStyle dateStyle = (format != LocaleTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle); + CFDateFormatterStyle timeStyle = (format != LocaleDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle); + + bool useCustomFormat = false; + UString customFormatString; + + UString arg0String = args.at(0).toString(exec); + if (arg0String == "custom" && !args.at(1).isUndefined()) { + useCustomFormat = true; + customFormatString = args.at(1).toString(exec); + } else if (format == LocaleDateAndTime && !args.at(1).isUndefined()) { + dateStyle = styleFromArgString(arg0String, dateStyle); + timeStyle = styleFromArgString(args.at(1).toString(exec), timeStyle); + } else if (format != LocaleTime && !args.at(0).isUndefined()) + dateStyle = styleFromArgString(arg0String, dateStyle); + else if (format != LocaleDate && !args.at(0).isUndefined()) + timeStyle = styleFromArgString(arg0String, timeStyle); + + CFLocaleRef locale = CFLocaleCopyCurrent(); + CFDateFormatterRef formatter = CFDateFormatterCreate(0, locale, dateStyle, timeStyle); + CFRelease(locale); + + if (useCustomFormat) { + CFStringRef customFormatCFString = CFStringCreateWithCharacters(0, customFormatString.data(), customFormatString.size()); + CFDateFormatterSetFormat(formatter, customFormatCFString); + CFRelease(customFormatCFString); + } + + CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(0, formatter, floor(timeInMilliseconds / msPerSecond) - kCFAbsoluteTimeIntervalSince1970); + + CFRelease(formatter); + + // We truncate the string returned from CFDateFormatter if it's absurdly long (> 200 characters). + // That's not great error handling, but it just won't happen so it doesn't matter. + UChar buffer[200]; + const size_t bufferLength = sizeof(buffer) / sizeof(buffer[0]); + size_t length = CFStringGetLength(string); + ASSERT(length <= bufferLength); + if (length > bufferLength) + length = bufferLength; + CFStringGetCharacters(string, CFRangeMake(0, length), buffer); + + CFRelease(string); + + return jsNontrivialString(exec, UString(buffer, length)); +} + +#else // !PLATFORM(MAC) + +static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, LocaleDateTimeFormat format) +{ +#if HAVE(LANGINFO_H) + static const nl_item formats[] = { D_T_FMT, D_FMT, T_FMT }; +#elif PLATFORM(WINCE) && !PLATFORM(QT) + // strftime() we are using does not support # + static const char* const formatStrings[] = { "%c", "%x", "%X" }; +#else + static const char* const formatStrings[] = { "%#c", "%#x", "%X" }; +#endif + + // Offset year if needed + struct tm localTM = gdt; + int year = gdt.year + 1900; + bool yearNeedsOffset = year < 1900 || year > 2038; + if (yearNeedsOffset) + localTM.tm_year = equivalentYearForDST(year) - 1900; + +#if HAVE(LANGINFO_H) + // We do not allow strftime to generate dates with 2-digits years, + // both to avoid ambiguity, and a crash in strncpy, for years that + // need offset. + char* formatString = strdup(nl_langinfo(formats[format])); + char* yPos = strchr(formatString, 'y'); + if (yPos) + *yPos = 'Y'; +#endif + + // Do the formatting + const int bufsize = 128; + char timebuffer[bufsize]; + +#if HAVE(LANGINFO_H) + size_t ret = strftime(timebuffer, bufsize, formatString, &localTM); + free(formatString); +#else + size_t ret = strftime(timebuffer, bufsize, formatStrings[format], &localTM); +#endif + + if (ret == 0) + return jsEmptyString(exec); + + // Copy original into the buffer + if (yearNeedsOffset && format != LocaleTime) { + static const int yearLen = 5; // FIXME will be a problem in the year 10,000 + char yearString[yearLen]; + + snprintf(yearString, yearLen, "%d", localTM.tm_year + 1900); + char* yearLocation = strstr(timebuffer, yearString); + snprintf(yearString, yearLen, "%d", year); + + strncpy(yearLocation, yearString, yearLen - 1); + } + + return jsNontrivialString(exec, timebuffer); +} + +static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double timeInMilliseconds, LocaleDateTimeFormat format, const ArgList&) +{ + GregorianDateTime gregorianDateTime; + const bool notUTC = false; + dateObject->msToGregorianDateTime(timeInMilliseconds, notUTC, gregorianDateTime); + return formatLocaleDate(exec, gregorianDateTime, format); +} + +#endif // !PLATFORM(MAC) + +// Converts a list of arguments sent to a Date member function into milliseconds, updating +// ms (representing milliseconds) and t (representing the rest of the date structure) appropriately. +// +// Format of member function: f([hour,] [min,] [sec,] [ms]) +static bool fillStructuresUsingTimeArgs(ExecState* exec, const ArgList& args, int maxArgs, double* ms, GregorianDateTime* t) +{ + double milliseconds = 0; + bool ok = true; + int idx = 0; + int numArgs = args.size(); + + // JS allows extra trailing arguments -- ignore them + if (numArgs > maxArgs) + numArgs = maxArgs; + + // hours + if (maxArgs >= 4 && idx < numArgs) { + t->hour = 0; + milliseconds += args.at(idx++).toInt32(exec, ok) * msPerHour; + } + + // minutes + if (maxArgs >= 3 && idx < numArgs && ok) { + t->minute = 0; + milliseconds += args.at(idx++).toInt32(exec, ok) * msPerMinute; + } + + // seconds + if (maxArgs >= 2 && idx < numArgs && ok) { + t->second = 0; + milliseconds += args.at(idx++).toInt32(exec, ok) * msPerSecond; + } + + if (!ok) + return false; + + // milliseconds + if (idx < numArgs) { + double millis = args.at(idx).toNumber(exec); + ok = isfinite(millis); + milliseconds += millis; + } else + milliseconds += *ms; + + *ms = milliseconds; + return ok; +} + +// Converts a list of arguments sent to a Date member function into years, months, and milliseconds, updating +// ms (representing milliseconds) and t (representing the rest of the date structure) appropriately. +// +// Format of member function: f([years,] [months,] [days]) +static bool fillStructuresUsingDateArgs(ExecState *exec, const ArgList& args, int maxArgs, double *ms, GregorianDateTime *t) +{ + int idx = 0; + bool ok = true; + int numArgs = args.size(); + + // JS allows extra trailing arguments -- ignore them + if (numArgs > maxArgs) + numArgs = maxArgs; + + // years + if (maxArgs >= 3 && idx < numArgs) + t->year = args.at(idx++).toInt32(exec, ok) - 1900; + + // months + if (maxArgs >= 2 && idx < numArgs && ok) + t->month = args.at(idx++).toInt32(exec, ok); + + // days + if (idx < numArgs && ok) { + t->monthDay = 0; + *ms += args.at(idx).toInt32(exec, ok) * msPerDay; + } + + return ok; +} + +const ClassInfo DatePrototype::info = {"Date", &DateInstance::info, 0, ExecState::dateTable}; + +/* Source for DatePrototype.lut.h +@begin dateTable + toString dateProtoFuncToString DontEnum|Function 0 + toISOString dateProtoFuncToISOString DontEnum|Function 0 + toUTCString dateProtoFuncToUTCString DontEnum|Function 0 + toDateString dateProtoFuncToDateString DontEnum|Function 0 + toTimeString dateProtoFuncToTimeString DontEnum|Function 0 + toLocaleString dateProtoFuncToLocaleString DontEnum|Function 0 + toLocaleDateString dateProtoFuncToLocaleDateString DontEnum|Function 0 + toLocaleTimeString dateProtoFuncToLocaleTimeString DontEnum|Function 0 + valueOf dateProtoFuncGetTime DontEnum|Function 0 + getTime dateProtoFuncGetTime DontEnum|Function 0 + getFullYear dateProtoFuncGetFullYear DontEnum|Function 0 + getUTCFullYear dateProtoFuncGetUTCFullYear DontEnum|Function 0 + toGMTString dateProtoFuncToGMTString DontEnum|Function 0 + getMonth dateProtoFuncGetMonth DontEnum|Function 0 + getUTCMonth dateProtoFuncGetUTCMonth DontEnum|Function 0 + getDate dateProtoFuncGetDate DontEnum|Function 0 + getUTCDate dateProtoFuncGetUTCDate DontEnum|Function 0 + getDay dateProtoFuncGetDay DontEnum|Function 0 + getUTCDay dateProtoFuncGetUTCDay DontEnum|Function 0 + getHours dateProtoFuncGetHours DontEnum|Function 0 + getUTCHours dateProtoFuncGetUTCHours DontEnum|Function 0 + getMinutes dateProtoFuncGetMinutes DontEnum|Function 0 + getUTCMinutes dateProtoFuncGetUTCMinutes DontEnum|Function 0 + getSeconds dateProtoFuncGetSeconds DontEnum|Function 0 + getUTCSeconds dateProtoFuncGetUTCSeconds DontEnum|Function 0 + getMilliseconds dateProtoFuncGetMilliSeconds DontEnum|Function 0 + getUTCMilliseconds dateProtoFuncGetUTCMilliseconds DontEnum|Function 0 + getTimezoneOffset dateProtoFuncGetTimezoneOffset DontEnum|Function 0 + setTime dateProtoFuncSetTime DontEnum|Function 1 + setMilliseconds dateProtoFuncSetMilliSeconds DontEnum|Function 1 + setUTCMilliseconds dateProtoFuncSetUTCMilliseconds DontEnum|Function 1 + setSeconds dateProtoFuncSetSeconds DontEnum|Function 2 + setUTCSeconds dateProtoFuncSetUTCSeconds DontEnum|Function 2 + setMinutes dateProtoFuncSetMinutes DontEnum|Function 3 + setUTCMinutes dateProtoFuncSetUTCMinutes DontEnum|Function 3 + setHours dateProtoFuncSetHours DontEnum|Function 4 + setUTCHours dateProtoFuncSetUTCHours DontEnum|Function 4 + setDate dateProtoFuncSetDate DontEnum|Function 1 + setUTCDate dateProtoFuncSetUTCDate DontEnum|Function 1 + setMonth dateProtoFuncSetMonth DontEnum|Function 2 + setUTCMonth dateProtoFuncSetUTCMonth DontEnum|Function 2 + setFullYear dateProtoFuncSetFullYear DontEnum|Function 3 + setUTCFullYear dateProtoFuncSetUTCFullYear DontEnum|Function 3 + setYear dateProtoFuncSetYear DontEnum|Function 1 + getYear dateProtoFuncGetYear DontEnum|Function 0 + toJSON dateProtoFuncToJSON DontEnum|Function 0 +@end +*/ + +// ECMA 15.9.4 + +DatePrototype::DatePrototype(ExecState* exec, PassRefPtr<Structure> structure) + : DateInstance(structure) +{ + setInternalValue(jsNaN(exec)); + // The constructor will be added later, after DateConstructor has been built. +} + +bool DatePrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +{ + return getStaticFunctionSlot<JSObject>(exec, ExecState::dateTable(exec), this, propertyName, slot); +} + +// Functions + +JSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = false; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNontrivialString(exec, "Invalid Date"); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return jsNontrivialString(exec, formatDate(t) + " " + formatTime(t, utc)); +} + +JSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = true; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNontrivialString(exec, "Invalid Date"); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return jsNontrivialString(exec, formatDateUTCVariant(t) + " " + formatTime(t, utc)); +} + +JSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = true; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (!isfinite(milli)) + return jsNontrivialString(exec, "Invalid Date"); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + // Maximum amount of space we need in buffer: 6 (max. digits in year) + 2 * 5 (2 characters each for month, day, hour, minute, second) + // 6 for formatting and one for null termination = 23. We add one extra character to allow us to force null termination. + char buffer[24]; + snprintf(buffer, sizeof(buffer) - 1, "%04d-%02d-%02dT%02d:%02d:%02dZ", 1900 + t.year, t.month + 1, t.monthDay, t.hour, t.minute, t.second); + buffer[sizeof(buffer) - 1] = 0; + return jsNontrivialString(exec, buffer); +} + +JSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = false; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNontrivialString(exec, "Invalid Date"); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return jsNontrivialString(exec, formatDate(t)); +} + +JSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = false; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNontrivialString(exec, "Invalid Date"); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return jsNontrivialString(exec, formatTime(t, utc)); +} + +JSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNontrivialString(exec, "Invalid Date"); + + return formatLocaleDate(exec, thisDateObj, milli, LocaleDateAndTime, args); +} + +JSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNontrivialString(exec, "Invalid Date"); + + return formatLocaleDate(exec, thisDateObj, milli, LocaleDate, args); +} + +JSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNontrivialString(exec, "Invalid Date"); + + return formatLocaleDate(exec, thisDateObj, milli, LocaleTime, args); +} + +JSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNaN(exec); + + return jsNumber(exec, milli); +} + +JSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = false; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNaN(exec); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return jsNumber(exec, 1900 + t.year); +} + +JSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = true; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNaN(exec); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return jsNumber(exec, 1900 + t.year); +} + +JSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = true; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNontrivialString(exec, "Invalid Date"); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return jsNontrivialString(exec, formatDateUTCVariant(t) + " " + formatTime(t, utc)); +} + +JSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = false; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNaN(exec); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return jsNumber(exec, t.month); +} + +JSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = true; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNaN(exec); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return jsNumber(exec, t.month); +} + +JSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = false; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNaN(exec); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return jsNumber(exec, t.monthDay); +} + +JSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = true; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNaN(exec); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return jsNumber(exec, t.monthDay); +} + +JSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = false; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNaN(exec); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return jsNumber(exec, t.weekDay); +} + +JSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = true; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNaN(exec); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return jsNumber(exec, t.weekDay); +} + +JSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = false; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNaN(exec); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return jsNumber(exec, t.hour); +} + +JSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = true; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNaN(exec); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return jsNumber(exec, t.hour); +} + +JSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = false; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNaN(exec); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return jsNumber(exec, t.minute); +} + +JSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = true; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNaN(exec); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return jsNumber(exec, t.minute); +} + +JSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = false; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNaN(exec); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return jsNumber(exec, t.second); +} + +JSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = true; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNaN(exec); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return jsNumber(exec, t.second); +} + +JSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNaN(exec); + + double secs = floor(milli / msPerSecond); + double ms = milli - secs * msPerSecond; + return jsNumber(exec, ms); +} + +JSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNaN(exec); + + double secs = floor(milli / msPerSecond); + double ms = milli - secs * msPerSecond; + return jsNumber(exec, ms); +} + +JSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = false; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNaN(exec); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return jsNumber(exec, -gmtoffset(t) / minutesPerHour); +} + +JSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + DateInstance* thisDateObj = asDateInstance(thisValue); + + double milli = timeClip(args.at(0).toNumber(exec)); + JSValue result = jsNumber(exec, milli); + thisDateObj->setInternalValue(result); + return result; +} + +static JSValue setNewValueFromTimeArgs(ExecState* exec, JSValue thisValue, const ArgList& args, int numArgsToUse, bool inputIsUTC) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + + if (args.isEmpty() || isnan(milli)) { + JSValue result = jsNaN(exec); + thisDateObj->setInternalValue(result); + return result; + } + + double secs = floor(milli / msPerSecond); + double ms = milli - secs * msPerSecond; + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, inputIsUTC, t); + + if (!fillStructuresUsingTimeArgs(exec, args, numArgsToUse, &ms, &t)) { + JSValue result = jsNaN(exec); + thisDateObj->setInternalValue(result); + return result; + } + + JSValue result = jsNumber(exec, gregorianDateTimeToMS(t, ms, inputIsUTC)); + thisDateObj->setInternalValue(result); + return result; +} + +static JSValue setNewValueFromDateArgs(ExecState* exec, JSValue thisValue, const ArgList& args, int numArgsToUse, bool inputIsUTC) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + DateInstance* thisDateObj = asDateInstance(thisValue); + if (args.isEmpty()) { + JSValue result = jsNaN(exec); + thisDateObj->setInternalValue(result); + return result; + } + + double milli = thisDateObj->internalNumber(); + double ms = 0; + + GregorianDateTime t; + if (numArgsToUse == 3 && isnan(milli)) + // Based on ECMA 262 15.9.5.40 - .41 (set[UTC]FullYear) + // the time must be reset to +0 if it is NaN. + thisDateObj->msToGregorianDateTime(0, true, t); + else { + double secs = floor(milli / msPerSecond); + ms = milli - secs * msPerSecond; + thisDateObj->msToGregorianDateTime(milli, inputIsUTC, t); + } + + if (!fillStructuresUsingDateArgs(exec, args, numArgsToUse, &ms, &t)) { + JSValue result = jsNaN(exec); + thisDateObj->setInternalValue(result); + return result; + } + + JSValue result = jsNumber(exec, gregorianDateTimeToMS(t, ms, inputIsUTC)); + thisDateObj->setInternalValue(result); + return result; +} + +JSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + const bool inputIsUTC = false; + return setNewValueFromTimeArgs(exec, thisValue, args, 1, inputIsUTC); +} + +JSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + const bool inputIsUTC = true; + return setNewValueFromTimeArgs(exec, thisValue, args, 1, inputIsUTC); +} + +JSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + const bool inputIsUTC = false; + return setNewValueFromTimeArgs(exec, thisValue, args, 2, inputIsUTC); +} + +JSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + const bool inputIsUTC = true; + return setNewValueFromTimeArgs(exec, thisValue, args, 2, inputIsUTC); +} + +JSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + const bool inputIsUTC = false; + return setNewValueFromTimeArgs(exec, thisValue, args, 3, inputIsUTC); +} + +JSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + const bool inputIsUTC = true; + return setNewValueFromTimeArgs(exec, thisValue, args, 3, inputIsUTC); +} + +JSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + const bool inputIsUTC = false; + return setNewValueFromTimeArgs(exec, thisValue, args, 4, inputIsUTC); +} + +JSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + const bool inputIsUTC = true; + return setNewValueFromTimeArgs(exec, thisValue, args, 4, inputIsUTC); +} + +JSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + const bool inputIsUTC = false; + return setNewValueFromDateArgs(exec, thisValue, args, 1, inputIsUTC); +} + +JSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + const bool inputIsUTC = true; + return setNewValueFromDateArgs(exec, thisValue, args, 1, inputIsUTC); +} + +JSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + const bool inputIsUTC = false; + return setNewValueFromDateArgs(exec, thisValue, args, 2, inputIsUTC); +} + +JSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + const bool inputIsUTC = true; + return setNewValueFromDateArgs(exec, thisValue, args, 2, inputIsUTC); +} + +JSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + const bool inputIsUTC = false; + return setNewValueFromDateArgs(exec, thisValue, args, 3, inputIsUTC); +} + +JSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + const bool inputIsUTC = true; + return setNewValueFromDateArgs(exec, thisValue, args, 3, inputIsUTC); +} + +JSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = false; + + DateInstance* thisDateObj = asDateInstance(thisValue); + if (args.isEmpty()) { + JSValue result = jsNaN(exec); + thisDateObj->setInternalValue(result); + return result; + } + + double milli = thisDateObj->internalNumber(); + double ms = 0; + + GregorianDateTime t; + if (isnan(milli)) + // Based on ECMA 262 B.2.5 (setYear) + // the time must be reset to +0 if it is NaN. + thisDateObj->msToGregorianDateTime(0, true, t); + else { + double secs = floor(milli / msPerSecond); + ms = milli - secs * msPerSecond; + thisDateObj->msToGregorianDateTime(milli, utc, t); + } + + bool ok = true; + int32_t year = args.at(0).toInt32(exec, ok); + if (!ok) { + JSValue result = jsNaN(exec); + thisDateObj->setInternalValue(result); + return result; + } + + t.year = (year > 99 || year < 0) ? year - 1900 : year; + JSValue result = jsNumber(exec, gregorianDateTimeToMS(t, ms, utc)); + thisDateObj->setInternalValue(result); + return result; +} + +JSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = false; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (isnan(milli)) + return jsNaN(exec); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + + // NOTE: IE returns the full year even in getYear. + return jsNumber(exec, t.year); +} + +JSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + JSObject* object = thisValue.toThisObject(exec); + if (exec->hadException()) + return jsNull(); + + JSValue toISOValue = object->get(exec, exec->globalData().propertyNames->toISOString); + if (exec->hadException()) + return jsNull(); + + CallData callData; + CallType callType = toISOValue.getCallData(callData); + if (callType == CallTypeNone) + return throwError(exec, TypeError, "toISOString is not a function"); + + JSValue result = call(exec, asObject(toISOValue), callType, callData, object, exec->emptyList()); + if (exec->hadException()) + return jsNull(); + if (result.isObject()) + return throwError(exec, TypeError, "toISOString did not return a primitive value"); + return result; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DatePrototype.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DatePrototype.h new file mode 100644 index 0000000..5f4d0ec --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DatePrototype.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 DatePrototype_h +#define DatePrototype_h + +#include "DateInstance.h" + +namespace JSC { + + class ObjectPrototype; + + class DatePrototype : public DateInstance { + public: + DatePrototype(ExecState*, PassRefPtr<Structure>); + + virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType)); + } + }; + +} // namespace JSC + +#endif // DatePrototype_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Error.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Error.cpp new file mode 100644 index 0000000..1aa9034 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Error.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003, 2004, 2005, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007 Eric Seidel (eric@webkit.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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 "Error.h" + +#include "ConstructData.h" +#include "ErrorConstructor.h" +#include "JSFunction.h" +#include "JSGlobalObject.h" +#include "JSObject.h" +#include "JSString.h" +#include "NativeErrorConstructor.h" + +namespace JSC { + +const char* expressionBeginOffsetPropertyName = "expressionBeginOffset"; +const char* expressionCaretOffsetPropertyName = "expressionCaretOffset"; +const char* expressionEndOffsetPropertyName = "expressionEndOffset"; + +JSObject* Error::create(ExecState* exec, ErrorType type, const UString& message, int lineNumber, intptr_t sourceID, const UString& sourceURL) +{ + JSObject* constructor; + const char* name; + switch (type) { + case EvalError: + constructor = exec->lexicalGlobalObject()->evalErrorConstructor(); + name = "Evaluation error"; + break; + case RangeError: + constructor = exec->lexicalGlobalObject()->rangeErrorConstructor(); + name = "Range error"; + break; + case ReferenceError: + constructor = exec->lexicalGlobalObject()->referenceErrorConstructor(); + name = "Reference error"; + break; + case SyntaxError: + constructor = exec->lexicalGlobalObject()->syntaxErrorConstructor(); + name = "Syntax error"; + break; + case TypeError: + constructor = exec->lexicalGlobalObject()->typeErrorConstructor(); + name = "Type error"; + break; + case URIError: + constructor = exec->lexicalGlobalObject()->URIErrorConstructor(); + name = "URI error"; + break; + default: + constructor = exec->lexicalGlobalObject()->errorConstructor(); + name = "Error"; + break; + } + + MarkedArgumentBuffer args; + if (message.isEmpty()) + args.append(jsString(exec, name)); + else + args.append(jsString(exec, message)); + ConstructData constructData; + ConstructType constructType = constructor->getConstructData(constructData); + JSObject* error = construct(exec, constructor, constructType, constructData, args); + + if (lineNumber != -1) + error->putWithAttributes(exec, Identifier(exec, JSC_ERROR_LINENUMBER_PROPERTYNAME), jsNumber(exec, lineNumber), ReadOnly | DontDelete); + if (sourceID != -1) + error->putWithAttributes(exec, Identifier(exec, "sourceId"), jsNumber(exec, sourceID), ReadOnly | DontDelete); + if (!sourceURL.isNull()) + error->putWithAttributes(exec, Identifier(exec, JSC_ERROR_FILENAME_PROPERTYNAME), jsString(exec, sourceURL), ReadOnly | DontDelete); + + return error; +} + +JSObject* Error::create(ExecState* exec, ErrorType type, const char* message) +{ + return create(exec, type, message, -1, -1, NULL); +} + +JSObject* throwError(ExecState* exec, ErrorType type) +{ + JSObject* error = Error::create(exec, type, UString(), -1, -1, NULL); + exec->setException(error); + return error; +} + +JSObject* throwError(ExecState* exec, ErrorType type, const UString& message) +{ + JSObject* error = Error::create(exec, type, message, -1, -1, NULL); + exec->setException(error); + return error; +} + +JSObject* throwError(ExecState* exec, ErrorType type, const char* message) +{ + JSObject* error = Error::create(exec, type, message, -1, -1, NULL); + exec->setException(error); + return error; +} + +JSObject* throwError(ExecState* exec, ErrorType type, const UString& message, int line, intptr_t sourceID, const UString& sourceURL) +{ + JSObject* error = Error::create(exec, type, message, line, sourceID, sourceURL); + exec->setException(error); + return error; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Error.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Error.h new file mode 100644 index 0000000..fb864ee --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Error.h @@ -0,0 +1,73 @@ +/* + * 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 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef Error_h +#define Error_h + +#include <stdint.h> + +namespace JSC { + + class ExecState; + class JSObject; + class UString; + + /** + * Types of Native Errors available. For custom errors, GeneralError + * should be used. + */ + enum ErrorType { + GeneralError = 0, + EvalError = 1, + RangeError = 2, + ReferenceError = 3, + SyntaxError = 4, + TypeError = 5, + URIError = 6 + }; + + extern const char* expressionBeginOffsetPropertyName; + extern const char* expressionCaretOffsetPropertyName; + extern const char* expressionEndOffsetPropertyName; + + class Error { + public: + static JSObject* create(ExecState*, ErrorType, const UString& message, int lineNumber, intptr_t sourceID, const UString& sourceURL); + static JSObject* create(ExecState*, ErrorType, const char* message); + }; + + JSObject* throwError(ExecState*, ErrorType, const UString& message, int lineNumber, intptr_t sourceID, const UString& sourceURL); + JSObject* throwError(ExecState*, ErrorType, const UString& message); + JSObject* throwError(ExecState*, ErrorType, const char* message); + JSObject* throwError(ExecState*, ErrorType); + +#ifdef QT_BUILD_SCRIPT_LIB +# define JSC_ERROR_FILENAME_PROPERTYNAME "fileName" +# define JSC_ERROR_LINENUMBER_PROPERTYNAME "lineNumber" +#else +# define JSC_ERROR_FILENAME_PROPERTYNAME "sourceURL" +# define JSC_ERROR_LINENUMBER_PROPERTYNAME "line" +#endif + +} // namespace JSC + +#endif // Error_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorConstructor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorConstructor.cpp new file mode 100644 index 0000000..07b7e23 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorConstructor.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "ErrorConstructor.h" + +#include "ErrorPrototype.h" +#include "JSGlobalObject.h" +#include "JSString.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(ErrorConstructor); + +ErrorConstructor::ErrorConstructor(ExecState* exec, PassRefPtr<Structure> structure, ErrorPrototype* errorPrototype) + : InternalFunction(&exec->globalData(), structure, Identifier(exec, errorPrototype->classInfo()->className)) +{ + // ECMA 15.11.3.1 Error.prototype + putDirectWithoutTransition(exec->propertyNames().prototype, errorPrototype, DontEnum | DontDelete | ReadOnly); + putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 1), DontDelete | ReadOnly | DontEnum); +} + +// ECMA 15.9.3 +ErrorInstance* constructError(ExecState* exec, const ArgList& args) +{ + ErrorInstance* obj = new (exec) ErrorInstance(exec->lexicalGlobalObject()->errorStructure()); + if (!args.at(0).isUndefined()) + obj->putDirect(exec->propertyNames().message, jsString(exec, args.at(0).toString(exec))); + return obj; +} + +static JSObject* constructWithErrorConstructor(ExecState* exec, JSObject*, const ArgList& args) +{ + return constructError(exec, args); +} + +ConstructType ErrorConstructor::getConstructData(ConstructData& constructData) +{ + constructData.native.function = constructWithErrorConstructor; + return ConstructTypeHost; +} + +// ECMA 15.9.2 +static JSValue JSC_HOST_CALL callErrorConstructor(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + // "Error()" gives the sames result as "new Error()" + return constructError(exec, args); +} + +CallType ErrorConstructor::getCallData(CallData& callData) +{ + callData.native.function = callErrorConstructor; + return CallTypeHost; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorConstructor.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorConstructor.h new file mode 100644 index 0000000..2dd4124 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorConstructor.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 ErrorConstructor_h +#define ErrorConstructor_h + +#include "ErrorInstance.h" +#include "InternalFunction.h" + +namespace JSC { + + class ErrorPrototype; + + class ErrorConstructor : public InternalFunction { + public: + ErrorConstructor(ExecState*, PassRefPtr<Structure>, ErrorPrototype*); + + private: + virtual ConstructType getConstructData(ConstructData&); + virtual CallType getCallData(CallData&); + }; + + ErrorInstance* constructError(ExecState*, const ArgList&); + +} // namespace JSC + +#endif // ErrorConstructor_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorInstance.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorInstance.cpp new file mode 100644 index 0000000..2e2cdce --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorInstance.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "ErrorInstance.h" + +namespace JSC { + +const ClassInfo ErrorInstance::info = { "Error", 0, 0, 0 }; + +ErrorInstance::ErrorInstance(PassRefPtr<Structure> structure) + : JSObject(structure) +{ +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorInstance.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorInstance.h new file mode 100644 index 0000000..6f9d262 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorInstance.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 ErrorInstance_h +#define ErrorInstance_h + +#include "JSObject.h" + +namespace JSC { + + class ErrorInstance : public JSObject { + public: + explicit ErrorInstance(PassRefPtr<Structure>); + + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + }; + +} // namespace JSC + +#endif // ErrorInstance_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorPrototype.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorPrototype.cpp new file mode 100644 index 0000000..599390e --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorPrototype.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "ErrorPrototype.h" + +#include "JSFunction.h" +#include "JSString.h" +#include "ObjectPrototype.h" +#include "PrototypeFunction.h" +#include "UString.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(ErrorPrototype); + +static JSValue JSC_HOST_CALL errorProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&); + +// ECMA 15.9.4 +ErrorPrototype::ErrorPrototype(ExecState* exec, PassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) + : ErrorInstance(structure) +{ + // The constructor will be added later in ErrorConstructor's constructor + + putDirectWithoutTransition(exec->propertyNames().name, jsNontrivialString(exec, "Error"), DontEnum); + putDirectWithoutTransition(exec->propertyNames().message, jsNontrivialString(exec, "Unknown error"), DontEnum); + + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().toString, errorProtoFuncToString), DontEnum); +} + +JSValue JSC_HOST_CALL errorProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + JSObject* thisObj = thisValue.toThisObject(exec); + + UString s = "Error"; + + JSValue v = thisObj->get(exec, exec->propertyNames().name); + if (!v.isUndefined()) + s = v.toString(exec); + + v = thisObj->get(exec, exec->propertyNames().message); + if (!v.isUndefined()) { + // Mozilla-compatible format. + s += ": "; + s += v.toString(exec); + } + + return jsNontrivialString(exec, s); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorPrototype.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorPrototype.h new file mode 100644 index 0000000..53d12d9 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorPrototype.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 ErrorPrototype_h +#define ErrorPrototype_h + +#include "ErrorInstance.h" + +namespace JSC { + + class ObjectPrototype; + + class ErrorPrototype : public ErrorInstance { + public: + ErrorPrototype(ExecState*, PassRefPtr<Structure>, Structure* prototypeFunctionStructure); + }; + +} // namespace JSC + +#endif // ErrorPrototype_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ExceptionHelpers.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ExceptionHelpers.cpp new file mode 100644 index 0000000..e63594c --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ExceptionHelpers.cpp @@ -0,0 +1,211 @@ +/* + * 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 "ExceptionHelpers.h" + +#include "CodeBlock.h" +#include "CallFrame.h" +#include "JSGlobalObjectFunctions.h" +#include "JSObject.h" +#include "JSNotAnObject.h" +#include "Interpreter.h" +#include "Nodes.h" + +namespace JSC { + +class InterruptedExecutionError : public JSObject { +public: + InterruptedExecutionError(JSGlobalData* globalData) + : JSObject(globalData->interruptedExecutionErrorStructure) + { + } + + virtual bool isWatchdogException() const { return true; } + + virtual UString toString(ExecState*) const { return "JavaScript execution exceeded timeout."; } +}; + +JSValue createInterruptedExecutionException(JSGlobalData* globalData) +{ + return new (globalData) InterruptedExecutionError(globalData); +} + +static JSValue createError(ExecState* exec, ErrorType e, const char* msg) +{ + return Error::create(exec, e, msg, -1, -1, 0); +} + +JSValue createStackOverflowError(ExecState* exec) +{ + return createError(exec, RangeError, "Maximum call stack size exceeded."); +} + +JSValue createUndefinedVariableError(ExecState* exec, const Identifier& ident, unsigned bytecodeOffset, CodeBlock* codeBlock) +{ + int startOffset = 0; + int endOffset = 0; + int divotPoint = 0; + int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); + UString message = "Can't find variable: "; + message.append(ident.ustring()); + JSObject* exception = Error::create(exec, ReferenceError, message, line, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL()); + exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete); + exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete); + exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete); + return exception; +} + +static UString createErrorMessage(ExecState* exec, CodeBlock* codeBlock, int, int expressionStart, int expressionStop, JSValue value, UString error) +{ + if (!expressionStop || expressionStart > codeBlock->source()->length()) { + UString errorText = value.toString(exec); + errorText.append(" is "); + errorText.append(error); + return errorText; + } + + UString errorText = "Result of expression "; + + if (expressionStart < expressionStop) { + errorText.append('\''); + errorText.append(codeBlock->source()->getRange(expressionStart, expressionStop)); + errorText.append("' ["); + errorText.append(value.toString(exec)); + errorText.append("] is "); + } else { + // No range information, so give a few characters of context + const UChar* data = codeBlock->source()->data(); + int dataLength = codeBlock->source()->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])) + stop--; + errorText.append("near '..."); + errorText.append(codeBlock->source()->getRange(start, stop)); + errorText.append("...' ["); + errorText.append(value.toString(exec)); + errorText.append("] is "); + } + errorText.append(error); + errorText.append("."); + return errorText; +} + +JSObject* createInvalidParamError(ExecState* exec, const char* op, JSValue value, unsigned bytecodeOffset, CodeBlock* codeBlock) +{ + UString message = "not a valid argument for '"; + message.append(op); + message.append("'"); + + int startOffset = 0; + int endOffset = 0; + int divotPoint = 0; + int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); + UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint, divotPoint + endOffset, value, message); + JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL()); + exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete); + exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete); + exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete); + return exception; +} + +JSObject* createNotAConstructorError(ExecState* exec, JSValue value, unsigned bytecodeOffset, CodeBlock* codeBlock) +{ + int startOffset = 0; + int endOffset = 0; + int divotPoint = 0; + int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); + + // We're in a "new" expression, so we need to skip over the "new.." part + int startPoint = divotPoint - (startOffset ? startOffset - 4 : 0); // -4 for "new " + const UChar* data = codeBlock->source()->data(); + while (startPoint < divotPoint && isStrWhiteSpace(data[startPoint])) + startPoint++; + + UString errorMessage = createErrorMessage(exec, codeBlock, line, startPoint, divotPoint, value, "not a constructor"); + JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL()); + exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete); + exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete); + exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete); + return exception; +} + +JSValue createNotAFunctionError(ExecState* exec, JSValue value, unsigned bytecodeOffset, CodeBlock* codeBlock) +{ + int startOffset = 0; + int endOffset = 0; + int divotPoint = 0; + int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); + UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint - startOffset, divotPoint, value, "not a function"); + JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL()); + exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete); + exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete); + exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete); + return exception; +} + +JSNotAnObjectErrorStub* createNotAnObjectErrorStub(ExecState* exec, bool isNull) +{ + return new (exec) JSNotAnObjectErrorStub(exec, isNull); +} + +JSObject* createNotAnObjectError(ExecState* exec, JSNotAnObjectErrorStub* error, unsigned bytecodeOffset, CodeBlock* codeBlock) +{ + // Both op_construct and op_instanceof require a use of op_get_by_id to get + // the prototype property from an object. The exception messages for exceptions + // thrown by these instances op_get_by_id need to reflect this. + OpcodeID followingOpcodeID; + if (codeBlock->getByIdExceptionInfoForBytecodeOffset(exec, bytecodeOffset, followingOpcodeID)) { + ASSERT(followingOpcodeID == op_construct || followingOpcodeID == op_instanceof); + if (followingOpcodeID == op_construct) + return createNotAConstructorError(exec, error->isNull() ? jsNull() : jsUndefined(), bytecodeOffset, codeBlock); + return createInvalidParamError(exec, "instanceof", error->isNull() ? jsNull() : jsUndefined(), bytecodeOffset, codeBlock); + } + + int startOffset = 0; + int endOffset = 0; + int divotPoint = 0; + int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); + UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint - startOffset, divotPoint, error->isNull() ? jsNull() : jsUndefined(), "not an object"); + JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL()); + exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete); + exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete); + exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete); + return exception; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ExceptionHelpers.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ExceptionHelpers.h new file mode 100644 index 0000000..09d99dc --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ExceptionHelpers.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ExceptionHelpers_h +#define ExceptionHelpers_h + +#include "JSImmediate.h" + +namespace JSC { + + class CodeBlock; + class ExecState; + class Identifier; + class Instruction; + class JSGlobalData; + class JSNotAnObjectErrorStub; + class JSObject; + class JSValue; + class Node; + + JSValue createInterruptedExecutionException(JSGlobalData*); + JSValue createStackOverflowError(ExecState*); + JSValue createUndefinedVariableError(ExecState*, const Identifier&, unsigned bytecodeOffset, CodeBlock*); + JSNotAnObjectErrorStub* createNotAnObjectErrorStub(ExecState*, bool isNull); + JSObject* createInvalidParamError(ExecState*, const char* op, JSValue, unsigned bytecodeOffset, CodeBlock*); + JSObject* createNotAConstructorError(ExecState*, JSValue, unsigned bytecodeOffset, CodeBlock*); + JSValue createNotAFunctionError(ExecState*, JSValue, unsigned bytecodeOffset, CodeBlock*); + JSObject* createNotAnObjectError(ExecState*, JSNotAnObjectErrorStub*, unsigned bytecodeOffset, CodeBlock*); + +} // namespace JSC + +#endif // ExceptionHelpers_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionConstructor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionConstructor.cpp new file mode 100644 index 0000000..f4f5cc8 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionConstructor.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "FunctionConstructor.h" + +#include "FunctionPrototype.h" +#include "JSFunction.h" +#include "JSGlobalObject.h" +#include "JSString.h" +#include "Parser.h" +#include "Debugger.h" +#include "Lexer.h" +#include "Nodes.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(FunctionConstructor); + +FunctionConstructor::FunctionConstructor(ExecState* exec, PassRefPtr<Structure> structure, FunctionPrototype* functionPrototype) + : InternalFunction(&exec->globalData(), structure, Identifier(exec, functionPrototype->classInfo()->className)) +{ + putDirectWithoutTransition(exec->propertyNames().prototype, functionPrototype, DontEnum | DontDelete | ReadOnly); + + // Number of arguments for constructor + putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 1), ReadOnly | DontDelete | DontEnum); +} + +static JSObject* constructWithFunctionConstructor(ExecState* exec, JSObject*, const ArgList& args) +{ + return constructFunction(exec, args); +} + +ConstructType FunctionConstructor::getConstructData(ConstructData& constructData) +{ + constructData.native.function = constructWithFunctionConstructor; + return ConstructTypeHost; +} + +static JSValue JSC_HOST_CALL callFunctionConstructor(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return constructFunction(exec, args); +} + +// ECMA 15.3.1 The Function Constructor Called as a Function +CallType FunctionConstructor::getCallData(CallData& callData) +{ + callData.native.function = callFunctionConstructor; + return CallTypeHost; +} + +FunctionBodyNode* extractFunctionBody(ProgramNode* program) +{ + if (!program) + return 0; + + StatementVector& children = program->children(); + if (children.size() != 1) + return 0; + + StatementNode* exprStatement = children[0]; + ASSERT(exprStatement); + ASSERT(exprStatement->isExprStatement()); + if (!exprStatement || !exprStatement->isExprStatement()) + return 0; + + ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr(); + ASSERT(funcExpr); + ASSERT(funcExpr->isFuncExprNode()); + if (!funcExpr || !funcExpr->isFuncExprNode()) + return 0; + + FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body(); + ASSERT(body); + return body; +} + +// ECMA 15.3.2 The Function Constructor +JSObject* constructFunction(ExecState* exec, const ArgList& args, const Identifier& functionName, const UString& sourceURL, int lineNumber) +{ + // Functions need to have a space following the opening { due to for web compatibility + // see https://bugs.webkit.org/show_bug.cgi?id=24350 + // We also need \n before the closing } to handle // comments at the end of the last line + UString program; + if (args.isEmpty()) + program = "(function() { \n})"; + else if (args.size() == 1) + program = "(function() { " + args.at(0).toString(exec) + "\n})"; + else { + program = "(function(" + args.at(0).toString(exec); + for (size_t i = 1; i < args.size() - 1; i++) + program += "," + args.at(i).toString(exec); + program += ") { " + args.at(args.size() - 1).toString(exec) + "\n})"; + } + + int errLine; + UString errMsg; + SourceCode source = makeSource(program, sourceURL, lineNumber); + RefPtr<ProgramNode> programNode = exec->globalData().parser->parse<ProgramNode>(exec, exec->dynamicGlobalObject()->debugger(), source, &errLine, &errMsg); + + FunctionBodyNode* body = extractFunctionBody(programNode.get()); + if (!body) + return throwError(exec, SyntaxError, errMsg, errLine, source.provider()->asID(), source.provider()->url()); + + JSGlobalObject* globalObject = exec->lexicalGlobalObject(); + ScopeChain scopeChain(globalObject, globalObject->globalData(), exec->globalThisValue()); + return new (exec) JSFunction(exec, functionName, body, scopeChain.node()); +} + +// ECMA 15.3.2 The Function Constructor +JSObject* constructFunction(ExecState* exec, const ArgList& args) +{ + return constructFunction(exec, args, Identifier(exec, "anonymous"), UString(), 1); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionConstructor.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionConstructor.h new file mode 100644 index 0000000..124b354 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionConstructor.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * 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 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 FunctionConstructor_h +#define FunctionConstructor_h + +#include "InternalFunction.h" + +namespace JSC { + + class FunctionPrototype; + class ProgramNode; + class FunctionBodyNode; + + class FunctionConstructor : public InternalFunction { + public: + FunctionConstructor(ExecState*, PassRefPtr<Structure>, FunctionPrototype*); + + private: + virtual ConstructType getConstructData(ConstructData&); + virtual CallType getCallData(CallData&); + }; + + JSObject* constructFunction(ExecState*, const ArgList&, const Identifier& functionName, const UString& sourceURL, int lineNumber); + JSObject* constructFunction(ExecState*, const ArgList&); + + FunctionBodyNode* extractFunctionBody(ProgramNode*); + +} // namespace JSC + +#endif // FunctionConstructor_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionPrototype.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionPrototype.cpp new file mode 100644 index 0000000..ff8e57b --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionPrototype.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "FunctionPrototype.h" + +#include "Arguments.h" +#include "JSArray.h" +#include "JSFunction.h" +#include "JSString.h" +#include "Interpreter.h" +#include "Lexer.h" +#include "PrototypeFunction.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(FunctionPrototype); + +static JSValue JSC_HOST_CALL functionProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL functionProtoFuncApply(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL functionProtoFuncCall(ExecState*, JSObject*, JSValue, const ArgList&); + +FunctionPrototype::FunctionPrototype(ExecState* exec, PassRefPtr<Structure> structure) + : InternalFunction(&exec->globalData(), structure, exec->propertyNames().nullIdentifier) +{ + putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 0), DontDelete | ReadOnly | DontEnum); +} + +void FunctionPrototype::addFunctionProperties(ExecState* exec, Structure* prototypeFunctionStructure, NativeFunctionWrapper** callFunction, NativeFunctionWrapper** applyFunction) +{ + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().toString, functionProtoFuncToString), DontEnum); + *applyFunction = new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 2, exec->propertyNames().apply, functionProtoFuncApply); + putDirectFunctionWithoutTransition(exec, *applyFunction, DontEnum); + *callFunction = new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().call, functionProtoFuncCall); + putDirectFunctionWithoutTransition(exec, *callFunction, DontEnum); +} + +static JSValue JSC_HOST_CALL callFunctionPrototype(ExecState*, JSObject*, JSValue, const ArgList&) +{ + return jsUndefined(); +} + +// ECMA 15.3.4 +CallType FunctionPrototype::getCallData(CallData& callData) +{ + callData.native.function = callFunctionPrototype; + return CallTypeHost; +} + +// Functions + +// Compatibility hack for the Optimost JavaScript library. (See <rdar://problem/6595040>.) +static inline void insertSemicolonIfNeeded(UString& functionBody) +{ + ASSERT(functionBody[0] == '{'); + ASSERT(functionBody[functionBody.size() - 1] == '}'); + + for (size_t i = functionBody.size() - 2; i > 0; --i) { + UChar ch = functionBody[i]; + if (!Lexer::isWhiteSpace(ch) && !Lexer::isLineTerminator(ch)) { + if (ch != ';' && ch != '}') + functionBody = functionBody.substr(0, i + 1) + ";" + functionBody.substr(i + 1, functionBody.size() - (i + 1)); + return; + } + } +} + +JSValue JSC_HOST_CALL functionProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (thisValue.isObject(&JSFunction::info)) { + JSFunction* function = asFunction(thisValue); + if (!function->isHostFunction()) { + UString functionBody = function->body()->toSourceString(); + insertSemicolonIfNeeded(functionBody); + return jsString(exec, "function " + function->name(&exec->globalData()) + "(" + function->body()->paramString() + ") " + functionBody); + } + } + + if (thisValue.isObject(&InternalFunction::info)) { + InternalFunction* function = asInternalFunction(thisValue); + return jsString(exec, "function " + function->name(&exec->globalData()) + "() {\n [native code]\n}"); + } + +#ifdef QT_BUILD_SCRIPT_LIB //same error message as in the old engine, and in mozilla + return throwError(exec, TypeError, "Function.prototype.toString called on incompatible object"); +#else + return throwError(exec, TypeError); +#endif +} + +JSValue JSC_HOST_CALL functionProtoFuncApply(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + CallData callData; + CallType callType = thisValue.getCallData(callData); + if (callType == CallTypeNone) + return throwError(exec, TypeError); + + JSValue array = args.at(1); + + MarkedArgumentBuffer applyArgs; + if (!array.isUndefinedOrNull()) { + if (!array.isObject()) + return throwError(exec, TypeError); + if (asObject(array)->classInfo() == &Arguments::info) + asArguments(array)->fillArgList(exec, applyArgs); + else if (isJSArray(&exec->globalData(), array)) + asArray(array)->fillArgList(exec, applyArgs); + else if (asObject(array)->inherits(&JSArray::info)) { + unsigned length = asArray(array)->get(exec, exec->propertyNames().length).toUInt32(exec); + for (unsigned i = 0; i < length; ++i) + applyArgs.append(asArray(array)->get(exec, i)); + } else + return throwError(exec, TypeError); + } + + return call(exec, thisValue, callType, callData, args.at(0), applyArgs); +} + +JSValue JSC_HOST_CALL functionProtoFuncCall(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + CallData callData; + CallType callType = thisValue.getCallData(callData); + if (callType == CallTypeNone) + return throwError(exec, TypeError); + + ArgList callArgs; + args.getSlice(1, callArgs); + return call(exec, thisValue, callType, callData, args.at(0), callArgs); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionPrototype.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionPrototype.h new file mode 100644 index 0000000..607ddab --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionPrototype.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * 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 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 FunctionPrototype_h +#define FunctionPrototype_h + +#include "InternalFunction.h" + +namespace JSC { + + class PrototypeFunction; + + class FunctionPrototype : public InternalFunction { + public: + FunctionPrototype(ExecState*, PassRefPtr<Structure>); + void addFunctionProperties(ExecState*, Structure* prototypeFunctionStructure, NativeFunctionWrapper** callFunction, NativeFunctionWrapper** applyFunction); + + static PassRefPtr<Structure> createStructure(JSValue proto) + { + return Structure::create(proto, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot)); + } + + private: + virtual CallType getCallData(CallData&); + }; + +} // namespace JSC + +#endif // FunctionPrototype_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GetterSetter.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GetterSetter.cpp new file mode 100644 index 0000000..cd1b40a --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GetterSetter.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2004, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "GetterSetter.h" + +#include "JSObject.h" +#include <wtf/Assertions.h> + +namespace JSC { + +void GetterSetter::mark() +{ + JSCell::mark(); + + if (m_getter && !m_getter->marked()) + m_getter->mark(); + if (m_setter && !m_setter->marked()) + m_setter->mark(); +} + +JSValue GetterSetter::toPrimitive(ExecState*, PreferredPrimitiveType) const +{ + ASSERT_NOT_REACHED(); + return jsNull(); +} + +bool GetterSetter::getPrimitiveNumber(ExecState*, double& number, JSValue& value) +{ + ASSERT_NOT_REACHED(); + number = 0; + value = JSValue(); + return true; +} + +bool GetterSetter::toBoolean(ExecState*) const +{ + ASSERT_NOT_REACHED(); + return false; +} + +double GetterSetter::toNumber(ExecState*) const +{ + ASSERT_NOT_REACHED(); + return 0.0; +} + +UString GetterSetter::toString(ExecState*) const +{ + ASSERT_NOT_REACHED(); + return UString::null(); +} + +JSObject* GetterSetter::toObject(ExecState* exec) const +{ + ASSERT_NOT_REACHED(); + return jsNull().toObject(exec); +} + +bool GetterSetter::isGetterSetter() const +{ + return true; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GetterSetter.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GetterSetter.h new file mode 100644 index 0000000..e6b74a1 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GetterSetter.h @@ -0,0 +1,75 @@ +/* + * 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 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef GetterSetter_h +#define GetterSetter_h + +#include "JSCell.h" + +namespace JSC { + + class JSObject; + + // This is an internal value object which stores getter and setter functions + // for a property. + class GetterSetter : public JSCell { + public: + GetterSetter() + : JSCell(0) + , m_getter(0) + , m_setter(0) + { + } + + virtual void mark(); + + JSObject* getter() const { return m_getter; } + void setGetter(JSObject* getter) { m_getter = getter; } + JSObject* setter() const { return m_setter; } + void setSetter(JSObject* setter) { m_setter = setter; } + + private: + virtual bool isGetterSetter() const; + + virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; + virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value); + virtual bool toBoolean(ExecState*) const; + virtual double toNumber(ExecState*) const; + virtual UString toString(ExecState*) const; + virtual JSObject* toObject(ExecState*) const; + + JSObject* m_getter; + JSObject* m_setter; + }; + + GetterSetter* asGetterSetter(JSValue); + + inline GetterSetter* asGetterSetter(JSValue value) + { + ASSERT(asCell(value)->isGetterSetter()); + return static_cast<GetterSetter*>(asCell(value)); + } + + +} // namespace JSC + +#endif // GetterSetter_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GlobalEvalFunction.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GlobalEvalFunction.cpp new file mode 100644 index 0000000..b0d4c25 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GlobalEvalFunction.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) + * Copyright (C) 2007 Maks Orlovich + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "GlobalEvalFunction.h" + +#include "JSGlobalObject.h" +#include <wtf/Assertions.h> + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(GlobalEvalFunction); + +GlobalEvalFunction::GlobalEvalFunction(ExecState* exec, PassRefPtr<Structure> structure, int len, const Identifier& name, NativeFunction function, JSGlobalObject* cachedGlobalObject) + : PrototypeFunction(exec, structure, len, name, function) + , m_cachedGlobalObject(cachedGlobalObject) +{ + ASSERT_ARG(cachedGlobalObject, cachedGlobalObject); +} + +void GlobalEvalFunction::mark() +{ + PrototypeFunction::mark(); + if (!m_cachedGlobalObject->marked()) + m_cachedGlobalObject->mark(); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GlobalEvalFunction.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GlobalEvalFunction.h new file mode 100644 index 0000000..49b1847 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GlobalEvalFunction.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) + * Copyright (C) 2007 Maks Orlovich + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef GlobalEvalFunction_h +#define GlobalEvalFunction_h + +#include "PrototypeFunction.h" + +namespace JSC { + + class JSGlobalObject; + + class GlobalEvalFunction : public PrototypeFunction { + public: + GlobalEvalFunction(ExecState*, PassRefPtr<Structure>, int len, const Identifier&, NativeFunction, JSGlobalObject* expectedThisObject); + JSGlobalObject* cachedGlobalObject() const { return m_cachedGlobalObject; } + + private: + virtual void mark(); + + JSGlobalObject* m_cachedGlobalObject; + }; + +} // namespace JSC + +#endif // GlobalEvalFunction_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Identifier.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Identifier.cpp new file mode 100644 index 0000000..7db723b --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Identifier.cpp @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2003, 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 + * 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 "Identifier.h" + +#include "CallFrame.h" +#include <new> // for placement new +#include <string.h> // for strlen +#include <wtf/Assertions.h> +#include <wtf/FastMalloc.h> +#include <wtf/HashSet.h> + +namespace JSC { + +typedef HashMap<const char*, RefPtr<UString::Rep>, PtrHash<const char*> > LiteralIdentifierTable; + +class IdentifierTable : public FastAllocBase { +public: + ~IdentifierTable() + { + HashSet<UString::Rep*>::iterator end = m_table.end(); + for (HashSet<UString::Rep*>::iterator iter = m_table.begin(); iter != end; ++iter) + (*iter)->setIdentifierTable(0); + } + + std::pair<HashSet<UString::Rep*>::iterator, bool> add(UString::Rep* value) + { + std::pair<HashSet<UString::Rep*>::iterator, bool> result = m_table.add(value); + (*result.first)->setIdentifierTable(this); + return result; + } + + template<typename U, typename V> + std::pair<HashSet<UString::Rep*>::iterator, bool> add(U value) + { + std::pair<HashSet<UString::Rep*>::iterator, bool> result = m_table.add<U, V>(value); + (*result.first)->setIdentifierTable(this); + return result; + } + + void remove(UString::Rep* r) { m_table.remove(r); } + + LiteralIdentifierTable& literalTable() { return m_literalTable; } + +private: + HashSet<UString::Rep*> m_table; + LiteralIdentifierTable m_literalTable; +}; + +IdentifierTable* createIdentifierTable() +{ + return new IdentifierTable; +} + +void deleteIdentifierTable(IdentifierTable* table) +{ + delete table; +} + +bool Identifier::equal(const UString::Rep* r, const char* s) +{ + int length = r->len; + const UChar* d = r->data(); + for (int i = 0; i != length; ++i) + if (d[i] != (unsigned char)s[i]) + return false; + return s[length] == 0; +} + +bool Identifier::equal(const UString::Rep* r, const UChar* s, int length) +{ + if (r->len != length) + return false; + const UChar* d = r->data(); + for (int i = 0; i != length; ++i) + if (d[i] != s[i]) + return false; + return true; +} + +struct CStringTranslator { + static unsigned hash(const char* c) + { + return UString::Rep::computeHash(c); + } + + static bool equal(UString::Rep* r, const char* s) + { + return Identifier::equal(r, s); + } + + static void translate(UString::Rep*& location, const char* c, unsigned hash) + { + size_t length = strlen(c); + UChar* d = static_cast<UChar*>(fastMalloc(sizeof(UChar) * length)); + for (size_t i = 0; i != length; i++) + d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend + + UString::Rep* r = UString::Rep::create(d, static_cast<int>(length)).releaseRef(); + r->_hash = hash; + + location = r; + } +}; + +PassRefPtr<UString::Rep> Identifier::add(JSGlobalData* globalData, const char* c) +{ + if (!c) { + UString::Rep::null().hash(); + return &UString::Rep::null(); + } + if (!c[0]) { + UString::Rep::empty().hash(); + return &UString::Rep::empty(); + } + if (!c[1]) + return add(globalData, globalData->smallStrings.singleCharacterStringRep(static_cast<unsigned char>(c[0]))); + + IdentifierTable& identifierTable = *globalData->identifierTable; + LiteralIdentifierTable& literalIdentifierTable = identifierTable.literalTable(); + + const LiteralIdentifierTable::iterator& iter = literalIdentifierTable.find(c); + if (iter != literalIdentifierTable.end()) + return iter->second; + + pair<HashSet<UString::Rep*>::iterator, bool> addResult = identifierTable.add<const char*, CStringTranslator>(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<UString::Rep> addedString = addResult.second ? adoptRef(*addResult.first) : *addResult.first; + + literalIdentifierTable.add(c, addedString.get()); + + return addedString.release(); +} + +PassRefPtr<UString::Rep> Identifier::add(ExecState* exec, const char* c) +{ + return add(&exec->globalData(), c); +} + +struct UCharBuffer { + const UChar* s; + unsigned int length; +}; + +struct UCharBufferTranslator { + static unsigned hash(const UCharBuffer& buf) + { + return UString::Rep::computeHash(buf.s, buf.length); + } + + static bool equal(UString::Rep* str, const UCharBuffer& buf) + { + return Identifier::equal(str, buf.s, buf.length); + } + + static void translate(UString::Rep*& location, const UCharBuffer& buf, unsigned hash) + { + UChar* d = static_cast<UChar*>(fastMalloc(sizeof(UChar) * buf.length)); + for (unsigned i = 0; i != buf.length; i++) + d[i] = buf.s[i]; + + UString::Rep* r = UString::Rep::create(d, buf.length).releaseRef(); + r->_hash = hash; + + location = r; + } +}; + +PassRefPtr<UString::Rep> Identifier::add(JSGlobalData* globalData, const UChar* s, int length) +{ + if (length == 1) { + UChar c = s[0]; + if (c <= 0xFF) + return add(globalData, globalData->smallStrings.singleCharacterStringRep(c)); + } + if (!length) { + UString::Rep::empty().hash(); + return &UString::Rep::empty(); + } + UCharBuffer buf = {s, length}; + pair<HashSet<UString::Rep*>::iterator, bool> addResult = globalData->identifierTable->add<UCharBuffer, UCharBufferTranslator>(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.second ? adoptRef(*addResult.first) : *addResult.first; +} + +PassRefPtr<UString::Rep> Identifier::add(ExecState* exec, const UChar* s, int length) +{ + return add(&exec->globalData(), s, length); +} + +PassRefPtr<UString::Rep> Identifier::addSlowCase(JSGlobalData* globalData, UString::Rep* r) +{ + ASSERT(!r->identifierTable()); + if (r->len == 1) { + UChar c = r->data()[0]; + if (c <= 0xFF) + r = globalData->smallStrings.singleCharacterStringRep(c); + if (r->identifierTable()) { +#ifndef NDEBUG + checkSameIdentifierTable(globalData, r); +#endif + return r; + } + } + if (!r->len) { + UString::Rep::empty().hash(); + return &UString::Rep::empty(); + } + return *globalData->identifierTable->add(r).first; +} + +PassRefPtr<UString::Rep> Identifier::addSlowCase(ExecState* exec, UString::Rep* r) +{ + return addSlowCase(&exec->globalData(), r); +} + +void Identifier::remove(UString::Rep* r) +{ + r->identifierTable()->remove(r); +} + +#ifndef NDEBUG + +void Identifier::checkSameIdentifierTable(ExecState* exec, UString::Rep* rep) +{ + ASSERT(rep->identifierTable() == exec->globalData().identifierTable); +} + +void Identifier::checkSameIdentifierTable(JSGlobalData* globalData, UString::Rep* rep) +{ + ASSERT(rep->identifierTable() == globalData->identifierTable); +} + +#else + +void Identifier::checkSameIdentifierTable(ExecState*, UString::Rep*) +{ +} + +void Identifier::checkSameIdentifierTable(JSGlobalData*, UString::Rep*) +{ +} + +#endif + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Identifier.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Identifier.h new file mode 100644 index 0000000..631cf42 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Identifier.h @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2003, 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 + * 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 Identifier_h +#define Identifier_h + +#include "JSGlobalData.h" +#include "UString.h" + +namespace JSC { + + class ExecState; + + class Identifier { + friend class Structure; + public: + Identifier() { } + + Identifier(ExecState* exec, const char* s) : _ustring(add(exec, s)) { } // Only to be used with string literals. + Identifier(ExecState* exec, const UChar* s, int length) : _ustring(add(exec, s, length)) { } + Identifier(ExecState* exec, UString::Rep* rep) : _ustring(add(exec, rep)) { } + Identifier(ExecState* exec, const UString& s) : _ustring(add(exec, s.rep())) { } + + Identifier(JSGlobalData* globalData, const char* s) : _ustring(add(globalData, s)) { } // Only to be used with string literals. + Identifier(JSGlobalData* globalData, const UChar* s, int length) : _ustring(add(globalData, s, length)) { } + Identifier(JSGlobalData* globalData, UString::Rep* rep) : _ustring(add(globalData, rep)) { } + Identifier(JSGlobalData* globalData, const UString& s) : _ustring(add(globalData, s.rep())) { } + + // Special constructor for cases where we overwrite an object in place. + Identifier(PlacementNewAdoptType) : _ustring(PlacementNewAdopt) { } + + const UString& ustring() const { return _ustring; } + + const UChar* data() const { return _ustring.data(); } + int size() const { return _ustring.size(); } + + const char* ascii() const { return _ustring.ascii(); } + + static Identifier from(ExecState* exec, unsigned y) { return Identifier(exec, UString::from(y)); } + + bool isNull() const { return _ustring.isNull(); } + bool isEmpty() const { return _ustring.isEmpty(); } + + uint32_t toUInt32(bool* ok) const { return _ustring.toUInt32(ok); } + uint32_t toUInt32(bool* ok, bool tolerateEmptyString) const { return _ustring.toUInt32(ok, tolerateEmptyString); }; + uint32_t toStrictUInt32(bool* ok) const { return _ustring.toStrictUInt32(ok); } + unsigned toArrayIndex(bool* ok) const { return _ustring.toArrayIndex(ok); } + double toDouble() const { return _ustring.toDouble(); } + + friend bool operator==(const Identifier&, const Identifier&); + friend bool operator!=(const Identifier&, const Identifier&); + + friend bool operator==(const Identifier&, const char*); + friend bool operator!=(const Identifier&, const char*); + + static void remove(UString::Rep*); + + static bool equal(const UString::Rep*, const char*); + static bool equal(const UString::Rep*, const UChar*, int length); + static bool equal(const UString::Rep* a, const UString::Rep* b) { return JSC::equal(a, b); } + + static PassRefPtr<UString::Rep> add(ExecState*, const char*); // Only to be used with string literals. + static PassRefPtr<UString::Rep> add(JSGlobalData*, const char*); // Only to be used with string literals. + + private: + UString _ustring; + + static bool equal(const Identifier& a, const Identifier& b) { return a._ustring.rep() == b._ustring.rep(); } + static bool equal(const Identifier& a, const char* b) { return equal(a._ustring.rep(), b); } + + static PassRefPtr<UString::Rep> add(ExecState*, const UChar*, int length); + static PassRefPtr<UString::Rep> add(JSGlobalData*, const UChar*, int length); + + static PassRefPtr<UString::Rep> add(ExecState* exec, UString::Rep* r) + { + if (r->identifierTable()) { +#ifndef NDEBUG + checkSameIdentifierTable(exec, r); +#endif + return r; + } + return addSlowCase(exec, r); + } + static PassRefPtr<UString::Rep> add(JSGlobalData* globalData, UString::Rep* r) + { + if (r->identifierTable()) { +#ifndef NDEBUG + checkSameIdentifierTable(globalData, r); +#endif + return r; + } + return addSlowCase(globalData, r); + } + + static PassRefPtr<UString::Rep> addSlowCase(ExecState*, UString::Rep* r); + static PassRefPtr<UString::Rep> addSlowCase(JSGlobalData*, UString::Rep* r); + + static void checkSameIdentifierTable(ExecState*, UString::Rep*); + static void checkSameIdentifierTable(JSGlobalData*, UString::Rep*); + }; + + 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 char* b) + { + return Identifier::equal(a, b); + } + + inline bool operator!=(const Identifier& a, const char* b) + { + return !Identifier::equal(a, b); + } + + IdentifierTable* createIdentifierTable(); + void deleteIdentifierTable(IdentifierTable*); + +} // namespace JSC + +#endif // Identifier_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InitializeThreading.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InitializeThreading.cpp new file mode 100644 index 0000000..a0620e7 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InitializeThreading.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "InitializeThreading.h" + +#include "JSImmediate.h" +#include "Collector.h" +#include "dtoa.h" +#include "Identifier.h" +#include "JSGlobalObject.h" +#include "UString.h" +#include <wtf/DateMath.h> +#include <wtf/Threading.h> + +using namespace WTF; + +namespace JSC { + +#if PLATFORM(DARWIN) && ENABLE(JSC_MULTIPLE_THREADS) +static pthread_once_t initializeThreadingKeyOnce = PTHREAD_ONCE_INIT; +#endif + +static void initializeThreadingOnce() +{ + WTF::initializeThreading(); + initializeUString(); +#if ENABLE(JSC_MULTIPLE_THREADS) + s_dtoaP5Mutex = new Mutex; + WTF::initializeDates(); +#endif +} + +void initializeThreading() +{ +#if PLATFORM(DARWIN) && ENABLE(JSC_MULTIPLE_THREADS) + pthread_once(&initializeThreadingKeyOnce, initializeThreadingOnce); +#else + static bool initializedThreading = false; + if (!initializedThreading) { + initializeThreadingOnce(); + initializedThreading = true; + } +#endif +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InitializeThreading.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InitializeThreading.h new file mode 100644 index 0000000..1a93ccb --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InitializeThreading.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef InitializeThreading_h +#define InitializeThreading_h + +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. + void initializeThreading(); + +} + +#endif // InitializeThreading_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InternalFunction.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InternalFunction.cpp new file mode 100644 index 0000000..b5c9571 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InternalFunction.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2004, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "InternalFunction.h" + +#include "FunctionPrototype.h" +#include "JSString.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(InternalFunction); + +const ClassInfo InternalFunction::info = { "Function", 0, 0, 0 }; + +const ClassInfo* InternalFunction::classInfo() const +{ + return &info; +} + +InternalFunction::InternalFunction(JSGlobalData* globalData, PassRefPtr<Structure> structure, const Identifier& name) + : JSObject(structure) +{ + putDirect(globalData->propertyNames->name, jsString(globalData, name.ustring()), DontDelete | ReadOnly | DontEnum); +} + +const UString& InternalFunction::name(JSGlobalData* globalData) +{ + return asString(getDirect(globalData->propertyNames->name))->value(); +} + +const UString InternalFunction::displayName(JSGlobalData* globalData) +{ + JSValue displayName = getDirect(globalData->propertyNames->displayName); + + if (displayName && isJSString(globalData, displayName)) + return asString(displayName)->value(); + + return UString::null(); +} + +const UString InternalFunction::calculatedDisplayName(JSGlobalData* globalData) +{ + const UString explicitName = displayName(globalData); + + if (!explicitName.isEmpty()) + return explicitName; + + return name(globalData); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InternalFunction.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InternalFunction.h new file mode 100644 index 0000000..310644c --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InternalFunction.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) + * Copyright (C) 2007 Maks Orlovich + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef InternalFunction_h +#define InternalFunction_h + +#include "JSObject.h" +#include "Identifier.h" + +namespace JSC { + + class FunctionPrototype; + + class InternalFunction : public JSObject { + public: + virtual const ClassInfo* classInfo() const; + static JS_EXPORTDATA const ClassInfo info; + + const UString& name(JSGlobalData*); + const UString displayName(JSGlobalData*); + const UString calculatedDisplayName(JSGlobalData*); + + static PassRefPtr<Structure> createStructure(JSValue proto) + { + return Structure::create(proto, TypeInfo(ObjectType, ImplementsHasInstance | HasStandardGetOwnPropertySlot)); + } + + protected: + InternalFunction(PassRefPtr<Structure> structure) : JSObject(structure) { } + InternalFunction(JSGlobalData*, PassRefPtr<Structure>, const Identifier&); + + private: + virtual CallType getCallData(CallData&) = 0; + }; + + InternalFunction* asInternalFunction(JSValue); + + inline InternalFunction* asInternalFunction(JSValue value) + { + ASSERT(asObject(value)->inherits(&InternalFunction::info)); + return static_cast<InternalFunction*>(asObject(value)); + } + +} // namespace JSC + +#endif // InternalFunction_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSActivation.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSActivation.cpp new file mode 100644 index 0000000..184a9cb --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSActivation.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSActivation.h" + +#include "Arguments.h" +#include "Interpreter.h" +#include "JSFunction.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(JSActivation); + +const ClassInfo JSActivation::info = { "JSActivation", 0, 0, 0 }; + +JSActivation::JSActivation(CallFrame* callFrame, PassRefPtr<FunctionBodyNode> functionBody) + : Base(callFrame->globalData().activationStructure, new JSActivationData(functionBody, callFrame->registers())) +{ +} + +JSActivation::~JSActivation() +{ + delete d(); +} + +void JSActivation::mark() +{ + Base::mark(); + + Register* registerArray = d()->registerArray.get(); + if (!registerArray) + return; + + size_t numParametersMinusThis = d()->functionBody->generatedBytecode().m_numParameters - 1; + + size_t i = 0; + size_t count = numParametersMinusThis; + for ( ; i < count; ++i) { + Register& r = registerArray[i]; + if (!r.marked()) + r.mark(); + } + + size_t numVars = d()->functionBody->generatedBytecode().m_numVars; + + // Skip the call frame, which sits between the parameters and vars. + i += RegisterFile::CallFrameHeaderSize; + count += RegisterFile::CallFrameHeaderSize + numVars; + + for ( ; i < count; ++i) { + Register& r = registerArray[i]; + if (r.jsValue() && !r.marked()) + r.mark(); + } +} + +bool JSActivation::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +{ + if (symbolTableGet(propertyName, slot)) + return true; + + if (JSValue* location = getDirectLocation(propertyName)) { + slot.setValueSlot(location); + return true; + } + + // Only return the built-in arguments object if it wasn't overridden above. + if (propertyName == exec->propertyNames().arguments) { + slot.setCustom(this, getArgumentsGetter()); + 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(!hasGetterSetterProperties()); + ASSERT(prototype().isNull()); + return false; +} + +void JSActivation::put(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) +{ + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); + + if (symbolTablePut(propertyName, value)) + 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(!hasGetterSetterProperties()); + putDirect(propertyName, value, 0, true, slot); +} + +// FIXME: Make this function honor ReadOnly (const) and DontEnum +void JSActivation::putWithAttributes(ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes) +{ + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); + + if (symbolTablePutWithAttributes(propertyName, value, attributes)) + 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(!hasGetterSetterProperties()); + PutPropertySlot slot; + JSObject::putWithAttributes(exec, propertyName, value, attributes, true, slot); +} + +bool JSActivation::deleteProperty(ExecState* exec, const Identifier& propertyName, bool checkDontDelete) +{ + if (propertyName == exec->propertyNames().arguments) + return false; + + return Base::deleteProperty(exec, propertyName, checkDontDelete); +} + +JSObject* JSActivation::toThisObject(ExecState* exec) const +{ + return exec->globalThisValue(); +} + +bool JSActivation::isDynamicScope() const +{ + return d()->functionBody->usesEval(); +} + +JSValue JSActivation::argumentsGetter(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + JSActivation* activation = asActivation(slot.slotBase()); + + if (activation->d()->functionBody->usesArguments()) { + PropertySlot slot; + activation->symbolTableGet(exec->propertyNames().arguments, slot); + return slot.getValue(exec, exec->propertyNames().arguments); + } + + CallFrame* callFrame = CallFrame::create(activation->d()->registers); + Arguments* arguments = callFrame->optionalCalleeArguments(); + if (!arguments) { + arguments = new (callFrame) Arguments(callFrame); + arguments->copyRegisters(); + callFrame->setCalleeArguments(arguments); + } + ASSERT(arguments->isObject(&Arguments::info)); + + return arguments; +} + +// These two functions serve the purpose of isolating the common case from a +// PIC branch. + +PropertySlot::GetValueFunc JSActivation::getArgumentsGetter() +{ + return argumentsGetter; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSActivation.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSActivation.h new file mode 100644 index 0000000..b48ef25 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSActivation.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSActivation_h +#define JSActivation_h + +#include "CodeBlock.h" +#include "JSVariableObject.h" +#include "RegisterFile.h" +#include "SymbolTable.h" +#include "Nodes.h" + +namespace JSC { + + class Arguments; + class Register; + + class JSActivation : public JSVariableObject { + typedef JSVariableObject Base; + public: + JSActivation(CallFrame*, PassRefPtr<FunctionBodyNode>); + virtual ~JSActivation(); + + virtual void mark(); + + virtual bool isDynamicScope() const; + + virtual bool isActivationObject() const { return true; } + + virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + + virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&); + + virtual void putWithAttributes(ExecState*, const Identifier&, JSValue, unsigned attributes); + virtual bool deleteProperty(ExecState*, const Identifier& propertyName, bool checkDontDelete = true); + + virtual JSObject* toThisObject(ExecState*) const; + + void copyRegisters(Arguments* arguments); + + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + + static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, NeedsThisConversion)); } + + private: + struct JSActivationData : public JSVariableObjectData { + JSActivationData(PassRefPtr<FunctionBodyNode> functionBody, Register* registers) + : JSVariableObjectData(&functionBody->generatedBytecode().symbolTable(), registers) + , functionBody(functionBody) + { + } + + RefPtr<FunctionBodyNode> functionBody; + }; + + static JSValue argumentsGetter(ExecState*, const Identifier&, const PropertySlot&); + NEVER_INLINE PropertySlot::GetValueFunc getArgumentsGetter(); + + JSActivationData* d() const { return static_cast<JSActivationData*>(JSVariableObject::d); } + }; + + JSActivation* asActivation(JSValue); + + inline JSActivation* asActivation(JSValue value) + { + ASSERT(asObject(value)->inherits(&JSActivation::info)); + return static_cast<JSActivation*>(asObject(value)); + } + +} // namespace JSC + +#endif // JSActivation_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSArray.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSArray.cpp new file mode 100644 index 0000000..a8207e3 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSArray.cpp @@ -0,0 +1,1073 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2003 Peter Kelly (pmk@post.com) + * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.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 + * + */ + +#include "config.h" +#include "JSArray.h" + +#include "ArrayPrototype.h" +#include "CachedCall.h" +#include "PropertyNameArray.h" +#include <wtf/AVLTree.h> +#include <wtf/Assertions.h> +#include <wtf/OwnPtr.h> +#include <Operations.h> + +#define CHECK_ARRAY_CONSISTENCY 0 + +using namespace std; +using namespace WTF; + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(JSArray); + +// Overview of JSArray +// +// Properties of JSArray objects may be stored in one of three locations: +// * The regular JSObject property map. +// * A storage vector. +// * A sparse map of array entries. +// +// Properties with non-numeric identifiers, with identifiers that are not representable +// as an unsigned integer, or where the value is greater than MAX_ARRAY_INDEX +// (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 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: +// +// * Where (i < MIN_SPARSE_ARRAY_INDEX) the value will be stored in the storage vector. +// * Where (MIN_SPARSE_ARRAY_INDEX <= i <= MAX_STORAGE_VECTOR_INDEX) the value will either +// be stored in the storage vector or in the sparse array, depending on the density of +// data that would be stored in the vector (a vector being used where at least +// (1 / minDensityMultiplier) of the entries would be populated). +// * Where (MAX_STORAGE_VECTOR_INDEX < i <= MAX_ARRAY_INDEX) the value will always be stored +// in the sparse array. + +// The definition of MAX_STORAGE_VECTOR_LENGTH is dependant on the definition storageSize +// function below - the MAX_STORAGE_VECTOR_LENGTH limit is defined such that the storage +// size calculation cannot overflow. (sizeof(ArrayStorage) - sizeof(JSValue)) + +// (vectorLength * sizeof(JSValue)) must be <= 0xFFFFFFFFU (which is maximum value of size_t). +#define MAX_STORAGE_VECTOR_LENGTH static_cast<unsigned>((0xFFFFFFFFU - (sizeof(ArrayStorage) - sizeof(JSValue))) / sizeof(JSValue)) + +// 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>. +#define MIN_SPARSE_ARRAY_INDEX 10000U +#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 + +// Our policy for when to use a vector and when to use a sparse map. +// For all array indices under MIN_SPARSE_ARRAY_INDEX, we always use a vector. +// When indices greater than MIN_SPARSE_ARRAY_INDEX are involved, we use a vector +// as long as it is 1/8 full. If more sparse than that, we use a map. +static const unsigned minDensityMultiplier = 8; + +const ClassInfo JSArray::info = {"Array", 0, 0, 0}; + +static inline size_t storageSize(unsigned vectorLength) +{ + ASSERT(vectorLength <= MAX_STORAGE_VECTOR_LENGTH); + + // MAX_STORAGE_VECTOR_LENGTH is defined such that provided (vectorLength <= MAX_STORAGE_VECTOR_LENGTH) + // - as asserted above - the following calculation cannot overflow. + size_t size = (sizeof(ArrayStorage) - sizeof(JSValue)) + (vectorLength * sizeof(JSValue)); + // Assertion to detect integer overflow in previous calculation (should not be possible, provided that + // MAX_STORAGE_VECTOR_LENGTH is correctly defined). + ASSERT(((size - (sizeof(ArrayStorage) - sizeof(JSValue))) / sizeof(JSValue) == vectorLength) && (size >= (sizeof(ArrayStorage) - sizeof(JSValue)))); + + return size; +} + +static inline unsigned increasedVectorLength(unsigned newLength) +{ + ASSERT(newLength <= MAX_STORAGE_VECTOR_LENGTH); + + // Mathematically equivalent to: + // increasedLength = (newLength * 3 + 1) / 2; + // or: + // increasedLength = (unsigned)ceil(newLength * 1.5)); + // This form is not prone to internal overflow. + unsigned increasedLength = newLength + (newLength >> 1) + (newLength & 1); + ASSERT(increasedLength >= newLength); + + return min(increasedLength, MAX_STORAGE_VECTOR_LENGTH); +} + +static inline bool isDenseEnoughForVector(unsigned length, unsigned numValues) +{ + return length / minDensityMultiplier <= numValues; +} + +#if !CHECK_ARRAY_CONSISTENCY + +inline void JSArray::checkConsistency(ConsistencyCheckType) +{ +} + +#endif + +JSArray::JSArray(PassRefPtr<Structure> structure) + : JSObject(structure) +{ + unsigned initialCapacity = 0; + + m_storage = static_cast<ArrayStorage*>(fastZeroedMalloc(storageSize(initialCapacity))); + m_fastAccessCutoff = 0; + m_storage->m_vectorLength = initialCapacity; + m_storage->m_length = 0; + + checkConsistency(); +} + +JSArray::JSArray(PassRefPtr<Structure> structure, unsigned initialLength) + : JSObject(structure) +{ + unsigned initialCapacity = min(initialLength, MIN_SPARSE_ARRAY_INDEX); + + m_storage = static_cast<ArrayStorage*>(fastZeroedMalloc(storageSize(initialCapacity))); + m_fastAccessCutoff = 0; + m_storage->m_vectorLength = initialCapacity; + m_storage->m_length = initialLength; + + Heap::heap(this)->reportExtraMemoryCost(initialCapacity * sizeof(JSValue)); + + checkConsistency(); +} + +JSArray::JSArray(PassRefPtr<Structure> structure, const ArgList& list) + : JSObject(structure) +{ + unsigned length = list.size(); + + m_fastAccessCutoff = length; + + ArrayStorage* storage = static_cast<ArrayStorage*>(fastMalloc(storageSize(length))); + + storage->m_vectorLength = length; + storage->m_numValuesInVector = length; + storage->m_sparseValueMap = 0; + storage->m_length = length; + + size_t i = 0; + ArgList::const_iterator end = list.end(); + for (ArgList::const_iterator it = list.begin(); it != end; ++it, ++i) + storage->m_vector[i] = *it; + + m_storage = storage; + + Heap::heap(this)->reportExtraMemoryCost(storageSize(length)); + + checkConsistency(); +} + +JSArray::~JSArray() +{ + checkConsistency(DestructorConsistencyCheck); + + delete m_storage->m_sparseValueMap; + fastFree(m_storage); +} + +bool JSArray::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& slot) +{ + ArrayStorage* storage = m_storage; + + if (i >= storage->m_length) { + if (i > MAX_ARRAY_INDEX) + return getOwnPropertySlot(exec, Identifier::from(exec, i), slot); + return false; + } + + if (i < storage->m_vectorLength) { + JSValue& valueSlot = storage->m_vector[i]; + if (valueSlot) { + slot.setValueSlot(&valueSlot); + return true; + } + } else if (SparseArrayValueMap* map = storage->m_sparseValueMap) { + if (i >= MIN_SPARSE_ARRAY_INDEX) { + SparseArrayValueMap::iterator it = map->find(i); + if (it != map->end()) { + slot.setValueSlot(&it->second); + return true; + } + } + } + + return false; +} + +bool JSArray::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +{ + if (propertyName == exec->propertyNames().length) { + slot.setValue(jsNumber(exec, length())); + return true; + } + + bool isArrayIndex; + unsigned i = propertyName.toArrayIndex(&isArrayIndex); + if (isArrayIndex) + return JSArray::getOwnPropertySlot(exec, i, slot); + + return JSObject::getOwnPropertySlot(exec, propertyName, slot); +} + +// ECMA 15.4.5.1 +void JSArray::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) +{ + bool isArrayIndex; + unsigned i = propertyName.toArrayIndex(&isArrayIndex); + if (isArrayIndex) { + put(exec, i, value); + return; + } + + if (propertyName == exec->propertyNames().length) { + unsigned newLength = value.toUInt32(exec); + if (value.toNumber(exec) != static_cast<double>(newLength)) { + throwError(exec, RangeError, "Invalid array length."); + return; + } + setLength(newLength); + return; + } + + JSObject::put(exec, propertyName, value, slot); +} + +void JSArray::put(ExecState* exec, unsigned i, JSValue value) +{ + checkConsistency(); + + unsigned length = m_storage->m_length; + if (i >= length && i <= MAX_ARRAY_INDEX) { + length = i + 1; + m_storage->m_length = length; + } + + if (i < m_storage->m_vectorLength) { + JSValue& valueSlot = m_storage->m_vector[i]; + if (valueSlot) { + valueSlot = value; + checkConsistency(); + return; + } + valueSlot = value; + if (++m_storage->m_numValuesInVector == m_storage->m_length) + m_fastAccessCutoff = m_storage->m_length; + checkConsistency(); + return; + } + + putSlowCase(exec, i, value); +} + +NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValue value) +{ + ArrayStorage* storage = m_storage; + SparseArrayValueMap* map = storage->m_sparseValueMap; + + if (i >= MIN_SPARSE_ARRAY_INDEX) { + if (i > MAX_ARRAY_INDEX) { + PutPropertySlot slot; + put(exec, Identifier::from(exec, i), value, slot); + return; + } + + // We miss some cases where we could compact the storage, such as a large array that is being filled from the end + // (which will only be compacted as we reach indices that are less than cutoff) - but this makes the check much faster. + if ((i > MAX_STORAGE_VECTOR_INDEX) || !isDenseEnoughForVector(i + 1, storage->m_numValuesInVector + 1)) { + if (!map) { + map = new SparseArrayValueMap; + storage->m_sparseValueMap = map; + } + map->set(i, value); + return; + } + } + + // We have decided that we'll put the new item into the vector. + // Fast case is when there is no sparse map, so we can increase the vector size without moving values from it. + if (!map || map->isEmpty()) { + if (increaseVectorLength(i + 1)) { + storage = m_storage; + storage->m_vector[i] = value; + if (++storage->m_numValuesInVector == storage->m_length) + m_fastAccessCutoff = storage->m_length; + checkConsistency(); + } else + throwOutOfMemoryError(exec); + return; + } + + // Decide how many values it would be best to move from the map. + unsigned newNumValuesInVector = storage->m_numValuesInVector + 1; + unsigned newVectorLength = increasedVectorLength(i + 1); + for (unsigned j = max(storage->m_vectorLength, MIN_SPARSE_ARRAY_INDEX); j < newVectorLength; ++j) + newNumValuesInVector += map->contains(j); + if (i >= MIN_SPARSE_ARRAY_INDEX) + newNumValuesInVector -= map->contains(i); + if (isDenseEnoughForVector(newVectorLength, newNumValuesInVector)) { + unsigned proposedNewNumValuesInVector = newNumValuesInVector; + // If newVectorLength is already the maximum - MAX_STORAGE_VECTOR_LENGTH - then do not attempt to grow any further. + while (newVectorLength < MAX_STORAGE_VECTOR_LENGTH) { + unsigned proposedNewVectorLength = increasedVectorLength(newVectorLength + 1); + for (unsigned j = max(newVectorLength, MIN_SPARSE_ARRAY_INDEX); j < proposedNewVectorLength; ++j) + proposedNewNumValuesInVector += map->contains(j); + if (!isDenseEnoughForVector(proposedNewVectorLength, proposedNewNumValuesInVector)) + break; + newVectorLength = proposedNewVectorLength; + newNumValuesInVector = proposedNewNumValuesInVector; + } + } + + storage = static_cast<ArrayStorage*>(tryFastRealloc(storage, storageSize(newVectorLength))); + if (!storage) { + throwOutOfMemoryError(exec); + return; + } + + unsigned vectorLength = storage->m_vectorLength; + + Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength)); + + if (newNumValuesInVector == storage->m_numValuesInVector + 1) { + for (unsigned j = vectorLength; j < newVectorLength; ++j) + storage->m_vector[j] = JSValue(); + if (i > MIN_SPARSE_ARRAY_INDEX) + map->remove(i); + } else { + for (unsigned j = vectorLength; j < max(vectorLength, MIN_SPARSE_ARRAY_INDEX); ++j) + storage->m_vector[j] = JSValue(); + for (unsigned j = max(vectorLength, MIN_SPARSE_ARRAY_INDEX); j < newVectorLength; ++j) + storage->m_vector[j] = map->take(j); + } + + storage->m_vector[i] = value; + + storage->m_vectorLength = newVectorLength; + storage->m_numValuesInVector = newNumValuesInVector; + + m_storage = storage; + + checkConsistency(); +} + +bool JSArray::deleteProperty(ExecState* exec, const Identifier& propertyName, bool checkDontDelete) +{ + bool isArrayIndex; + unsigned i = propertyName.toArrayIndex(&isArrayIndex); + if (isArrayIndex) + return deleteProperty(exec, i, checkDontDelete); + + if (propertyName == exec->propertyNames().length) + return false; + + return JSObject::deleteProperty(exec, propertyName, checkDontDelete); +} + +bool JSArray::deleteProperty(ExecState* exec, unsigned i, bool checkDontDelete) +{ + checkConsistency(); + + ArrayStorage* storage = m_storage; + + if (i < storage->m_vectorLength) { + JSValue& valueSlot = storage->m_vector[i]; + if (!valueSlot) { + checkConsistency(); + return false; + } + valueSlot = JSValue(); + --storage->m_numValuesInVector; + if (m_fastAccessCutoff > i) + m_fastAccessCutoff = i; + checkConsistency(); + return true; + } + + if (SparseArrayValueMap* map = storage->m_sparseValueMap) { + if (i >= MIN_SPARSE_ARRAY_INDEX) { + SparseArrayValueMap::iterator it = map->find(i); + if (it != map->end()) { + map->remove(it); + checkConsistency(); + return true; + } + } + } + + checkConsistency(); + + if (i > MAX_ARRAY_INDEX) + return deleteProperty(exec, Identifier::from(exec, i), checkDontDelete); + + return false; +} + +void JSArray::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, unsigned listedAttributes) +{ + // 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. + + ArrayStorage* storage = m_storage; + + unsigned usedVectorLength = min(storage->m_length, storage->m_vectorLength); + for (unsigned i = 0; i < usedVectorLength; ++i) { + if (storage->m_vector[i]) + propertyNames.add(Identifier::from(exec, i)); + } + + if (SparseArrayValueMap* map = storage->m_sparseValueMap) { + SparseArrayValueMap::iterator end = map->end(); + for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) + propertyNames.add(Identifier::from(exec, it->first)); + } + + JSObject::getPropertyNames(exec, propertyNames, listedAttributes); +} + +bool JSArray::increaseVectorLength(unsigned newLength) +{ + // This function leaves the array in an internally inconsistent state, because it does not move any values from sparse value map + // to the vector. Callers have to account for that, because they can do it more efficiently. + + ArrayStorage* storage = m_storage; + + unsigned vectorLength = storage->m_vectorLength; + ASSERT(newLength > vectorLength); + ASSERT(newLength <= MAX_STORAGE_VECTOR_INDEX); + unsigned newVectorLength = increasedVectorLength(newLength); + + storage = static_cast<ArrayStorage*>(tryFastRealloc(storage, storageSize(newVectorLength))); + if (!storage) + return false; + + Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength)); + storage->m_vectorLength = newVectorLength; + + for (unsigned i = vectorLength; i < newVectorLength; ++i) + storage->m_vector[i] = JSValue(); + + m_storage = storage; + return true; +} + +void JSArray::setLength(unsigned newLength) +{ + checkConsistency(); + + ArrayStorage* storage = m_storage; + + unsigned length = m_storage->m_length; + + if (newLength < length) { + if (m_fastAccessCutoff > newLength) + m_fastAccessCutoff = newLength; + + unsigned usedVectorLength = min(length, storage->m_vectorLength); + for (unsigned i = newLength; i < usedVectorLength; ++i) { + JSValue& valueSlot = storage->m_vector[i]; + bool hadValue = valueSlot; + valueSlot = JSValue(); + storage->m_numValuesInVector -= hadValue; + } + + if (SparseArrayValueMap* map = storage->m_sparseValueMap) { + SparseArrayValueMap copy = *map; + SparseArrayValueMap::iterator end = copy.end(); + for (SparseArrayValueMap::iterator it = copy.begin(); it != end; ++it) { + if (it->first >= newLength) + map->remove(it->first); + } + if (map->isEmpty()) { + delete map; + storage->m_sparseValueMap = 0; + } + } + } + + m_storage->m_length = newLength; + + checkConsistency(); +} + +JSValue JSArray::pop() +{ + checkConsistency(); + + unsigned length = m_storage->m_length; + if (!length) + return jsUndefined(); + + --length; + + JSValue result; + + if (m_fastAccessCutoff > length) { + JSValue& valueSlot = m_storage->m_vector[length]; + result = valueSlot; + ASSERT(result); + valueSlot = JSValue(); + --m_storage->m_numValuesInVector; + m_fastAccessCutoff = length; + } else if (length < m_storage->m_vectorLength) { + JSValue& valueSlot = m_storage->m_vector[length]; + result = valueSlot; + valueSlot = JSValue(); + if (result) + --m_storage->m_numValuesInVector; + else + result = jsUndefined(); + } else { + result = jsUndefined(); + if (SparseArrayValueMap* map = m_storage->m_sparseValueMap) { + SparseArrayValueMap::iterator it = map->find(length); + if (it != map->end()) { + result = it->second; + map->remove(it); + if (map->isEmpty()) { + delete map; + m_storage->m_sparseValueMap = 0; + } + } + } + } + + m_storage->m_length = length; + + checkConsistency(); + + return result; +} + +void JSArray::push(ExecState* exec, JSValue value) +{ + checkConsistency(); + + if (m_storage->m_length < m_storage->m_vectorLength) { + ASSERT(!m_storage->m_vector[m_storage->m_length]); + m_storage->m_vector[m_storage->m_length] = value; + if (++m_storage->m_numValuesInVector == ++m_storage->m_length) + m_fastAccessCutoff = m_storage->m_length; + checkConsistency(); + return; + } + + if (m_storage->m_length < MIN_SPARSE_ARRAY_INDEX) { + SparseArrayValueMap* map = m_storage->m_sparseValueMap; + if (!map || map->isEmpty()) { + if (increaseVectorLength(m_storage->m_length + 1)) { + m_storage->m_vector[m_storage->m_length] = value; + if (++m_storage->m_numValuesInVector == ++m_storage->m_length) + m_fastAccessCutoff = m_storage->m_length; + checkConsistency(); + return; + } + checkConsistency(); + throwOutOfMemoryError(exec); + return; + } + } + + putSlowCase(exec, m_storage->m_length++, value); +} + +void JSArray::mark() +{ + JSObject::mark(); + + ArrayStorage* storage = m_storage; + + unsigned usedVectorLength = min(storage->m_length, storage->m_vectorLength); + for (unsigned i = 0; i < usedVectorLength; ++i) { + JSValue value = storage->m_vector[i]; + if (value && !value.marked()) + value.mark(); + } + + if (SparseArrayValueMap* map = storage->m_sparseValueMap) { + SparseArrayValueMap::iterator end = map->end(); + for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) { + JSValue value = it->second; + if (!value.marked()) + value.mark(); + } + } +} + +static int compareNumbersForQSort(const void* a, const void* b) +{ + double da = static_cast<const JSValue*>(a)->uncheckedGetNumber(); + double db = static_cast<const JSValue*>(b)->uncheckedGetNumber(); + return (da > db) - (da < db); +} + +typedef std::pair<JSValue, UString> ValueStringPair; + +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 compare(va->second, vb->second); +} + +void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData) +{ + unsigned lengthNotIncludingUndefined = compactForSorting(); + if (m_storage->m_sparseValueMap) { + throwOutOfMemoryError(exec); + return; + } + + if (!lengthNotIncludingUndefined) + return; + + bool allValuesAreNumbers = true; + size_t size = m_storage->m_numValuesInVector; + for (size_t i = 0; i < size; ++i) { + if (!m_storage->m_vector[i].isNumber()) { + allValuesAreNumbers = false; + break; + } + } + + if (!allValuesAreNumbers) + return sort(exec, compareFunction, callType, callData); + + // For numeric comparison, which is fast, qsort is faster than mergesort. We + // also don't require mergesort's stability, since there's no user visible + // side-effect from swapping the order of equal primitive values. + qsort(m_storage->m_vector, size, sizeof(JSValue), compareNumbersForQSort); + + checkConsistency(SortConsistencyCheck); +} + +void JSArray::sort(ExecState* exec) +{ + unsigned lengthNotIncludingUndefined = compactForSorting(); + if (m_storage->m_sparseValueMap) { + throwOutOfMemoryError(exec); + return; + } + + if (!lengthNotIncludingUndefined) + return; + + // Converting JavaScript values to strings can be expensive, so we do it once up front and sort based on that. + // This is a considerable improvement over doing it twice per comparison, though it requires a large temporary + // buffer. Besides, this protects us from crashing if some objects have custom toString methods that return + // random or otherwise changing results, effectively making compare function inconsistent. + + Vector<ValueStringPair> values(lengthNotIncludingUndefined); + if (!values.begin()) { + throwOutOfMemoryError(exec); + return; + } + + for (size_t i = 0; i < lengthNotIncludingUndefined; i++) { + JSValue value = m_storage->m_vector[i]; + ASSERT(!value.isUndefined()); + values[i].first = value; + } + + // FIXME: While calling these toString functions, the array could be mutated. + // In that case, objects pointed to by values in this vector might get garbage-collected! + + // FIXME: The following loop continues to call toString on subsequent values even after + // a toString call raises an exception. + + for (size_t i = 0; i < lengthNotIncludingUndefined; i++) + values[i].second = values[i].first.toString(exec); + + if (exec->hadException()) + 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) + 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 + + // FIXME: If the toString function changed the length of the array, this might be + // modifying the vector incorrectly. + + for (size_t i = 0; i < lengthNotIncludingUndefined; i++) + m_storage->m_vector[i] = values[i].first; + + checkConsistency(SortConsistencyCheck); +} + +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> m_nodes; + ExecState* m_exec; + JSValue m_compareFunction; + CallType m_compareCallType; + const CallData* m_compareCallData; + JSValue m_globalThisValue; + 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(m_globalThisValue); + m_cachedCall->setArgument(0, va); + m_cachedCall->setArgument(1, vb); + compareResult = m_cachedCall->call().toNumber(m_cachedCall->newCallFrame()); + } else { + MarkedArgumentBuffer arguments; + arguments.append(va); + arguments.append(vb); + compareResult = call(m_exec, m_compareFunction, m_compareCallType, *m_compareCallData, m_globalThisValue, 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; } +}; + +void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData) +{ + checkConsistency(); + + // 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_storage->m_length <= static_cast<unsigned>(std::numeric_limits<int>::max())); + if (m_storage->m_length > static_cast<unsigned>(std::numeric_limits<int>::max())) + return; + + if (!m_storage->m_length) + return; + + unsigned usedVectorLength = min(m_storage->m_length, m_storage->m_vectorLength); + + 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_globalThisValue = exec->globalThisValue(); + tree.abstractor().m_nodes.resize(usedVectorLength + (m_storage->m_sparseValueMap ? m_storage->m_sparseValueMap->size() : 0)); + + if (callType == CallTypeJS) + tree.abstractor().m_cachedCall.set(new CachedCall(exec, asFunction(compareFunction), 2, exec->exceptionSlot())); + + 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) { + JSValue v = m_storage->m_vector[numDefined]; + if (!v || v.isUndefined()) + break; + tree.abstractor().m_nodes[numDefined].value = v; + tree.insert(numDefined); + } + for (unsigned i = numDefined; i < usedVectorLength; ++i) { + JSValue v = m_storage->m_vector[i]; + if (v) { + if (v.isUndefined()) + ++numUndefined; + else { + tree.abstractor().m_nodes[numDefined].value = v; + tree.insert(numDefined); + ++numDefined; + } + } + } + + unsigned newUsedVectorLength = numDefined + numUndefined; + + if (SparseArrayValueMap* map = m_storage->m_sparseValueMap) { + newUsedVectorLength += map->size(); + if (newUsedVectorLength > m_storage->m_vectorLength) { + // Check that it is possible to allocate an array large enough to hold all the entries. + if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(newUsedVectorLength)) { + throwOutOfMemoryError(exec); + return; + } + } + + SparseArrayValueMap::iterator end = map->end(); + for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) { + tree.abstractor().m_nodes[numDefined].value = it->second; + tree.insert(numDefined); + ++numDefined; + } + + delete map; + m_storage->m_sparseValueMap = 0; + } + + ASSERT(tree.abstractor().m_nodes.size() >= numDefined); + + // FIXME: If the compare function changed the length of the array, the following might be + // modifying the vector incorrectly. + + // Copy the values back into m_storage. + AVLTree<AVLTreeAbstractorForArrayCompare, 44>::Iterator iter; + iter.start_iter_least(tree); + for (unsigned i = 0; i < numDefined; ++i) { + m_storage->m_vector[i] = tree.abstractor().m_nodes[*iter].value; + ++iter; + } + + // Put undefined values back in. + for (unsigned i = numDefined; i < newUsedVectorLength; ++i) + m_storage->m_vector[i] = jsUndefined(); + + // Ensure that unused values in the vector are zeroed out. + for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i) + m_storage->m_vector[i] = JSValue(); + + m_fastAccessCutoff = newUsedVectorLength; + m_storage->m_numValuesInVector = newUsedVectorLength; + + checkConsistency(SortConsistencyCheck); +} + +void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args) +{ + unsigned fastAccessLength = min(m_storage->m_length, m_fastAccessCutoff); + unsigned i = 0; + for (; i < fastAccessLength; ++i) + args.append(getIndex(i)); + for (; i < m_storage->m_length; ++i) + args.append(get(exec, i)); +} + +void JSArray::copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize) +{ + ASSERT(m_storage->m_length == maxSize); + UNUSED_PARAM(maxSize); + unsigned fastAccessLength = min(m_storage->m_length, m_fastAccessCutoff); + unsigned i = 0; + for (; i < fastAccessLength; ++i) + buffer[i] = getIndex(i); + uint32_t size = m_storage->m_length; + for (; i < size; ++i) + buffer[i] = get(exec, i); +} + +unsigned JSArray::compactForSorting() +{ + checkConsistency(); + + ArrayStorage* storage = m_storage; + + unsigned usedVectorLength = min(m_storage->m_length, storage->m_vectorLength); + + unsigned numDefined = 0; + unsigned numUndefined = 0; + + for (; numDefined < usedVectorLength; ++numDefined) { + JSValue v = storage->m_vector[numDefined]; + if (!v || v.isUndefined()) + break; + } + for (unsigned i = numDefined; i < usedVectorLength; ++i) { + JSValue v = storage->m_vector[i]; + if (v) { + if (v.isUndefined()) + ++numUndefined; + else + storage->m_vector[numDefined++] = v; + } + } + + unsigned newUsedVectorLength = numDefined + numUndefined; + + if (SparseArrayValueMap* map = storage->m_sparseValueMap) { + newUsedVectorLength += map->size(); + if (newUsedVectorLength > storage->m_vectorLength) { + // Check that it is possible to allocate an array large enough to hold all the entries - if not, + // exception is thrown by caller. + if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(newUsedVectorLength)) + return 0; + storage = m_storage; + } + + SparseArrayValueMap::iterator end = map->end(); + for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) + storage->m_vector[numDefined++] = it->second; + + delete map; + storage->m_sparseValueMap = 0; + } + + for (unsigned i = numDefined; i < newUsedVectorLength; ++i) + storage->m_vector[i] = jsUndefined(); + for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i) + storage->m_vector[i] = JSValue(); + + m_fastAccessCutoff = newUsedVectorLength; + storage->m_numValuesInVector = newUsedVectorLength; + + checkConsistency(SortConsistencyCheck); + + return numDefined; +} + +void* JSArray::lazyCreationData() +{ + return m_storage->lazyCreationData; +} + +void JSArray::setLazyCreationData(void* d) +{ + m_storage->lazyCreationData = d; +} + +#if CHECK_ARRAY_CONSISTENCY + +void JSArray::checkConsistency(ConsistencyCheckType type) +{ + ASSERT(m_storage); + if (type == SortConsistencyCheck) + ASSERT(!m_storage->m_sparseValueMap); + + ASSERT(m_fastAccessCutoff <= m_storage->m_length); + ASSERT(m_fastAccessCutoff <= m_storage->m_numValuesInVector); + + unsigned numValuesInVector = 0; + for (unsigned i = 0; i < m_storage->m_vectorLength; ++i) { + if (JSValue value = m_storage->m_vector[i]) { + ASSERT(i < m_storage->m_length); + if (type != DestructorConsistencyCheck) + value->type(); // Likely to crash if the object was deallocated. + ++numValuesInVector; + } else { + ASSERT(i >= m_fastAccessCutoff); + if (type == SortConsistencyCheck) + ASSERT(i >= m_storage->m_numValuesInVector); + } + } + ASSERT(numValuesInVector == m_storage->m_numValuesInVector); + + if (m_storage->m_sparseValueMap) { + SparseArrayValueMap::iterator end = m_storage->m_sparseValueMap->end(); + for (SparseArrayValueMap::iterator it = m_storage->m_sparseValueMap->begin(); it != end; ++it) { + unsigned index = it->first; + ASSERT(index < m_storage->m_length); + ASSERT(index >= m_storage->m_vectorLength); + ASSERT(index <= MAX_ARRAY_INDEX); + ASSERT(it->second); + if (type != DestructorConsistencyCheck) + it->second->type(); // Likely to crash if the object was deallocated. + } + } +} + +#endif + +JSArray* constructEmptyArray(ExecState* exec) +{ + return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure()); +} + +JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength) +{ + return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), initialLength); +} + +JSArray* constructArray(ExecState* exec, JSValue singleItemValue) +{ + MarkedArgumentBuffer values; + values.append(singleItemValue); + return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values); +} + +JSArray* constructArray(ExecState* exec, const ArgList& values) +{ + return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSArray.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSArray.h new file mode 100644 index 0000000..73e1711 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSArray.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 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 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 JSArray_h +#define JSArray_h + +#include "JSObject.h" + +namespace JSC { + + typedef HashMap<unsigned, JSValue> SparseArrayValueMap; + + struct ArrayStorage { + unsigned m_length; + unsigned m_vectorLength; + unsigned m_numValuesInVector; + SparseArrayValueMap* m_sparseValueMap; + void* lazyCreationData; // A JSArray subclass can use this to fill the vector lazily. + JSValue m_vector[1]; + }; + + class JSArray : public JSObject { + friend class JIT; + + public: + explicit JSArray(PassRefPtr<Structure>); + JSArray(PassRefPtr<Structure>, unsigned initialLength); + JSArray(PassRefPtr<Structure>, const ArgList& initialValues); + virtual ~JSArray(); + + virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); + virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); + virtual void put(ExecState*, unsigned propertyName, JSValue); // FIXME: Make protected and add setItem. + + static JS_EXPORTDATA const ClassInfo info; + + unsigned length() const { return m_storage->m_length; } + void setLength(unsigned); // OK to use on new arrays, but not if it might be a RegExpMatchArray. + + void sort(ExecState*); + void sort(ExecState*, JSValue compareFunction, CallType, const CallData&); + void sortNumeric(ExecState*, JSValue compareFunction, CallType, const CallData&); + + void push(ExecState*, JSValue); + JSValue pop(); + + bool canGetIndex(unsigned i) { return i < m_fastAccessCutoff; } + JSValue getIndex(unsigned i) + { + ASSERT(canGetIndex(i)); + return m_storage->m_vector[i]; + } + + bool canSetIndex(unsigned i) { return i < m_fastAccessCutoff; } + JSValue setIndex(unsigned i, JSValue v) + { + ASSERT(canSetIndex(i)); + return m_storage->m_vector[i] = v; + } + + void fillArgList(ExecState*, MarkedArgumentBuffer&); + void copyToRegisters(ExecState*, Register*, uint32_t); + + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType)); + } + + protected: + virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); + virtual bool deleteProperty(ExecState*, const Identifier& propertyName, bool checkDontDelete = true); + virtual bool deleteProperty(ExecState*, unsigned propertyName, bool checkDontDelete = true); + virtual void getPropertyNames(ExecState*, PropertyNameArray&, unsigned listedAttributes = Structure::Prototype); + virtual void mark(); + + void* lazyCreationData(); + void setLazyCreationData(void*); + + private: + virtual const ClassInfo* classInfo() const { return &info; } + + bool getOwnPropertySlotSlowCase(ExecState*, unsigned propertyName, PropertySlot&); + void putSlowCase(ExecState*, unsigned propertyName, JSValue); + + bool increaseVectorLength(unsigned newLength); + + unsigned compactForSorting(); + + enum ConsistencyCheckType { NormalConsistencyCheck, DestructorConsistencyCheck, SortConsistencyCheck }; + void checkConsistency(ConsistencyCheckType = NormalConsistencyCheck); + + unsigned m_fastAccessCutoff; + ArrayStorage* m_storage; + }; + + JSArray* asArray(JSValue); + + JSArray* constructEmptyArray(ExecState*); + JSArray* constructEmptyArray(ExecState*, unsigned initialLength); + JSArray* constructArray(ExecState*, JSValue singleItemValue); + JSArray* constructArray(ExecState*, const ArgList& values); + + inline JSArray* asArray(JSValue value) + { + ASSERT(asObject(value)->inherits(&JSArray::info)); + return static_cast<JSArray*>(asObject(value)); + } + + inline bool isJSArray(JSGlobalData* globalData, JSValue v) { return v.isCell() && v.asCell()->vptr() == globalData->jsArrayVPtr; } + +} // namespace JSC + +#endif // JSArray_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSByteArray.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSByteArray.cpp new file mode 100644 index 0000000..d00b69c --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSByteArray.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSByteArray.h" + +#include "JSGlobalObject.h" +#include "PropertyNameArray.h" + +using namespace WTF; + +namespace JSC { + +const ClassInfo JSByteArray::s_defaultInfo = { "ByteArray", 0, 0, 0 }; + +JSByteArray::JSByteArray(ExecState* exec, PassRefPtr<Structure> structure, ByteArray* storage, const JSC::ClassInfo* classInfo) + : JSObject(structure) + , m_storage(storage) + , m_classInfo(classInfo) +{ + putDirect(exec->globalData().propertyNames->length, jsNumber(exec, m_storage->length()), ReadOnly | DontDelete); +} + +PassRefPtr<Structure> JSByteArray::createStructure(JSValue prototype) +{ + PassRefPtr<Structure> result = Structure::create(prototype, TypeInfo(ObjectType)); + return result; +} + +bool JSByteArray::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +{ + bool ok; + unsigned index = propertyName.toUInt32(&ok, false); + if (ok && canAccessIndex(index)) { + slot.setValue(getIndex(exec, index)); + return true; + } + return JSObject::getOwnPropertySlot(exec, propertyName, slot); +} + +bool JSByteArray::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) +{ + if (canAccessIndex(propertyName)) { + slot.setValue(getIndex(exec, propertyName)); + return true; + } + return JSObject::getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot); +} + +void JSByteArray::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) +{ + bool ok; + unsigned index = propertyName.toUInt32(&ok, false); + if (ok) { + setIndex(exec, index, value); + return; + } + JSObject::put(exec, propertyName, value, slot); +} + +void JSByteArray::put(ExecState* exec, unsigned propertyName, JSValue value) +{ + setIndex(exec, propertyName, value); +} + +void JSByteArray::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, unsigned listedAttributes) +{ + unsigned length = m_storage->length(); + for (unsigned i = 0; i < length; ++i) + propertyNames.add(Identifier::from(exec, i)); + JSObject::getPropertyNames(exec, propertyNames, listedAttributes); +} + +} + diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSByteArray.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSByteArray.h new file mode 100644 index 0000000..c43c3ea --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSByteArray.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSByteArray_h +#define JSByteArray_h + +#include "JSObject.h" + +#include <wtf/ByteArray.h> + +namespace JSC { + + class JSByteArray : public JSObject { + friend class VPtrSet; + public: + bool canAccessIndex(unsigned i) { return i < m_storage->length(); } + JSValue getIndex(ExecState* exec, unsigned i) + { + ASSERT(canAccessIndex(i)); + return jsNumber(exec, m_storage->data()[i]); + } + + void setIndex(unsigned i, int value) + { + ASSERT(canAccessIndex(i)); + if (value & ~0xFF) { + if (value < 0) + value = 0; + else + value = 255; + } + m_storage->data()[i] = static_cast<unsigned char>(value); + } + + void setIndex(unsigned i, double value) + { + ASSERT(canAccessIndex(i)); + if (!(value > 0)) // Clamp NaN to 0 + value = 0; + else if (value > 255) + value = 255; + m_storage->data()[i] = static_cast<unsigned char>(value + 0.5); + } + + void setIndex(ExecState* exec, unsigned i, JSValue value) + { + double byteValue = value.toNumber(exec); + if (exec->hadException()) + return; + if (canAccessIndex(i)) + setIndex(i, byteValue); + } + + JSByteArray(ExecState* exec, PassRefPtr<Structure>, WTF::ByteArray* storage, const JSC::ClassInfo* = &s_defaultInfo); + static PassRefPtr<Structure> createStructure(JSValue prototype); + + virtual bool getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot&); + virtual bool getOwnPropertySlot(JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&); + virtual void put(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSValue, JSC::PutPropertySlot&); + virtual void put(JSC::ExecState*, unsigned propertyName, JSC::JSValue); + + virtual void getPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&, unsigned listedAttributes = Structure::Prototype); + + virtual const ClassInfo* classInfo() const { return m_classInfo; } + static const ClassInfo s_defaultInfo; + + size_t length() const { return m_storage->length(); } + + WTF::ByteArray* storage() const { return m_storage.get(); } + + private: + enum VPtrStealingHackType { VPtrStealingHack }; + JSByteArray(VPtrStealingHackType) + : JSObject(createStructure(jsNull())) + , m_classInfo(0) + { + } + + RefPtr<WTF::ByteArray> m_storage; + const ClassInfo* m_classInfo; + }; + + JSByteArray* asByteArray(JSValue value); + inline JSByteArray* asByteArray(JSValue value) + { + return static_cast<JSByteArray*>(asCell(value)); + } + + inline bool isJSByteArray(JSGlobalData* globalData, JSValue v) { return v.isCell() && v.asCell()->vptr() == globalData->jsByteArrayVPtr; } + +} // namespace JSC + +#endif // JSByteArray_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSCell.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSCell.cpp new file mode 100644 index 0000000..10a91f7 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSCell.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "JSCell.h" + +#include "JSFunction.h" +#include "JSString.h" +#include "JSObject.h" +#include <wtf/MathExtras.h> + +namespace JSC { + +#if defined NAN && defined INFINITY + +extern const double NaN = NAN; +extern const double Inf = INFINITY; + +#else // !(defined NAN && defined INFINITY) + +// The trick is to define the NaN and Inf globals with a different type than the declaration. +// This trick works because the mangled name of the globals does not include the type, although +// I'm not sure that's guaranteed. There could be alignment issues with this, since arrays of +// characters don't necessarily need the same alignment doubles do, but for now it seems to work. +// It would be good to figure out a 100% clean way that still avoids code that runs at init time. + +// Note, we have to use union to ensure alignment. Otherwise, NaN_Bytes can start anywhere, +// while NaN_double has to be 4-byte aligned for 32-bits. +// With -fstrict-aliasing enabled, unions are the only safe way to do type masquerading. + +static const union { + struct { + unsigned char NaN_Bytes[8]; + unsigned char Inf_Bytes[8]; + } bytes; + + struct { + double NaN_Double; + double Inf_Double; + } doubles; + +} NaNInf = { { +#if PLATFORM(BIG_ENDIAN) + { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 }, + { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 } +#elif PLATFORM(MIDDLE_ENDIAN) + { 0, 0, 0xf8, 0x7f, 0, 0, 0, 0 }, + { 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 } +#else + { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f }, + { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f } +#endif +} } ; + +extern const double NaN = NaNInf.doubles.NaN_Double; +extern const double Inf = NaNInf.doubles.Inf_Double; + +#endif // !(defined NAN && defined INFINITY) + +void* JSCell::operator new(size_t size, ExecState* exec) +{ +#ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE + return exec->heap()->inlineAllocate(size); +#else + return exec->heap()->allocate(size); +#endif +} + +bool JSCell::getUInt32(uint32_t&) const +{ + return false; +} + +bool JSCell::getTruncatedInt32(int32_t&) const +{ + return false; +} + +bool JSCell::getTruncatedUInt32(uint32_t&) const +{ + return false; +} + +bool JSCell::getString(UString&stringValue) const +{ + if (!isString()) + return false; + stringValue = static_cast<const JSString*>(this)->value(); + return true; +} + +UString JSCell::getString() const +{ + return isString() ? static_cast<const JSString*>(this)->value() : UString(); +} + +JSObject* JSCell::getObject() +{ + return isObject() ? static_cast<JSObject*>(this) : 0; +} + +const JSObject* JSCell::getObject() const +{ + return isObject() ? static_cast<const JSObject*>(this) : 0; +} + +CallType JSCell::getCallData(CallData&) +{ + return CallTypeNone; +} + +ConstructType JSCell::getConstructData(ConstructData&) +{ + return ConstructTypeNone; +} + +bool JSCell::getOwnPropertySlot(ExecState* exec, const Identifier& identifier, PropertySlot& slot) +{ + // This is not a general purpose implementation of getOwnPropertySlot. + // It should only be called by JSValue::get. + // It calls getPropertySlot, not getOwnPropertySlot. + JSObject* object = toObject(exec); + slot.setBase(object); + if (!object->getPropertySlot(exec, identifier, slot)) + slot.setUndefined(); + return true; +} + +bool JSCell::getOwnPropertySlot(ExecState* exec, unsigned identifier, PropertySlot& slot) +{ + // This is not a general purpose implementation of getOwnPropertySlot. + // It should only be called by JSValue::get. + // It calls getPropertySlot, not getOwnPropertySlot. + JSObject* object = toObject(exec); + slot.setBase(object); + if (!object->getPropertySlot(exec, identifier, slot)) + slot.setUndefined(); + return true; +} + +void JSCell::put(ExecState* exec, const Identifier& identifier, JSValue value, PutPropertySlot& slot) +{ + toObject(exec)->put(exec, identifier, value, slot); +} + +void JSCell::put(ExecState* exec, unsigned identifier, JSValue value) +{ + toObject(exec)->put(exec, identifier, value); +} + +bool JSCell::deleteProperty(ExecState* exec, const Identifier& identifier, bool checkDontDelete) +{ + return toObject(exec)->deleteProperty(exec, identifier, checkDontDelete); +} + +bool JSCell::deleteProperty(ExecState* exec, unsigned identifier, bool checkDontDelete) +{ + return toObject(exec)->deleteProperty(exec, identifier, checkDontDelete); +} + +JSObject* JSCell::toThisObject(ExecState* exec) const +{ + return toObject(exec); +} + +UString JSCell::toThisString(ExecState* exec) const +{ + return toThisObject(exec)->toString(exec); +} + +JSString* JSCell::toThisJSString(ExecState* exec) +{ + return jsString(exec, toThisString(exec)); +} + +const ClassInfo* JSCell::classInfo() const +{ + return 0; +} + +JSValue JSCell::getJSNumber() +{ + return JSValue(); +} + +bool JSCell::isGetterSetter() const +{ + return false; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSCell.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSCell.h new file mode 100644 index 0000000..4743baf --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSCell.h @@ -0,0 +1,300 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003, 2004, 2005, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef JSCell_h +#define JSCell_h + +#include <wtf/Noncopyable.h> +#include "Structure.h" +#include "JSValue.h" +#include "JSImmediate.h" +#include "Collector.h" + +namespace JSC { + + class JSCell : public NoncopyableCustomAllocated { + friend class GetterSetter; + friend class Heap; + friend class JIT; + friend class JSNumberCell; + friend class JSObject; + friend class JSPropertyNameIterator; + friend class JSString; + friend class JSValue; + friend class VPtrSet; + + private: + explicit JSCell(Structure*); + virtual ~JSCell(); + + public: + // Querying the type. + bool isNumber() const; + bool isString() const; + bool isObject() const; + virtual bool isGetterSetter() const; + virtual bool isObject(const ClassInfo*) const; + + Structure* structure() const; + + // Extracting the value. + bool getString(UString&) const; + UString getString() const; // null string if not a string + JSObject* getObject(); // NULL if not an object + const JSObject* getObject() const; // NULL if not an object + + virtual CallType getCallData(CallData&); + virtual ConstructType getConstructData(ConstructData&); + + // Extracting integer values. + // FIXME: remove these methods, can check isNumberCell in JSValue && then call asNumberCell::*. + virtual bool getUInt32(uint32_t&) const; + virtual bool getTruncatedInt32(int32_t&) const; + virtual bool getTruncatedUInt32(uint32_t&) const; + + // Basic conversions. + virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const = 0; + virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue&) = 0; + virtual bool toBoolean(ExecState*) const = 0; + virtual double toNumber(ExecState*) const = 0; + virtual UString toString(ExecState*) const = 0; + virtual JSObject* toObject(ExecState*) const = 0; + + // Garbage collection. + void* operator new(size_t, ExecState*); + void* operator new(size_t, JSGlobalData*); + void* operator new(size_t, void* placementNewDestination) { return placementNewDestination; } + virtual void mark(); + bool marked() const; + + // Object operations, with the toObject operation included. + virtual const ClassInfo* classInfo() const; + virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); + virtual void put(ExecState*, unsigned propertyName, JSValue); + virtual bool deleteProperty(ExecState*, const Identifier& propertyName, bool checkDontDelete = true); + virtual bool deleteProperty(ExecState*, unsigned propertyName, bool checkDontDelete = true); + + virtual JSObject* toThisObject(ExecState*) const; + virtual UString toThisString(ExecState*) const; + virtual JSString* toThisJSString(ExecState*); + virtual JSValue getJSNumber(); + void* vptr() { return *reinterpret_cast<void**>(this); } + + private: + // Base implementation; for non-object classes implements getPropertySlot. + bool fastGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); + virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); + virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); + + Structure* m_structure; + }; + + JSCell* asCell(JSValue); + + inline JSCell* asCell(JSValue value) + { + return value.asCell(); + } + + inline JSCell::JSCell(Structure* structure) + : m_structure(structure) + { + } + + inline JSCell::~JSCell() + { + } + + inline bool JSCell::isNumber() const + { + return Heap::isNumber(const_cast<JSCell*>(this)); + } + + inline bool JSCell::isObject() const + { + return m_structure->typeInfo().type() == ObjectType; + } + + inline bool JSCell::isString() const + { + return m_structure->typeInfo().type() == StringType; + } + + inline Structure* JSCell::structure() const + { + return m_structure; + } + + inline bool JSCell::marked() const + { + return Heap::isCellMarked(this); + } + + inline void JSCell::mark() + { + return Heap::markCell(this); + } + + ALWAYS_INLINE JSCell* JSValue::asCell() const + { + ASSERT(isCell()); + return m_ptr; + } + + inline void* JSCell::operator new(size_t size, JSGlobalData* globalData) + { +#ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE + return globalData->heap.inlineAllocate(size); +#else + return globalData->heap.allocate(size); +#endif + } + + // --- JSValue inlines ---------------------------- + + inline bool JSValue::isString() const + { + return !JSImmediate::isImmediate(asValue()) && asCell()->isString(); + } + + inline bool JSValue::isGetterSetter() const + { + return !JSImmediate::isImmediate(asValue()) && asCell()->isGetterSetter(); + } + + inline bool JSValue::isObject() const + { + return !JSImmediate::isImmediate(asValue()) && asCell()->isObject(); + } + + inline bool JSValue::getString(UString& s) const + { + return !JSImmediate::isImmediate(asValue()) && asCell()->getString(s); + } + + inline UString JSValue::getString() const + { + return JSImmediate::isImmediate(asValue()) ? UString() : asCell()->getString(); + } + + inline JSObject* JSValue::getObject() const + { + return JSImmediate::isImmediate(asValue()) ? 0 : asCell()->getObject(); + } + + inline CallType JSValue::getCallData(CallData& callData) + { + return JSImmediate::isImmediate(asValue()) ? CallTypeNone : asCell()->getCallData(callData); + } + + inline ConstructType JSValue::getConstructData(ConstructData& constructData) + { + return JSImmediate::isImmediate(asValue()) ? ConstructTypeNone : asCell()->getConstructData(constructData); + } + + ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const + { + return JSImmediate::isImmediate(asValue()) ? JSImmediate::getUInt32(asValue(), v) : asCell()->getUInt32(v); + } + + ALWAYS_INLINE bool JSValue::getTruncatedInt32(int32_t& v) const + { + return JSImmediate::isImmediate(asValue()) ? JSImmediate::getTruncatedInt32(asValue(), v) : asCell()->getTruncatedInt32(v); + } + + inline bool JSValue::getTruncatedUInt32(uint32_t& v) const + { + return JSImmediate::isImmediate(asValue()) ? JSImmediate::getTruncatedUInt32(asValue(), v) : asCell()->getTruncatedUInt32(v); + } + + inline void JSValue::mark() + { + asCell()->mark(); // callers should check !marked() before calling mark(), so this should only be called with cells + } + + inline bool JSValue::marked() const + { + return JSImmediate::isImmediate(asValue()) || asCell()->marked(); + } + + inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const + { + return JSImmediate::isImmediate(asValue()) ? asValue() : asCell()->toPrimitive(exec, preferredType); + } + + inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value) + { + if (JSImmediate::isImmediate(asValue())) { + number = JSImmediate::toDouble(asValue()); + value = asValue(); + return true; + } + return asCell()->getPrimitiveNumber(exec, number, value); + } + + inline bool JSValue::toBoolean(ExecState* exec) const + { + return JSImmediate::isImmediate(asValue()) ? JSImmediate::toBoolean(asValue()) : asCell()->toBoolean(exec); + } + + ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const + { + return JSImmediate::isImmediate(asValue()) ? JSImmediate::toDouble(asValue()) : asCell()->toNumber(exec); + } + + inline UString JSValue::toString(ExecState* exec) const + { + return JSImmediate::isImmediate(asValue()) ? JSImmediate::toString(asValue()) : asCell()->toString(exec); + } + + inline JSObject* JSValue::toObject(ExecState* exec) const + { + return JSImmediate::isImmediate(asValue()) ? JSImmediate::toObject(asValue(), exec) : asCell()->toObject(exec); + } + + inline JSObject* JSValue::toThisObject(ExecState* exec) const + { + if (UNLIKELY(JSImmediate::isImmediate(asValue()))) + return JSImmediate::toThisObject(asValue(), exec); + return asCell()->toThisObject(exec); + } + + inline bool JSValue::needsThisConversion() const + { + if (UNLIKELY(JSImmediate::isImmediate(asValue()))) + return true; + return asCell()->structure()->typeInfo().needsThisConversion(); + } + + inline UString JSValue::toThisString(ExecState* exec) const + { + return JSImmediate::isImmediate(asValue()) ? JSImmediate::toString(asValue()) : asCell()->toThisString(exec); + } + + inline JSValue JSValue::getJSNumber() + { + return JSImmediate::isNumber(asValue()) ? asValue() : JSImmediate::isImmediate(asValue()) ? JSValue() : asCell()->getJSNumber(); + } + +} // namespace JSC + +#endif // JSCell_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSFunction.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSFunction.cpp new file mode 100644 index 0000000..c8e137e --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSFunction.cpp @@ -0,0 +1,215 @@ +/* + * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) + * Copyright (C) 2007 Maks Orlovich + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "JSFunction.h" + +#include "CodeBlock.h" +#include "CommonIdentifiers.h" +#include "CallFrame.h" +#include "FunctionPrototype.h" +#include "JSGlobalObject.h" +#include "Interpreter.h" +#include "ObjectPrototype.h" +#include "Parser.h" +#include "PropertyNameArray.h" +#include "ScopeChainMark.h" + +using namespace WTF; +using namespace Unicode; + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(JSFunction); + +const ClassInfo JSFunction::info = { "Function", &InternalFunction::info, 0, 0 }; + +JSFunction::JSFunction(ExecState* exec, PassRefPtr<Structure> structure, int length, const Identifier& name, NativeFunction func) + : Base(&exec->globalData(), structure, name) +#if ENABLE(JIT) + , m_body(FunctionBodyNode::createNativeThunk(&exec->globalData())) +#else + , m_body(0) +#endif +{ +#if ENABLE(JIT) + setNativeFunction(func); + putDirect(exec->propertyNames().length, jsNumber(exec, length), DontDelete | ReadOnly | DontEnum); +#else + UNUSED_PARAM(length); + UNUSED_PARAM(func); + ASSERT_NOT_REACHED(); +#endif +} + +JSFunction::JSFunction(ExecState* exec, const Identifier& name, FunctionBodyNode* body, ScopeChainNode* scopeChainNode) + : Base(&exec->globalData(), exec->lexicalGlobalObject()->functionStructure(), name) + , m_body(body) +{ + setScopeChain(scopeChainNode); +} + +JSFunction::~JSFunction() +{ +#if ENABLE(JIT) + // JIT code for other functions may have had calls linked directly to the code for this function; these links + // are based on a check for the this pointer value for this JSFunction - which will no longer be valid once + // this memory is freed and may be reused (potentially for another, different JSFunction). + if (m_body && m_body->isGenerated()) + m_body->generatedBytecode().unlinkCallers(); +#endif + if (!isHostFunction()) + scopeChain().~ScopeChain(); +} + +void JSFunction::mark() +{ + Base::mark(); + m_body->mark(); + if (!isHostFunction()) + scopeChain().mark(); +} + +CallType JSFunction::getCallData(CallData& callData) +{ + if (isHostFunction()) { + callData.native.function = nativeFunction(); + return CallTypeHost; + } + callData.js.functionBody = m_body.get(); + callData.js.scopeChain = scopeChain().node(); + return CallTypeJS; +} + +JSValue JSFunction::call(ExecState* exec, JSValue thisValue, const ArgList& args) +{ + ASSERT(!isHostFunction()); + return exec->interpreter()->execute(m_body.get(), exec, this, thisValue.toThisObject(exec), args, scopeChain().node(), exec->exceptionSlot()); +} + +JSValue JSFunction::argumentsGetter(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + JSFunction* thisObj = asFunction(slot.slotBase()); + ASSERT(!thisObj->isHostFunction()); + return exec->interpreter()->retrieveArguments(exec, thisObj); +} + +JSValue JSFunction::callerGetter(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + JSFunction* thisObj = asFunction(slot.slotBase()); + ASSERT(!thisObj->isHostFunction()); + return exec->interpreter()->retrieveCaller(exec, thisObj); +} + +JSValue JSFunction::lengthGetter(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + JSFunction* thisObj = asFunction(slot.slotBase()); + ASSERT(!thisObj->isHostFunction()); + return jsNumber(exec, thisObj->m_body->parameterCount()); +} + +bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +{ + if (isHostFunction()) + return Base::getOwnPropertySlot(exec, propertyName, slot); + + if (propertyName == exec->propertyNames().prototype) { + JSValue* location = getDirectLocation(propertyName); + + if (!location) { + JSObject* prototype = new (exec) JSObject(scopeChain().globalObject()->emptyObjectStructure()); + prototype->putDirect(exec->propertyNames().constructor, this, DontEnum); + putDirect(exec->propertyNames().prototype, prototype, DontDelete); + location = getDirectLocation(propertyName); + } + + slot.setValueSlot(this, location, offsetForLocation(location)); + } + + if (propertyName == exec->propertyNames().arguments) { + slot.setCustom(this, argumentsGetter); + return true; + } + + if (propertyName == exec->propertyNames().length) { + slot.setCustom(this, lengthGetter); + return true; + } + + if (propertyName == exec->propertyNames().caller) { + slot.setCustom(this, callerGetter); + return true; + } + + return Base::getOwnPropertySlot(exec, propertyName, slot); +} + +void JSFunction::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) +{ + if (isHostFunction()) { + Base::put(exec, propertyName, value, slot); + return; + } + if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length) + return; + Base::put(exec, propertyName, value, slot); +} + +bool JSFunction::deleteProperty(ExecState* exec, const Identifier& propertyName, bool checkDontDelete) +{ + if (isHostFunction()) + return Base::deleteProperty(exec, propertyName, checkDontDelete); + if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length) + return false; + return Base::deleteProperty(exec, propertyName, checkDontDelete); +} + +// ECMA 13.2.2 [[Construct]] +ConstructType JSFunction::getConstructData(ConstructData& constructData) +{ + if (isHostFunction()) + return ConstructTypeNone; + constructData.js.functionBody = m_body.get(); + constructData.js.scopeChain = scopeChain().node(); + return ConstructTypeJS; +} + +JSObject* JSFunction::construct(ExecState* exec, const ArgList& args) +{ + ASSERT(!isHostFunction()); + Structure* structure; + JSValue prototype = get(exec, exec->propertyNames().prototype); + if (prototype.isObject()) + structure = asObject(prototype)->inheritorID(); + else + structure = exec->lexicalGlobalObject()->emptyObjectStructure(); + JSObject* thisObj = new (exec) JSObject(structure); + + JSValue result = exec->interpreter()->execute(m_body.get(), exec, this, thisObj, args, scopeChain().node(), exec->exceptionSlot()); + if (exec->hadException() || !result.isObject()) + return thisObj; + return asObject(result); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSFunction.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSFunction.h new file mode 100644 index 0000000..5ddd97c --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSFunction.h @@ -0,0 +1,138 @@ +/* + * 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 JSFunction_h +#define JSFunction_h + +#include "InternalFunction.h" +#include "JSVariableObject.h" +#include "SymbolTable.h" +#include "Nodes.h" +#include "JSObject.h" + +namespace JSC { + + class FunctionBodyNode; + class FunctionPrototype; + class JSActivation; + class JSGlobalObject; + + class JSFunction : public InternalFunction { + friend class JIT; + friend class VPtrSet; + + typedef InternalFunction Base; + + JSFunction(PassRefPtr<Structure> structure) + : InternalFunction(structure) + { + clearScopeChain(); + } + + public: + JSFunction(ExecState*, PassRefPtr<Structure>, int length, const Identifier&, NativeFunction); + JSFunction(ExecState*, const Identifier&, FunctionBodyNode*, ScopeChainNode*); + ~JSFunction(); + + virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); + virtual bool deleteProperty(ExecState*, const Identifier& propertyName, bool checkDontDelete = true); + + JSObject* construct(ExecState*, const ArgList&); + JSValue call(ExecState*, JSValue thisValue, const ArgList&); + + void setScope(const ScopeChain& scopeChain) { setScopeChain(scopeChain); } + ScopeChain& scope() { return scopeChain(); } + + void setBody(FunctionBodyNode* body) { m_body = body; } + void setBody(PassRefPtr<FunctionBodyNode> body) { m_body = body; } + FunctionBodyNode* body() const { return m_body.get(); } + + virtual void mark(); + + static JS_EXPORTDATA const ClassInfo info; + + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType, ImplementsHasInstance)); + } + +#if ENABLE(JIT) + bool isHostFunction() const { return m_body && m_body->isHostFunction(); } +#else + bool isHostFunction() const { return false; } +#endif + NativeFunction nativeFunction() + { + return *reinterpret_cast<NativeFunction*>(m_data); + } + + virtual ConstructType getConstructData(ConstructData&); + virtual CallType getCallData(CallData&); + + private: + virtual const ClassInfo* classInfo() const { return &info; } + + static JSValue argumentsGetter(ExecState*, const Identifier&, const PropertySlot&); + static JSValue callerGetter(ExecState*, const Identifier&, const PropertySlot&); + static JSValue lengthGetter(ExecState*, const Identifier&, const PropertySlot&); + + RefPtr<FunctionBodyNode> m_body; + ScopeChain& scopeChain() + { + ASSERT(!isHostFunction()); + return *reinterpret_cast<ScopeChain*>(m_data); + } + void clearScopeChain() + { + ASSERT(!isHostFunction()); + new (m_data) ScopeChain(NoScopeChain()); + } + void setScopeChain(ScopeChainNode* sc) + { + ASSERT(!isHostFunction()); + new (m_data) ScopeChain(sc); + } + void setScopeChain(const ScopeChain& sc) + { + ASSERT(!isHostFunction()); + *reinterpret_cast<ScopeChain*>(m_data) = sc; + } + void setNativeFunction(NativeFunction func) + { + *reinterpret_cast<NativeFunction*>(m_data) = func; + } + unsigned char m_data[sizeof(void*)]; + }; + + JSFunction* asFunction(JSValue); + + inline JSFunction* asFunction(JSValue value) + { + ASSERT(asObject(value)->inherits(&JSFunction::info)); + return static_cast<JSFunction*>(asObject(value)); + } + +} // namespace JSC + +#endif // JSFunction_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.cpp new file mode 100644 index 0000000..85d881e --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.cpp @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSGlobalData.h" + +#include "ArgList.h" +#include "Collector.h" +#include "CommonIdentifiers.h" +#include "FunctionConstructor.h" +#include "Interpreter.h" +#include "JSActivation.h" +#include "JSArray.h" +#include "JSByteArray.h" +#include "JSClassRef.h" +#include "JSFunction.h" +#include "JSLock.h" +#include "JSNotAnObject.h" +#include "JSStaticScopeObject.h" +#include "Parser.h" +#include "Lexer.h" +#include "Lookup.h" +#include "Nodes.h" + +#if ENABLE(JSC_MULTIPLE_THREADS) +#include <wtf/Threading.h> +#endif + +#if PLATFORM(MAC) +#include "ProfilerServer.h" +#endif + +using namespace WTF; + +namespace JSC { + +extern JSC_CONST_HASHTABLE HashTable arrayTable; +extern JSC_CONST_HASHTABLE HashTable jsonTable; +extern JSC_CONST_HASHTABLE HashTable dateTable; +extern JSC_CONST_HASHTABLE HashTable mathTable; +extern JSC_CONST_HASHTABLE HashTable numberTable; +extern JSC_CONST_HASHTABLE HashTable regExpTable; +extern JSC_CONST_HASHTABLE HashTable regExpConstructorTable; +extern JSC_CONST_HASHTABLE HashTable stringTable; + +struct VPtrSet { + VPtrSet(); + + void* jsArrayVPtr; + void* jsByteArrayVPtr; + void* jsStringVPtr; + void* jsFunctionVPtr; +}; + +VPtrSet::VPtrSet() +{ + // Bizarrely, calling fastMalloc here is faster than allocating space on the stack. + void* storage = fastMalloc(sizeof(CollectorBlock)); + + JSCell* jsArray = new (storage) JSArray(JSArray::createStructure(jsNull())); + jsArrayVPtr = jsArray->vptr(); + jsArray->~JSCell(); + + JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack); + jsByteArrayVPtr = jsByteArray->vptr(); + jsByteArray->~JSCell(); + + JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack); + jsStringVPtr = jsString->vptr(); + jsString->~JSCell(); + + JSCell* jsFunction = new (storage) JSFunction(JSFunction::createStructure(jsNull())); + jsFunctionVPtr = jsFunction->vptr(); + jsFunction->~JSCell(); + + fastFree(storage); +} + +JSGlobalData::JSGlobalData(bool isShared, const VPtrSet& vptrSet) + : isSharedInstance(isShared) + , clientData(0) + , arrayTable(fastNew<HashTable>(JSC::arrayTable)) + , dateTable(fastNew<HashTable>(JSC::dateTable)) + , jsonTable(fastNew<HashTable>(JSC::jsonTable)) + , mathTable(fastNew<HashTable>(JSC::mathTable)) + , numberTable(fastNew<HashTable>(JSC::numberTable)) + , regExpTable(fastNew<HashTable>(JSC::regExpTable)) + , regExpConstructorTable(fastNew<HashTable>(JSC::regExpConstructorTable)) + , stringTable(fastNew<HashTable>(JSC::stringTable)) + , activationStructure(JSActivation::createStructure(jsNull())) + , interruptedExecutionErrorStructure(JSObject::createStructure(jsNull())) + , staticScopeStructure(JSStaticScopeObject::createStructure(jsNull())) + , stringStructure(JSString::createStructure(jsNull())) + , notAnObjectErrorStubStructure(JSNotAnObjectErrorStub::createStructure(jsNull())) + , notAnObjectStructure(JSNotAnObject::createStructure(jsNull())) +#if !USE(ALTERNATE_JSIMMEDIATE) + , numberStructure(JSNumberCell::createStructure(jsNull())) +#endif + , jsArrayVPtr(vptrSet.jsArrayVPtr) + , jsByteArrayVPtr(vptrSet.jsByteArrayVPtr) + , jsStringVPtr(vptrSet.jsStringVPtr) + , jsFunctionVPtr(vptrSet.jsFunctionVPtr) + , identifierTable(createIdentifierTable()) + , propertyNames(new CommonIdentifiers(this)) + , emptyList(new MarkedArgumentBuffer) + , lexer(new Lexer(this)) + , parser(new Parser) + , interpreter(new Interpreter) +#if ENABLE(JIT) + , jitStubs(this) +#endif + , timeoutChecker(new TimeoutChecker) + , heap(this) + , initializingLazyNumericCompareFunction(false) + , head(0) + , dynamicGlobalObject(0) + , scopeNodeBeingReparsed(0) + , firstStringifierToMark(0) +{ +#ifdef QT_BUILD_SCRIPT_LIB + scriptpool = new SourcePool(); +#endif +#if PLATFORM(MAC) + startProfilerServerIfNeeded(); +#endif +} + +JSGlobalData::~JSGlobalData() +{ + // By the time this is destroyed, heap.destroy() must already have been called. + + delete interpreter; +#ifndef NDEBUG + // Zeroing out to make the behavior more predictable when someone attempts to use a deleted instance. + interpreter = 0; +#endif + + arrayTable->deleteTable(); + dateTable->deleteTable(); + jsonTable->deleteTable(); + mathTable->deleteTable(); + numberTable->deleteTable(); + regExpTable->deleteTable(); + regExpConstructorTable->deleteTable(); + stringTable->deleteTable(); + + fastDelete(const_cast<HashTable*>(arrayTable)); + fastDelete(const_cast<HashTable*>(dateTable)); + fastDelete(const_cast<HashTable*>(jsonTable)); + fastDelete(const_cast<HashTable*>(mathTable)); + fastDelete(const_cast<HashTable*>(numberTable)); + fastDelete(const_cast<HashTable*>(regExpTable)); + fastDelete(const_cast<HashTable*>(regExpConstructorTable)); + fastDelete(const_cast<HashTable*>(stringTable)); + + delete parser; + delete lexer; + delete timeoutChecker; + + deleteAllValues(opaqueJSClassData); + + delete emptyList; + + delete propertyNames; + deleteIdentifierTable(identifierTable); + + delete clientData; +#ifdef QT_BUILD_SCRIPT_LIB + if (scriptpool) + delete scriptpool; +#endif +} + +PassRefPtr<JSGlobalData> JSGlobalData::create(bool isShared) +{ + return adoptRef(new JSGlobalData(isShared, VPtrSet())); +} + +PassRefPtr<JSGlobalData> JSGlobalData::createLeaked() +{ + Structure::startIgnoringLeaks(); + RefPtr<JSGlobalData> data = create(); + Structure::stopIgnoringLeaks(); + return data.release(); +} + +bool JSGlobalData::sharedInstanceExists() +{ + return sharedInstanceInternal(); +} + +JSGlobalData& JSGlobalData::sharedInstance() +{ + JSGlobalData*& instance = sharedInstanceInternal(); + if (!instance) { + instance = create(true).releaseRef(); +#if ENABLE(JSC_MULTIPLE_THREADS) + instance->makeUsableFromMultipleThreads(); +#endif + } + return *instance; +} + +JSGlobalData*& JSGlobalData::sharedInstanceInternal() +{ + ASSERT(JSLock::currentThreadIsHoldingLock()); + static JSGlobalData* sharedInstance; + return sharedInstance; +} + +// FIXME: We can also detect forms like v1 < v2 ? -1 : 0, reverse comparison, etc. +const Vector<Instruction>& JSGlobalData::numericCompareFunction(ExecState* exec) +{ + if (!lazyNumericCompareFunction.size() && !initializingLazyNumericCompareFunction) { + initializingLazyNumericCompareFunction = true; + RefPtr<ProgramNode> programNode = parser->parse<ProgramNode>(exec, 0, makeSource(UString("(function (v1, v2) { return v1 - v2; })")), 0, 0); + RefPtr<FunctionBodyNode> functionBody = extractFunctionBody(programNode.get()); + lazyNumericCompareFunction = functionBody->bytecode(exec->scopeChain()).instructions(); + initializingLazyNumericCompareFunction = false; + } + + return lazyNumericCompareFunction; +} + +JSGlobalData::ClientData::~ClientData() +{ +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.h new file mode 100644 index 0000000..fb557af --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.h @@ -0,0 +1,164 @@ +/* + * 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. + */ + +#ifndef JSGlobalData_h +#define JSGlobalData_h + +#include "Collector.h" +#include "ExecutableAllocator.h" +#include "JITStubs.h" +#include "JSValue.h" +#include "SmallStrings.h" +#include "TimeoutChecker.h" +#include <wtf/Forward.h> +#include <wtf/HashMap.h> +#include <wtf/RefCounted.h> + +#ifdef QT_BUILD_SCRIPT_LIB +#include "SourcePoolQt.h" +#endif + +struct OpaqueJSClass; +struct OpaqueJSClassContextData; + +namespace JSC { + + class CommonIdentifiers; + class FunctionBodyNode; + class IdentifierTable; + class Instruction; + class Interpreter; + class JSGlobalObject; + class JSObject; + class Lexer; + class Parser; + class ScopeNode; + class Stringifier; + class Structure; + class UString; + + struct HashTable; + struct VPtrSet; + + class JSGlobalData : public RefCounted<JSGlobalData> { + public: + struct ClientData { + virtual ~ClientData() = 0; +#ifdef QT_BUILD_SCRIPT_LIB + virtual void mark() {} +#endif + }; + + static bool sharedInstanceExists(); + static JSGlobalData& sharedInstance(); + + static PassRefPtr<JSGlobalData> create(bool isShared = false); + static PassRefPtr<JSGlobalData> createLeaked(); + ~JSGlobalData(); + +#if ENABLE(JSC_MULTIPLE_THREADS) + // Will start tracking threads that use the heap, which is resource-heavy. + void makeUsableFromMultipleThreads() { heap.makeUsableFromMultipleThreads(); } +#endif + + bool isSharedInstance; + ClientData* clientData; + + const HashTable* arrayTable; + const HashTable* dateTable; + const HashTable* jsonTable; + const HashTable* mathTable; + const HashTable* numberTable; + const HashTable* regExpTable; + const HashTable* regExpConstructorTable; + const HashTable* stringTable; + + RefPtr<Structure> activationStructure; + RefPtr<Structure> interruptedExecutionErrorStructure; + RefPtr<Structure> staticScopeStructure; + RefPtr<Structure> stringStructure; + RefPtr<Structure> notAnObjectErrorStubStructure; + RefPtr<Structure> notAnObjectStructure; +#if !USE(ALTERNATE_JSIMMEDIATE) + RefPtr<Structure> numberStructure; +#endif + + void* jsArrayVPtr; + void* jsByteArrayVPtr; + void* jsStringVPtr; + void* jsFunctionVPtr; + + 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; + +#if ENABLE(ASSEMBLER) + ExecutableAllocator executableAllocator; +#endif + + Lexer* lexer; + Parser* parser; + Interpreter* interpreter; +#ifdef QT_BUILD_SCRIPT_LIB + SourcePool* scriptpool; +#endif +#if ENABLE(JIT) + JITThunks jitStubs; +#endif + TimeoutChecker* timeoutChecker; + Heap heap; + + JSValue exception; +#if ENABLE(JIT) + ReturnAddressPtr exceptionLocation; +#endif + + const Vector<Instruction>& numericCompareFunction(ExecState*); + Vector<Instruction> lazyNumericCompareFunction; + bool initializingLazyNumericCompareFunction; + + HashMap<OpaqueJSClass*, OpaqueJSClassContextData*> opaqueJSClassData; + + JSGlobalObject* head; + JSGlobalObject* dynamicGlobalObject; + + HashSet<JSObject*> arrayVisitedElements; + + ScopeNode* scopeNodeBeingReparsed; + Stringifier* firstStringifierToMark; + + private: + JSGlobalData(bool isShared, const VPtrSet&); + static JSGlobalData*& sharedInstanceInternal(); + void createNativeThunk(); + }; + +} // namespace JSC + +#endif // JSGlobalData_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObject.cpp new file mode 100644 index 0000000..55286d3 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -0,0 +1,464 @@ +/* + * 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 + * 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 "JSGlobalObject.h" + +#include "JSCallbackConstructor.h" +#include "JSCallbackFunction.h" +#include "JSCallbackObject.h" + +#include "Arguments.h" +#include "ArrayConstructor.h" +#include "ArrayPrototype.h" +#include "BooleanConstructor.h" +#include "BooleanPrototype.h" +#include "CodeBlock.h" +#include "DateConstructor.h" +#include "DatePrototype.h" +#include "ErrorConstructor.h" +#include "ErrorPrototype.h" +#include "FunctionConstructor.h" +#include "FunctionPrototype.h" +#include "GlobalEvalFunction.h" +#include "JSFunction.h" +#include "JSGlobalObjectFunctions.h" +#include "JSLock.h" +#include "JSONObject.h" +#include "Interpreter.h" +#include "MathObject.h" +#include "NativeErrorConstructor.h" +#include "NativeErrorPrototype.h" +#include "NumberConstructor.h" +#include "NumberPrototype.h" +#include "ObjectConstructor.h" +#include "ObjectPrototype.h" +#include "Profiler.h" +#include "PrototypeFunction.h" +#include "RegExpConstructor.h" +#include "RegExpMatchesArray.h" +#include "RegExpObject.h" +#include "RegExpPrototype.h" +#include "ScopeChainMark.h" +#include "StringConstructor.h" +#include "StringPrototype.h" +#include "Debugger.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(JSGlobalObject); + +// Default number of ticks before a timeout check should be done. +static const int initialTickCountThreshold = 255; + +// Preferred number of milliseconds between each timeout check +static const int preferredScriptCheckTimeInterval = 1000; + +static inline void markIfNeeded(JSValue v) +{ + if (v && !v.marked()) + v.mark(); +} + +static inline void markIfNeeded(const RefPtr<Structure>& s) +{ + if (s) + s->mark(); +} + +JSGlobalObject::~JSGlobalObject() +{ + ASSERT(JSLock::currentThreadIsHoldingLock()); + + if (d()->debugger) + d()->debugger->detach(this); + + Profiler** profiler = Profiler::enabledProfilerReference(); + if (UNLIKELY(*profiler != 0)) { + (*profiler)->stopProfiling(globalExec(), UString()); + } + + d()->next->d()->prev = d()->prev; + d()->prev->d()->next = d()->next; + JSGlobalObject*& headObject = head(); + if (headObject == this) + headObject = d()->next; + if (headObject == this) + headObject = 0; + + HashSet<ProgramCodeBlock*>::const_iterator end = codeBlocks().end(); + for (HashSet<ProgramCodeBlock*>::const_iterator it = codeBlocks().begin(); it != end; ++it) + (*it)->clearGlobalObject(); + + RegisterFile& registerFile = globalData()->interpreter->registerFile(); + if (registerFile.globalObject() == this) { + registerFile.setGlobalObject(0); + registerFile.setNumGlobals(0); + } + delete d(); +} + +void JSGlobalObject::init(JSObject* thisValue) +{ + ASSERT(JSLock::currentThreadIsHoldingLock()); + + d()->globalData = Heap::heap(this)->globalData(); + d()->globalScopeChain = ScopeChain(this, d()->globalData.get(), thisValue); + + JSGlobalObject::globalExec()->init(0, 0, d()->globalScopeChain.node(), CallFrame::noCaller(), 0, 0, 0); + + if (JSGlobalObject*& headObject = head()) { + d()->prev = headObject; + d()->next = headObject->d()->next; + headObject->d()->next->d()->prev = this; + headObject->d()->next = this; + } else + headObject = d()->next = d()->prev = this; + + d()->recursion = 0; + d()->debugger = 0; + + d()->profileGroup = 0; + + reset(prototype()); +} + +void JSGlobalObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) +{ + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); + + if (symbolTablePut(propertyName, value)) + return; + JSVariableObject::put(exec, propertyName, value, slot); +} + +void JSGlobalObject::putWithAttributes(ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes) +{ + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); + + if (symbolTablePutWithAttributes(propertyName, value, attributes)) + return; + + JSValue valueBefore = getDirect(propertyName); + PutPropertySlot slot; + JSVariableObject::put(exec, propertyName, value, slot); + if (!valueBefore) { + JSValue valueAfter = getDirect(propertyName); + if (valueAfter) + JSObject::putWithAttributes(exec, propertyName, valueAfter, attributes); + } +} + +void JSGlobalObject::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunc) +{ + PropertySlot slot; + if (!symbolTableGet(propertyName, slot)) + JSVariableObject::defineGetter(exec, propertyName, getterFunc); +} + +void JSGlobalObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunc) +{ + PropertySlot slot; + if (!symbolTableGet(propertyName, slot)) + JSVariableObject::defineSetter(exec, propertyName, setterFunc); +} + +static inline JSObject* lastInPrototypeChain(JSObject* object) +{ + JSObject* o = object; + while (o->prototype().isObject()) + o = asObject(o->prototype()); + return o; +} + +void JSGlobalObject::reset(JSValue prototype) +{ + ExecState* exec = JSGlobalObject::globalExec(); + + // Prototypes + + d()->functionPrototype = new (exec) FunctionPrototype(exec, FunctionPrototype::createStructure(jsNull())); // The real prototype will be set once ObjectPrototype is created. + d()->prototypeFunctionStructure = PrototypeFunction::createStructure(d()->functionPrototype); + NativeFunctionWrapper* callFunction = 0; + NativeFunctionWrapper* applyFunction = 0; + d()->functionPrototype->addFunctionProperties(exec, d()->prototypeFunctionStructure.get(), &callFunction, &applyFunction); + d()->callFunction = callFunction; + d()->applyFunction = applyFunction; + d()->objectPrototype = new (exec) ObjectPrototype(exec, ObjectPrototype::createStructure(jsNull()), d()->prototypeFunctionStructure.get()); + d()->functionPrototype->structure()->setPrototypeWithoutTransition(d()->objectPrototype); + + d()->emptyObjectStructure = d()->objectPrototype->inheritorID(); + + d()->functionStructure = JSFunction::createStructure(d()->functionPrototype); + d()->callbackFunctionStructure = JSCallbackFunction::createStructure(d()->functionPrototype); + d()->argumentsStructure = Arguments::createStructure(d()->objectPrototype); + d()->callbackConstructorStructure = JSCallbackConstructor::createStructure(d()->objectPrototype); + d()->callbackObjectStructure = JSCallbackObject<JSObject>::createStructure(d()->objectPrototype); + + d()->arrayPrototype = new (exec) ArrayPrototype(ArrayPrototype::createStructure(d()->objectPrototype)); + d()->arrayStructure = JSArray::createStructure(d()->arrayPrototype); + d()->regExpMatchesArrayStructure = RegExpMatchesArray::createStructure(d()->arrayPrototype); + + d()->stringPrototype = new (exec) StringPrototype(exec, StringPrototype::createStructure(d()->objectPrototype)); + d()->stringObjectStructure = StringObject::createStructure(d()->stringPrototype); + + d()->booleanPrototype = new (exec) BooleanPrototype(exec, BooleanPrototype::createStructure(d()->objectPrototype), d()->prototypeFunctionStructure.get()); + d()->booleanObjectStructure = BooleanObject::createStructure(d()->booleanPrototype); + + d()->numberPrototype = new (exec) NumberPrototype(exec, NumberPrototype::createStructure(d()->objectPrototype), d()->prototypeFunctionStructure.get()); + d()->numberObjectStructure = NumberObject::createStructure(d()->numberPrototype); + + d()->datePrototype = new (exec) DatePrototype(exec, DatePrototype::createStructure(d()->objectPrototype)); + d()->dateStructure = DateInstance::createStructure(d()->datePrototype); + + d()->regExpPrototype = new (exec) RegExpPrototype(exec, RegExpPrototype::createStructure(d()->objectPrototype), d()->prototypeFunctionStructure.get()); + d()->regExpStructure = RegExpObject::createStructure(d()->regExpPrototype); + + d()->methodCallDummy = constructEmptyObject(exec); + + ErrorPrototype* errorPrototype = new (exec) ErrorPrototype(exec, ErrorPrototype::createStructure(d()->objectPrototype), d()->prototypeFunctionStructure.get()); + d()->errorStructure = ErrorInstance::createStructure(errorPrototype); + + RefPtr<Structure> nativeErrorPrototypeStructure = NativeErrorPrototype::createStructure(errorPrototype); + + NativeErrorPrototype* evalErrorPrototype = new (exec) NativeErrorPrototype(exec, nativeErrorPrototypeStructure, "EvalError", "EvalError"); + NativeErrorPrototype* rangeErrorPrototype = new (exec) NativeErrorPrototype(exec, nativeErrorPrototypeStructure, "RangeError", "RangeError"); + NativeErrorPrototype* referenceErrorPrototype = new (exec) NativeErrorPrototype(exec, nativeErrorPrototypeStructure, "ReferenceError", "ReferenceError"); + NativeErrorPrototype* syntaxErrorPrototype = new (exec) NativeErrorPrototype(exec, nativeErrorPrototypeStructure, "SyntaxError", "SyntaxError"); + NativeErrorPrototype* typeErrorPrototype = new (exec) NativeErrorPrototype(exec, nativeErrorPrototypeStructure, "TypeError", "TypeError"); + NativeErrorPrototype* URIErrorPrototype = new (exec) NativeErrorPrototype(exec, nativeErrorPrototypeStructure, "URIError", "URIError"); + + // Constructors + + JSCell* objectConstructor = new (exec) ObjectConstructor(exec, ObjectConstructor::createStructure(d()->functionPrototype), d()->objectPrototype); + JSCell* functionConstructor = new (exec) FunctionConstructor(exec, FunctionConstructor::createStructure(d()->functionPrototype), d()->functionPrototype); + JSCell* arrayConstructor = new (exec) ArrayConstructor(exec, ArrayConstructor::createStructure(d()->functionPrototype), d()->arrayPrototype); + JSCell* stringConstructor = new (exec) StringConstructor(exec, StringConstructor::createStructure(d()->functionPrototype), d()->prototypeFunctionStructure.get(), d()->stringPrototype); + JSCell* booleanConstructor = new (exec) BooleanConstructor(exec, BooleanConstructor::createStructure(d()->functionPrototype), d()->booleanPrototype); + JSCell* numberConstructor = new (exec) NumberConstructor(exec, NumberConstructor::createStructure(d()->functionPrototype), d()->numberPrototype); + JSCell* dateConstructor = new (exec) DateConstructor(exec, DateConstructor::createStructure(d()->functionPrototype), d()->prototypeFunctionStructure.get(), d()->datePrototype); + + d()->regExpConstructor = new (exec) RegExpConstructor(exec, RegExpConstructor::createStructure(d()->functionPrototype), d()->regExpPrototype); + + d()->errorConstructor = new (exec) ErrorConstructor(exec, ErrorConstructor::createStructure(d()->functionPrototype), errorPrototype); + + RefPtr<Structure> nativeErrorStructure = NativeErrorConstructor::createStructure(d()->functionPrototype); + + d()->evalErrorConstructor = new (exec) NativeErrorConstructor(exec, nativeErrorStructure, evalErrorPrototype); + d()->rangeErrorConstructor = new (exec) NativeErrorConstructor(exec, nativeErrorStructure, rangeErrorPrototype); + d()->referenceErrorConstructor = new (exec) NativeErrorConstructor(exec, nativeErrorStructure, referenceErrorPrototype); + d()->syntaxErrorConstructor = new (exec) NativeErrorConstructor(exec, nativeErrorStructure, syntaxErrorPrototype); + d()->typeErrorConstructor = new (exec) NativeErrorConstructor(exec, nativeErrorStructure, typeErrorPrototype); + d()->URIErrorConstructor = new (exec) NativeErrorConstructor(exec, nativeErrorStructure, URIErrorPrototype); + + d()->objectPrototype->putDirectFunctionWithoutTransition(exec->propertyNames().constructor, objectConstructor, DontEnum); + d()->functionPrototype->putDirectFunctionWithoutTransition(exec->propertyNames().constructor, functionConstructor, DontEnum); + d()->arrayPrototype->putDirectFunctionWithoutTransition(exec->propertyNames().constructor, arrayConstructor, DontEnum); + d()->booleanPrototype->putDirectFunctionWithoutTransition(exec->propertyNames().constructor, booleanConstructor, DontEnum); + d()->stringPrototype->putDirectFunctionWithoutTransition(exec->propertyNames().constructor, stringConstructor, DontEnum); + d()->numberPrototype->putDirectFunctionWithoutTransition(exec->propertyNames().constructor, numberConstructor, DontEnum); + d()->datePrototype->putDirectFunctionWithoutTransition(exec->propertyNames().constructor, dateConstructor, DontEnum); + d()->regExpPrototype->putDirectFunctionWithoutTransition(exec->propertyNames().constructor, d()->regExpConstructor, DontEnum); + errorPrototype->putDirectFunctionWithoutTransition(exec->propertyNames().constructor, d()->errorConstructor, DontEnum); + + evalErrorPrototype->putDirect(exec->propertyNames().constructor, d()->evalErrorConstructor, DontEnum); + rangeErrorPrototype->putDirect(exec->propertyNames().constructor, d()->rangeErrorConstructor, DontEnum); + referenceErrorPrototype->putDirect(exec->propertyNames().constructor, d()->referenceErrorConstructor, DontEnum); + syntaxErrorPrototype->putDirect(exec->propertyNames().constructor, d()->syntaxErrorConstructor, DontEnum); + typeErrorPrototype->putDirect(exec->propertyNames().constructor, d()->typeErrorConstructor, DontEnum); + URIErrorPrototype->putDirect(exec->propertyNames().constructor, d()->URIErrorConstructor, DontEnum); + + // Set global constructors + + // FIXME: These properties could be handled by a static hash table. + + putDirectFunctionWithoutTransition(Identifier(exec, "Object"), objectConstructor, DontEnum); + putDirectFunctionWithoutTransition(Identifier(exec, "Function"), functionConstructor, DontEnum); + putDirectFunctionWithoutTransition(Identifier(exec, "Array"), arrayConstructor, DontEnum); + putDirectFunctionWithoutTransition(Identifier(exec, "Boolean"), booleanConstructor, DontEnum); + putDirectFunctionWithoutTransition(Identifier(exec, "String"), stringConstructor, DontEnum); + putDirectFunctionWithoutTransition(Identifier(exec, "Number"), numberConstructor, DontEnum); + putDirectFunctionWithoutTransition(Identifier(exec, "Date"), dateConstructor, DontEnum); + putDirectFunctionWithoutTransition(Identifier(exec, "RegExp"), d()->regExpConstructor, DontEnum); + putDirectFunctionWithoutTransition(Identifier(exec, "Error"), d()->errorConstructor, DontEnum); + putDirectFunctionWithoutTransition(Identifier(exec, "EvalError"), d()->evalErrorConstructor, DontEnum); + putDirectFunctionWithoutTransition(Identifier(exec, "RangeError"), d()->rangeErrorConstructor, DontEnum); + putDirectFunctionWithoutTransition(Identifier(exec, "ReferenceError"), d()->referenceErrorConstructor, DontEnum); + putDirectFunctionWithoutTransition(Identifier(exec, "SyntaxError"), d()->syntaxErrorConstructor, DontEnum); + putDirectFunctionWithoutTransition(Identifier(exec, "TypeError"), d()->typeErrorConstructor, DontEnum); + putDirectFunctionWithoutTransition(Identifier(exec, "URIError"), d()->URIErrorConstructor, DontEnum); + + // Set global values. + GlobalPropertyInfo staticGlobals[] = { + GlobalPropertyInfo(Identifier(exec, "Math"), new (exec) MathObject(exec, MathObject::createStructure(d()->objectPrototype)), DontEnum | DontDelete), + GlobalPropertyInfo(Identifier(exec, "NaN"), jsNaN(exec), DontEnum | DontDelete), + GlobalPropertyInfo(Identifier(exec, "Infinity"), jsNumber(exec, Inf), DontEnum | DontDelete), + GlobalPropertyInfo(Identifier(exec, "undefined"), jsUndefined(), DontEnum | DontDelete), + GlobalPropertyInfo(Identifier(exec, "JSON"), new (exec) JSONObject(JSONObject::createStructure(d()->objectPrototype)), DontEnum | DontDelete) + }; + + addStaticGlobals(staticGlobals, sizeof(staticGlobals) / sizeof(GlobalPropertyInfo)); + + // Set global functions. + + d()->evalFunction = new (exec) GlobalEvalFunction(exec, GlobalEvalFunction::createStructure(d()->functionPrototype), 1, exec->propertyNames().eval, globalFuncEval, this); + putDirectFunctionWithoutTransition(exec, d()->evalFunction, DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 2, Identifier(exec, "parseInt"), globalFuncParseInt), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "parseFloat"), globalFuncParseFloat), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "isNaN"), globalFuncIsNaN), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "isFinite"), globalFuncIsFinite), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "escape"), globalFuncEscape), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "unescape"), globalFuncUnescape), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "decodeURI"), globalFuncDecodeURI), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "decodeURIComponent"), globalFuncDecodeURIComponent), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "encodeURI"), globalFuncEncodeURI), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "encodeURIComponent"), globalFuncEncodeURIComponent), DontEnum); +#ifndef NDEBUG +#ifndef QT_BUILD_SCRIPT_LIB + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "jscprint"), globalFuncJSCPrint), DontEnum); +#endif +#endif + + resetPrototype(prototype); +} + +// Set prototype, and also insert the object prototype at the end of the chain. +void JSGlobalObject::resetPrototype(JSValue prototype) +{ + setPrototype(prototype); + + JSObject* oldLastInPrototypeChain = lastInPrototypeChain(this); + JSObject* objectPrototype = d()->objectPrototype; + if (oldLastInPrototypeChain != objectPrototype) + oldLastInPrototypeChain->setPrototype(objectPrototype); +} + +void JSGlobalObject::mark() +{ + JSVariableObject::mark(); + + HashSet<ProgramCodeBlock*>::const_iterator end = codeBlocks().end(); + for (HashSet<ProgramCodeBlock*>::const_iterator it = codeBlocks().begin(); it != end; ++it) + (*it)->mark(); + + RegisterFile& registerFile = globalData()->interpreter->registerFile(); + if (registerFile.globalObject() == this) + registerFile.markGlobals(&globalData()->heap); + + markIfNeeded(d()->regExpConstructor); + markIfNeeded(d()->errorConstructor); + markIfNeeded(d()->evalErrorConstructor); + markIfNeeded(d()->rangeErrorConstructor); + markIfNeeded(d()->referenceErrorConstructor); + markIfNeeded(d()->syntaxErrorConstructor); + markIfNeeded(d()->typeErrorConstructor); + markIfNeeded(d()->URIErrorConstructor); + + markIfNeeded(d()->evalFunction); + markIfNeeded(d()->callFunction); + markIfNeeded(d()->applyFunction); + + markIfNeeded(d()->objectPrototype); + markIfNeeded(d()->functionPrototype); + markIfNeeded(d()->arrayPrototype); + markIfNeeded(d()->booleanPrototype); + markIfNeeded(d()->stringPrototype); + markIfNeeded(d()->numberPrototype); + markIfNeeded(d()->datePrototype); + markIfNeeded(d()->regExpPrototype); + + markIfNeeded(d()->methodCallDummy); + + markIfNeeded(d()->errorStructure); + + // No need to mark the other structures, because their prototypes are all + // guaranteed to be referenced elsewhere. + + Register* registerArray = d()->registerArray.get(); + if (!registerArray) + return; + + size_t size = d()->registerArraySize; + for (size_t i = 0; i < size; ++i) { + Register& r = registerArray[i]; + if (!r.marked()) + r.mark(); + } +} + +ExecState* JSGlobalObject::globalExec() +{ + return CallFrame::create(d()->globalCallFrame + RegisterFile::CallFrameHeaderSize); +} + +bool JSGlobalObject::isDynamicScope() const +{ + return true; +} + +void JSGlobalObject::copyGlobalsFrom(RegisterFile& registerFile) +{ + ASSERT(!d()->registerArray); + ASSERT(!d()->registerArraySize); + + int numGlobals = registerFile.numGlobals(); + if (!numGlobals) { + d()->registers = 0; + return; + } + + Register* registerArray = copyRegisterArray(registerFile.lastGlobal(), numGlobals); + setRegisters(registerArray + numGlobals, registerArray, numGlobals); +} + +void JSGlobalObject::copyGlobalsTo(RegisterFile& registerFile) +{ + JSGlobalObject* lastGlobalObject = registerFile.globalObject(); + if (lastGlobalObject && lastGlobalObject != this) + lastGlobalObject->copyGlobalsFrom(registerFile); + + registerFile.setGlobalObject(this); + registerFile.setNumGlobals(symbolTable().size()); + + if (d()->registerArray) { + memcpy(registerFile.start() - d()->registerArraySize, d()->registerArray.get(), d()->registerArraySize * sizeof(Register)); + setRegisters(registerFile.start(), 0, 0); + } +} + +void* JSGlobalObject::operator new(size_t size, JSGlobalData* globalData) +{ +#ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE + return globalData->heap.inlineAllocate(size); +#else + return globalData->heap.allocate(size); +#endif +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObject.h new file mode 100644 index 0000000..98e9b68 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObject.h @@ -0,0 +1,426 @@ +/* + * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef JSGlobalObject_h +#define JSGlobalObject_h + +#include "JSGlobalData.h" +#include "JSVariableObject.h" +#include "NativeFunctionWrapper.h" +#include "NumberPrototype.h" +#include "StringPrototype.h" +#include "StructureChain.h" +#include <wtf/HashSet.h> +#include <wtf/OwnPtr.h> + +#ifdef QT_BUILD_SCRIPT_LIB +#include "SourcePoolQt.h" +#endif + +namespace JSC { + + class ArrayPrototype; + class BooleanPrototype; + class DatePrototype; + class Debugger; + class ErrorConstructor; + class FunctionPrototype; + class GlobalEvalFunction; + class NativeErrorConstructor; + class ProgramCodeBlock; + class PrototypeFunction; + class RegExpConstructor; + class RegExpPrototype; + class RegisterFile; + + struct ActivationStackNode; + struct HashTable; + + typedef Vector<ExecState*, 16> ExecStateStack; + + class JSGlobalObject : public JSVariableObject { + protected: + using JSVariableObject::JSVariableObjectData; + + struct JSGlobalObjectData : public JSVariableObjectData { + JSGlobalObjectData() + : JSVariableObjectData(&symbolTable, 0) + , registerArraySize(0) + , globalScopeChain(NoScopeChain()) + , regExpConstructor(0) + , errorConstructor(0) + , evalErrorConstructor(0) + , rangeErrorConstructor(0) + , referenceErrorConstructor(0) + , syntaxErrorConstructor(0) + , typeErrorConstructor(0) + , URIErrorConstructor(0) + , evalFunction(0) + , callFunction(0) + , applyFunction(0) + , objectPrototype(0) + , functionPrototype(0) + , arrayPrototype(0) + , booleanPrototype(0) + , stringPrototype(0) + , numberPrototype(0) + , datePrototype(0) + , regExpPrototype(0) + , methodCallDummy(0) + { + } + + virtual ~JSGlobalObjectData() + { + } + + size_t registerArraySize; + + JSGlobalObject* next; + JSGlobalObject* prev; + + Debugger* debugger; + + ScopeChain globalScopeChain; + Register globalCallFrame[RegisterFile::CallFrameHeaderSize]; + + int recursion; + + RegExpConstructor* regExpConstructor; + ErrorConstructor* errorConstructor; + NativeErrorConstructor* evalErrorConstructor; + NativeErrorConstructor* rangeErrorConstructor; + NativeErrorConstructor* referenceErrorConstructor; + NativeErrorConstructor* syntaxErrorConstructor; + NativeErrorConstructor* typeErrorConstructor; + NativeErrorConstructor* URIErrorConstructor; + + GlobalEvalFunction* evalFunction; + NativeFunctionWrapper* callFunction; + NativeFunctionWrapper* applyFunction; + + ObjectPrototype* objectPrototype; + FunctionPrototype* functionPrototype; + ArrayPrototype* arrayPrototype; + BooleanPrototype* booleanPrototype; + StringPrototype* stringPrototype; + NumberPrototype* numberPrototype; + DatePrototype* datePrototype; + RegExpPrototype* regExpPrototype; + + JSObject* methodCallDummy; + + RefPtr<Structure> argumentsStructure; + RefPtr<Structure> arrayStructure; + RefPtr<Structure> booleanObjectStructure; + RefPtr<Structure> callbackConstructorStructure; + RefPtr<Structure> callbackFunctionStructure; + RefPtr<Structure> callbackObjectStructure; + RefPtr<Structure> dateStructure; + RefPtr<Structure> emptyObjectStructure; + RefPtr<Structure> errorStructure; + RefPtr<Structure> functionStructure; + RefPtr<Structure> numberObjectStructure; + RefPtr<Structure> prototypeFunctionStructure; + RefPtr<Structure> regExpMatchesArrayStructure; + RefPtr<Structure> regExpStructure; + RefPtr<Structure> stringObjectStructure; + + SymbolTable symbolTable; + unsigned profileGroup; + + RefPtr<JSGlobalData> globalData; + + HashSet<ProgramCodeBlock*> codeBlocks; + }; + + public: + void* operator new(size_t, JSGlobalData*); + + explicit JSGlobalObject() + : JSVariableObject(JSGlobalObject::createStructure(jsNull()), new JSGlobalObjectData) + { + init(this); + } + + protected: + JSGlobalObject(PassRefPtr<Structure> structure, JSGlobalObjectData* data, JSObject* thisValue) + : JSVariableObject(structure, data) + { + init(thisValue); + } + + public: + virtual ~JSGlobalObject(); + + virtual void mark(); + + virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + virtual bool hasOwnPropertyForWrite(ExecState*, const Identifier&); + virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&); + virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes); + + virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunc); + virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunc); + + // Linked list of all global objects that use the same JSGlobalData. + JSGlobalObject*& head() { return d()->globalData->head; } + JSGlobalObject* next() { return d()->next; } + + // The following accessors return pristine values, even if a script + // replaces the global object's associated property. + + RegExpConstructor* regExpConstructor() const { return d()->regExpConstructor; } + + ErrorConstructor* errorConstructor() const { return d()->errorConstructor; } + NativeErrorConstructor* evalErrorConstructor() const { return d()->evalErrorConstructor; } + NativeErrorConstructor* rangeErrorConstructor() const { return d()->rangeErrorConstructor; } + NativeErrorConstructor* referenceErrorConstructor() const { return d()->referenceErrorConstructor; } + NativeErrorConstructor* syntaxErrorConstructor() const { return d()->syntaxErrorConstructor; } + NativeErrorConstructor* typeErrorConstructor() const { return d()->typeErrorConstructor; } + NativeErrorConstructor* URIErrorConstructor() const { return d()->URIErrorConstructor; } + + GlobalEvalFunction* evalFunction() const { return d()->evalFunction; } + + ObjectPrototype* objectPrototype() const { return d()->objectPrototype; } + FunctionPrototype* functionPrototype() const { return d()->functionPrototype; } + ArrayPrototype* arrayPrototype() const { return d()->arrayPrototype; } + BooleanPrototype* booleanPrototype() const { return d()->booleanPrototype; } + StringPrototype* stringPrototype() const { return d()->stringPrototype; } + NumberPrototype* numberPrototype() const { return d()->numberPrototype; } + DatePrototype* datePrototype() const { return d()->datePrototype; } + RegExpPrototype* regExpPrototype() const { return d()->regExpPrototype; } + + JSObject* methodCallDummy() const { return d()->methodCallDummy; } + + Structure* argumentsStructure() const { return d()->argumentsStructure.get(); } + Structure* arrayStructure() const { return d()->arrayStructure.get(); } + Structure* booleanObjectStructure() const { return d()->booleanObjectStructure.get(); } + Structure* callbackConstructorStructure() const { return d()->callbackConstructorStructure.get(); } + Structure* callbackFunctionStructure() const { return d()->callbackFunctionStructure.get(); } + Structure* callbackObjectStructure() const { return d()->callbackObjectStructure.get(); } + Structure* dateStructure() const { return d()->dateStructure.get(); } + Structure* emptyObjectStructure() const { return d()->emptyObjectStructure.get(); } + Structure* errorStructure() const { return d()->errorStructure.get(); } + Structure* functionStructure() const { return d()->functionStructure.get(); } + Structure* numberObjectStructure() const { return d()->numberObjectStructure.get(); } + Structure* prototypeFunctionStructure() const { return d()->prototypeFunctionStructure.get(); } + Structure* regExpMatchesArrayStructure() const { return d()->regExpMatchesArrayStructure.get(); } + Structure* regExpStructure() const { return d()->regExpStructure.get(); } + Structure* stringObjectStructure() const { return d()->stringObjectStructure.get(); } + + void setProfileGroup(unsigned value) { d()->profileGroup = value; } + unsigned profileGroup() const { return d()->profileGroup; } + + Debugger* debugger() const { return d()->debugger; } + void setDebugger(Debugger* debugger) + { +#ifdef QT_BUILD_SCRIPT_LIB + globalData()->scriptpool->setDebugger(debugger); +#endif + d()->debugger = debugger; + } + + virtual bool supportsProfiling() const { return false; } + + int recursion() { return d()->recursion; } + void incRecursion() { ++d()->recursion; } + void decRecursion() { --d()->recursion; } + + ScopeChain& globalScopeChain() { return d()->globalScopeChain; } + + virtual bool isGlobalObject() const { return true; } + + virtual ExecState* globalExec(); + + virtual bool shouldInterruptScript() const { return true; } + + virtual bool allowsAccessFrom(const JSGlobalObject*) const { return true; } + + virtual bool isDynamicScope() const; + + HashSet<ProgramCodeBlock*>& codeBlocks() { return d()->codeBlocks; } + + void copyGlobalsFrom(RegisterFile&); + void copyGlobalsTo(RegisterFile&); + + void resetPrototype(JSValue prototype); + + JSGlobalData* globalData() { return d()->globalData.get(); } + JSGlobalObjectData* d() const { return static_cast<JSGlobalObjectData*>(JSVariableObject::d); } + + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType)); + } + + protected: + struct GlobalPropertyInfo { + GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a) + : identifier(i) + , value(v) + , attributes(a) + { + } + + const Identifier identifier; + JSValue value; + unsigned attributes; + }; + void addStaticGlobals(GlobalPropertyInfo*, int count); + + private: + // FIXME: Fold reset into init. + void init(JSObject* thisValue); + void reset(JSValue prototype); + + void setRegisters(Register* registers, Register* registerArray, size_t count); + + void* operator new(size_t); // can only be allocated with JSGlobalData + }; + + JSGlobalObject* asGlobalObject(JSValue); + + inline JSGlobalObject* asGlobalObject(JSValue value) + { + ASSERT(asObject(value)->isGlobalObject()); + return static_cast<JSGlobalObject*>(asObject(value)); + } + + inline void JSGlobalObject::setRegisters(Register* registers, Register* registerArray, size_t count) + { + JSVariableObject::setRegisters(registers, registerArray); + d()->registerArraySize = count; + } + + inline void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count) + { + size_t oldSize = d()->registerArraySize; + size_t newSize = oldSize + count; + Register* registerArray = new Register[newSize]; + if (d()->registerArray) + memcpy(registerArray + count, d()->registerArray.get(), oldSize * sizeof(Register)); + setRegisters(registerArray + newSize, registerArray, newSize); + + for (int i = 0, index = -static_cast<int>(oldSize) - 1; i < count; ++i, --index) { + GlobalPropertyInfo& global = globals[i]; + ASSERT(global.attributes & DontDelete); + SymbolTableEntry newEntry(index, global.attributes); + symbolTable().add(global.identifier.ustring().rep(), newEntry); + registerAt(index) = global.value; + } + } + + inline bool JSGlobalObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) + { + if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot)) + return true; + return symbolTableGet(propertyName, slot); + } + + inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, const Identifier& propertyName) + { + PropertySlot slot; + if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot)) + return true; + bool slotIsWriteable; + return symbolTableGet(propertyName, slot, slotIsWriteable); + } + + inline JSGlobalObject* ScopeChainNode::globalObject() const + { + const ScopeChainNode* n = this; + while (n->next) + n = n->next; + return asGlobalObject(n->object); + } + + inline JSValue Structure::prototypeForLookup(ExecState* exec) const + { + if (typeInfo().type() == ObjectType) + return m_prototype; + + if (typeInfo().type() == StringType) + return exec->lexicalGlobalObject()->stringPrototype(); + + ASSERT(typeInfo().type() == NumberType); + return exec->lexicalGlobalObject()->numberPrototype(); + } + + inline StructureChain* Structure::prototypeChain(ExecState* exec) const + { + // We cache our prototype chain so our clients can share it. + if (!isValid(exec, m_cachedPrototypeChain.get())) { + JSValue prototype = prototypeForLookup(exec); + m_cachedPrototypeChain = StructureChain::create(prototype.isNull() ? 0 : asObject(prototype)->structure()); + } + return m_cachedPrototypeChain.get(); + } + + inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const + { + if (!cachedPrototypeChain) + return false; + + JSValue prototype = prototypeForLookup(exec); + RefPtr<Structure>* cachedStructure = cachedPrototypeChain->head(); + while(*cachedStructure && !prototype.isNull()) { + if (asObject(prototype)->structure() != *cachedStructure) + return false; + ++cachedStructure; + prototype = asObject(prototype)->prototype(); + } + return prototype.isNull() && !*cachedStructure; + } + + inline JSGlobalObject* ExecState::dynamicGlobalObject() + { + if (this == lexicalGlobalObject()->globalExec()) + return lexicalGlobalObject(); + + // For any ExecState that's not a globalExec, the + // dynamic global object must be set since code is running + ASSERT(globalData().dynamicGlobalObject); + return globalData().dynamicGlobalObject; + } + + class DynamicGlobalObjectScope : public Noncopyable { + public: + DynamicGlobalObjectScope(CallFrame* callFrame, JSGlobalObject* dynamicGlobalObject) + : m_dynamicGlobalObjectSlot(callFrame->globalData().dynamicGlobalObject) + , m_savedDynamicGlobalObject(m_dynamicGlobalObjectSlot) + { + m_dynamicGlobalObjectSlot = dynamicGlobalObject; + } + + ~DynamicGlobalObjectScope() + { + m_dynamicGlobalObjectSlot = m_savedDynamicGlobalObject; + } + + private: + JSGlobalObject*& m_dynamicGlobalObjectSlot; + JSGlobalObject* m_savedDynamicGlobalObject; + }; + +} // namespace JSC + +#endif // JSGlobalObject_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp new file mode 100644 index 0000000..85f92f2 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp @@ -0,0 +1,439 @@ +/* + * 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 "JSGlobalObjectFunctions.h" + +#include "CallFrame.h" +#include "GlobalEvalFunction.h" +#include "JSGlobalObject.h" +#include "LiteralParser.h" +#include "JSString.h" +#include "Interpreter.h" +#include "Parser.h" +#include "dtoa.h" +#include "Lexer.h" +#include "Nodes.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wtf/ASCIICType.h> +#include <wtf/Assertions.h> +#include <wtf/MathExtras.h> +#include <wtf/unicode/UTF8.h> + +using namespace WTF; +using namespace Unicode; + +namespace JSC { + +static JSValue encode(ExecState* exec, const ArgList& args, const char* doNotEscape) +{ + UString str = args.at(0).toString(exec); + CString cstr = str.UTF8String(true); + if (!cstr.c_str()) + return throwError(exec, URIError, "String contained an illegal UTF-16 sequence."); + + UString result = ""; + const char* p = cstr.c_str(); + for (size_t k = 0; k < cstr.size(); k++, p++) { + char c = *p; + if (c && strchr(doNotEscape, c)) + result.append(c); + else { + char tmp[4]; + sprintf(tmp, "%%%02X", static_cast<unsigned char>(c)); + result += tmp; + } + } + return jsString(exec, result); +} + +static JSValue decode(ExecState* exec, const ArgList& args, const char* doNotUnescape, bool strict) +{ + UString result = ""; + UString str = args.at(0).toString(exec); + int k = 0; + int len = str.size(); + const UChar* d = str.data(); + UChar u = 0; + while (k < len) { + const UChar* p = d + k; + UChar c = *p; + if (c == '%') { + int charLen = 0; + if (k <= len - 3 && isASCIIHexDigit(p[1]) && isASCIIHexDigit(p[2])) { + const char b0 = Lexer::convertHex(p[1], p[2]); + const int sequenceLen = UTF8SequenceLength(b0); + if (sequenceLen != 0 && k <= len - sequenceLen * 3) { + charLen = sequenceLen * 3; + char sequence[5]; + sequence[0] = b0; + for (int i = 1; i < sequenceLen; ++i) { + const UChar* q = p + i * 3; + if (q[0] == '%' && isASCIIHexDigit(q[1]) && isASCIIHexDigit(q[2])) + sequence[i] = Lexer::convertHex(q[1], q[2]); + else { + charLen = 0; + break; + } + } + if (charLen != 0) { + sequence[sequenceLen] = 0; + const int character = decodeUTF8Sequence(sequence); + if (character < 0 || character >= 0x110000) + charLen = 0; + else if (character >= 0x10000) { + // Convert to surrogate pair. + result.append(static_cast<UChar>(0xD800 | ((character - 0x10000) >> 10))); + u = static_cast<UChar>(0xDC00 | ((character - 0x10000) & 0x3FF)); + } else + u = static_cast<UChar>(character); + } + } + } + if (charLen == 0) { + if (strict) + return throwError(exec, URIError); + // The only case where we don't use "strict" mode is the "unescape" function. + // For that, it's good to support the wonky "%u" syntax for compatibility with WinIE. + if (k <= len - 6 && p[1] == 'u' + && isASCIIHexDigit(p[2]) && isASCIIHexDigit(p[3]) + && isASCIIHexDigit(p[4]) && isASCIIHexDigit(p[5])) { + charLen = 6; + u = Lexer::convertUnicode(p[2], p[3], p[4], p[5]); + } + } + if (charLen && (u == 0 || u >= 128 || !strchr(doNotUnescape, u))) { + c = u; + k += charLen - 1; + } + } + k++; + result.append(c); + } + return jsString(exec, result); +} + +bool isStrWhiteSpace(UChar c) +{ + switch (c) { + case 0x0009: + case 0x000A: + case 0x000B: + case 0x000C: + case 0x000D: + case 0x0020: + case 0x00A0: + case 0x2028: + case 0x2029: + return true; + default: + return c > 0xff && isSeparatorSpace(c); + } +} + +static int parseDigit(unsigned short c, int radix) +{ + int digit = -1; + + if (c >= '0' && c <= '9') + digit = c - '0'; + else if (c >= 'A' && c <= 'Z') + digit = c - 'A' + 10; + else if (c >= 'a' && c <= 'z') + digit = c - 'a' + 10; + + if (digit >= radix) + return -1; + return digit; +} + +double parseIntOverflow(const char* s, int length, int radix) +{ + double number = 0.0; + double radixMultiplier = 1.0; + + for (const char* p = s + length - 1; p >= s; p--) { + if (radixMultiplier == Inf) { + if (*p != '0') { + number = Inf; + break; + } + } else { + int digit = parseDigit(*p, radix); + number += digit * radixMultiplier; + } + + radixMultiplier *= radix; + } + + return number; +} + +static double parseInt(const UString& s, int radix) +{ + int length = s.size(); + const UChar* data = s.data(); + int p = 0; + + while (p < length && isStrWhiteSpace(data[p])) + ++p; + + double sign = 1; + if (p < length) { + if (data[p] == '+') + ++p; + else if (data[p] == '-') { + sign = -1; + ++p; + } + } + + if ((radix == 0 || radix == 16) && length - p >= 2 && data[p] == '0' && (data[p + 1] == 'x' || data[p + 1] == 'X')) { + radix = 16; + p += 2; + } else if (radix == 0) { + if (p < length && data[p] == '0') + radix = 8; + else + radix = 10; + } + + if (radix < 2 || radix > 36) + return NaN; + + int firstDigitPosition = p; + bool sawDigit = false; + double number = 0; + while (p < length) { + int digit = parseDigit(data[p], radix); + if (digit == -1) + break; + sawDigit = true; + number *= radix; + number += digit; + ++p; + } + + if (number >= mantissaOverflowLowerBound) { + if (radix == 10) + number = WTF::strtod(s.substr(firstDigitPosition, p - firstDigitPosition).ascii(), 0); + else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32) + number = parseIntOverflow(s.substr(firstDigitPosition, p - firstDigitPosition).ascii(), p - firstDigitPosition, radix); + } + + if (!sawDigit) + return NaN; + + return sign * number; +} + +static double parseFloat(const UString& s) +{ + // Check for 0x prefix here, because toDouble allows it, but we must treat it as 0. + // Need to skip any whitespace and then one + or - sign. + int length = s.size(); + const UChar* data = s.data(); + int p = 0; + while (p < length && isStrWhiteSpace(data[p])) + ++p; + + if (p < length && (data[p] == '+' || data[p] == '-')) + ++p; + + if (length - p >= 2 && data[p] == '0' && (data[p + 1] == 'x' || data[p + 1] == 'X')) + return 0; + + return s.toDouble(true /*tolerant*/, false /* NaN for empty string */); +} + +JSValue JSC_HOST_CALL globalFuncEval(ExecState* exec, JSObject* function, JSValue thisValue, const ArgList& args) +{ + JSObject* thisObject = thisValue.toThisObject(exec); + JSObject* unwrappedObject = thisObject->unwrappedObject(); + if (!unwrappedObject->isGlobalObject() || static_cast<JSGlobalObject*>(unwrappedObject)->evalFunction() != function) + return throwError(exec, EvalError, "The \"this\" value passed to eval must be the global object from which eval originated"); + + JSValue x = args.at(0); + if (!x.isString()) + return x; + + UString s = x.toString(exec); + + LiteralParser preparser(exec, s, LiteralParser::NonStrictJSON); + if (JSValue parsedObject = preparser.tryLiteralParse()) + return parsedObject; + + int errLine; + UString errMsg; + + SourceCode source = makeSource(s); + RefPtr<EvalNode> evalNode = exec->globalData().parser->parse<EvalNode>(exec, exec->dynamicGlobalObject()->debugger(), source, &errLine, &errMsg); + + if (!evalNode) + return throwError(exec, SyntaxError, errMsg, errLine, source.provider()->asID(), NULL); + + return exec->interpreter()->execute(evalNode.get(), exec, thisObject, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain().node(), exec->exceptionSlot()); +} + +JSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + JSValue value = args.at(0); + int32_t radix = args.at(1).toInt32(exec); + + if (value.isNumber() && (radix == 0 || radix == 10)) { + if (value.isInt32Fast()) + return value; + double d = value.uncheckedGetNumber(); + if (isfinite(d)) + return jsNumber(exec, (d > 0) ? floor(d) : ceil(d)); + if (isnan(d) || isinf(d)) + return jsNaN(&exec->globalData()); + return jsNumber(exec, 0); + } + + return jsNumber(exec, parseInt(value.toString(exec), radix)); +} + +JSValue JSC_HOST_CALL globalFuncParseFloat(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return jsNumber(exec, parseFloat(args.at(0).toString(exec))); +} + +JSValue JSC_HOST_CALL globalFuncIsNaN(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return jsBoolean(isnan(args.at(0).toNumber(exec))); +} + +JSValue JSC_HOST_CALL globalFuncIsFinite(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + double n = args.at(0).toNumber(exec); + return jsBoolean(!isnan(n) && !isinf(n)); +} + +JSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + static const char do_not_unescape_when_decoding_URI[] = + "#$&+,/:;=?@"; + + return decode(exec, args, do_not_unescape_when_decoding_URI, true); +} + +JSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return decode(exec, args, "", true); +} + +JSValue JSC_HOST_CALL globalFuncEncodeURI(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + static const char do_not_escape_when_encoding_URI[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "!#$&'()*+,-./:;=?@_~"; + + return encode(exec, args, do_not_escape_when_encoding_URI); +} + +JSValue JSC_HOST_CALL globalFuncEncodeURIComponent(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + static const char do_not_escape_when_encoding_URI_component[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "!'()*-._~"; + + return encode(exec, args, do_not_escape_when_encoding_URI_component); +} + +JSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + static const char do_not_escape[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "*+-./@_"; + + UString result = ""; + UString s; + UString str = args.at(0).toString(exec); + const UChar* c = str.data(); + for (int k = 0; k < str.size(); k++, c++) { + int u = c[0]; + if (u > 255) { + char tmp[7]; + sprintf(tmp, "%%u%04X", u); + s = UString(tmp); + } else if (u != 0 && strchr(do_not_escape, static_cast<char>(u))) + s = UString(c, 1); + else { + char tmp[4]; + sprintf(tmp, "%%%02X", u); + s = UString(tmp); + } + result += s; + } + + return jsString(exec, result); +} + +JSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + UString result = ""; + UString str = args.at(0).toString(exec); + int k = 0; + int len = str.size(); + while (k < len) { + const UChar* c = str.data() + k; + UChar u; + if (c[0] == '%' && k <= len - 6 && c[1] == 'u') { + if (isASCIIHexDigit(c[2]) && isASCIIHexDigit(c[3]) && isASCIIHexDigit(c[4]) && isASCIIHexDigit(c[5])) { + u = Lexer::convertUnicode(c[2], c[3], c[4], c[5]); + c = &u; + k += 5; + } + } else if (c[0] == '%' && k <= len - 3 && isASCIIHexDigit(c[1]) && isASCIIHexDigit(c[2])) { + u = UChar(Lexer::convertHex(c[1], c[2])); + c = &u; + k += 2; + } + k++; + result.append(*c); + } + + return jsString(exec, result); +} + +#ifndef NDEBUG +JSValue JSC_HOST_CALL globalFuncJSCPrint(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + CStringBuffer string; + args.at(0).toString(exec).getCString(string); + puts(string.data()); + return jsUndefined(); +} +#endif + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObjectFunctions.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObjectFunctions.h new file mode 100644 index 0000000..b1046f2 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObjectFunctions.h @@ -0,0 +1,60 @@ +/* + * 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 JSGlobalObjectFunctions_h +#define JSGlobalObjectFunctions_h + +#include <wtf/unicode/Unicode.h> + +namespace JSC { + + class ArgList; + class ExecState; + class JSObject; + class JSValue; + + // FIXME: These functions should really be in JSGlobalObject.cpp, but putting them there + // is a 0.5% reduction. + + JSValue JSC_HOST_CALL globalFuncEval(ExecState*, JSObject*, JSValue, const ArgList&); + JSValue JSC_HOST_CALL globalFuncParseInt(ExecState*, JSObject*, JSValue, const ArgList&); + JSValue JSC_HOST_CALL globalFuncParseFloat(ExecState*, JSObject*, JSValue, const ArgList&); + JSValue JSC_HOST_CALL globalFuncIsNaN(ExecState*, JSObject*, JSValue, const ArgList&); + JSValue JSC_HOST_CALL globalFuncIsFinite(ExecState*, JSObject*, JSValue, const ArgList&); + JSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState*, JSObject*, JSValue, const ArgList&); + JSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState*, JSObject*, JSValue, const ArgList&); + JSValue JSC_HOST_CALL globalFuncEncodeURI(ExecState*, JSObject*, JSValue, const ArgList&); + JSValue JSC_HOST_CALL globalFuncEncodeURIComponent(ExecState*, JSObject*, JSValue, const ArgList&); + JSValue JSC_HOST_CALL globalFuncEscape(ExecState*, JSObject*, JSValue, const ArgList&); + JSValue JSC_HOST_CALL globalFuncUnescape(ExecState*, JSObject*, JSValue, const ArgList&); +#ifndef NDEBUG + JSValue JSC_HOST_CALL globalFuncJSCPrint(ExecState*, JSObject*, JSValue, const ArgList&); +#endif + + static const double mantissaOverflowLowerBound = 9007199254740992.0; + double parseIntOverflow(const char*, int length, int radix); + bool isStrWhiteSpace(UChar); + +} // namespace JSC + +#endif // JSGlobalObjectFunctions_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSImmediate.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSImmediate.cpp new file mode 100644 index 0000000..201e56c --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSImmediate.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2003-2006, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "JSImmediate.h" + +#include "BooleanConstructor.h" +#include "BooleanPrototype.h" +#include "Error.h" +#include "ExceptionHelpers.h" +#include "JSGlobalObject.h" +#include "JSNotAnObject.h" +#include "NumberConstructor.h" +#include "NumberPrototype.h" + +namespace JSC { + +JSObject* JSImmediate::toThisObject(JSValue v, ExecState* exec) +{ + ASSERT(isImmediate(v)); + if (isNumber(v)) + return constructNumber(exec, v); + if (isBoolean(v)) + return constructBooleanFromImmediateBoolean(exec, v); + ASSERT(v.isUndefinedOrNull()); + return exec->globalThisValue(); +} + +JSObject* JSImmediate::toObject(JSValue v, ExecState* exec) +{ + ASSERT(isImmediate(v)); + if (isNumber(v)) + return constructNumber(exec, v); + if (isBoolean(v)) + return constructBooleanFromImmediateBoolean(exec, v); + + JSNotAnObjectErrorStub* exception = createNotAnObjectErrorStub(exec, v.isNull()); + exec->setException(exception); + return new (exec) JSNotAnObject(exec, exception); +} + +JSObject* JSImmediate::prototype(JSValue v, ExecState* exec) +{ + ASSERT(isImmediate(v)); + if (isNumber(v)) + return exec->lexicalGlobalObject()->numberPrototype(); + if (isBoolean(v)) + return exec->lexicalGlobalObject()->booleanPrototype(); + + JSNotAnObjectErrorStub* exception = createNotAnObjectErrorStub(exec, v.isNull()); + exec->setException(exception); + return new (exec) JSNotAnObject(exec, exception); +} + +UString JSImmediate::toString(JSValue v) +{ + ASSERT(isImmediate(v)); + if (isIntegerNumber(v)) + return UString::from(getTruncatedInt32(v)); +#if USE(ALTERNATE_JSIMMEDIATE) + if (isNumber(v)) { + ASSERT(isDoubleNumber(v)); + double value = doubleValue(v); + if (value == 0.0) // +0.0 or -0.0 + return "0"; + return UString::from(value); + } +#else + ASSERT(!isNumber(v)); +#endif + if (jsBoolean(false) == v) + return "false"; + if (jsBoolean(true) == v) + return "true"; + if (v.isNull()) + return "null"; + ASSERT(v.isUndefined()); + return "undefined"; +} + +NEVER_INLINE double JSImmediate::nonInlineNaN() +{ + return std::numeric_limits<double>::quiet_NaN(); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSImmediate.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSImmediate.h new file mode 100644 index 0000000..e7d7847 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSImmediate.h @@ -0,0 +1,790 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef JSImmediate_h +#define JSImmediate_h + +#include <wtf/Assertions.h> +#include <wtf/AlwaysInline.h> +#include <wtf/MathExtras.h> +#include <wtf/StdLibExtras.h> +#include "JSValue.h" +#include <limits> +#include <limits.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdlib.h> + +namespace JSC { + + class ExecState; + class JSCell; + class JSFastMath; + class JSGlobalData; + class JSObject; + class UString; + +#if USE(ALTERNATE_JSIMMEDIATE) + inline intptr_t reinterpretDoubleToIntptr(double value) + { + return WTF::bitwise_cast<intptr_t>(value); + } + + inline double reinterpretIntptrToDouble(intptr_t value) + { + return WTF::bitwise_cast<double>(value); + } +#endif + + /* + * A JSValue* is either a pointer to a cell (a heap-allocated object) or an immediate (a type-tagged + * value masquerading as a pointer). The low two bits in a JSValue* are available for type tagging + * because allocator alignment guarantees they will be 00 in cell pointers. + * + * For example, on a 32 bit system: + * + * JSCell*: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 00 + * [ high 30 bits: pointer address ] [ low 2 bits -- always 0 ] + * JSImmediate: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX TT + * [ high 30 bits: 'payload' ] [ low 2 bits -- tag ] + * + * Where the bottom two bits are non-zero they either indicate that the immediate is a 31 bit signed + * integer, or they mark the value as being an immediate of a type other than integer, with a secondary + * tag used to indicate the exact type. + * + * Where the lowest bit is set (TT is equal to 01 or 11) the high 31 bits form a 31 bit signed int value. + * Where TT is equal to 10 this indicates this is a type of immediate other than an integer, and the next + * two bits will form an extended tag. + * + * 31 bit signed int: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X1 + * [ high 30 bits of the value ] [ high bit part of value ] + * Other: YYYYYYYYYYYYYYYYYYYYYYYYYYYY ZZ 10 + * [ extended 'payload' ] [ extended tag ] [ tag 'other' ] + * + * Where the first bit of the extended tag is set this flags the value as being a boolean, and the following + * bit would flag the value as undefined. If neither bits are set, the value is null. + * + * Other: YYYYYYYYYYYYYYYYYYYYYYYYYYYY UB 10 + * [ extended 'payload' ] [ undefined | bool ] [ tag 'other' ] + * + * For boolean value the lowest bit in the payload holds the value of the bool, all remaining bits are zero. + * For undefined or null immediates the payload is zero. + * + * Boolean: 000000000000000000000000000V 01 10 + * [ boolean value ] [ bool ] [ tag 'other' ] + * Undefined: 0000000000000000000000000000 10 10 + * [ zero ] [ undefined ] [ tag 'other' ] + * Null: 0000000000000000000000000000 00 10 + * [ zero ] [ zero ] [ tag 'other' ] + */ + + /* + * On 64-bit platforms, we support an alternative encoding form for immediates, if + * USE(ALTERNATE_JSIMMEDIATE) is defined. When this format is used, double precision + * floating point values may also be encoded as JSImmediates. + * + * The encoding makes use of unused NaN space in the IEEE754 representation. Any value + * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values + * can encode a 51-bit payload. Hardware produced and C-library payloads typically + * have a payload of zero. We assume that non-zero payloads are available to encode + * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are + * all set represents a NaN with a non-zero payload, we can use this space in the NaN + * ranges to encode other values (however there are also other ranges of NaN space that + * could have been selected). This range of NaN space is represented by 64-bit numbers + * begining with the 16-bit hex patterns 0xFFFE and 0xFFFF - we rely on the fact that no + * valid double-precision numbers will begin fall in these ranges. + * + * The scheme we have implemented encodes double precision values by adding 2^48 to the + * 64-bit integer representation of the number. After this manipulation, no encoded + * double-precision value will begin with the pattern 0x0000 or 0xFFFF. + * + * The top 16-bits denote the type of the encoded JSImmediate: + * + * Pointer: 0000:PPPP:PPPP:PPPP + * 0001:****:****:**** + * Double:{ ... + * FFFE:****:****:**** + * Integer: FFFF:0000:IIII:IIII + * + * 32-bit signed integers are marked with the 16-bit tag 0xFFFF. The tag 0x0000 + * denotes a pointer, or another form of tagged immediate. Boolean, null and undefined + * values are encoded in the same manner as the default format. + */ + + class JSImmediate { +#ifdef QT_BUILD_SCRIPT_LIB + public: // QtScript needs isImmediate() and from() functions +#else + private: +#endif + friend class JIT; + friend class JSValue; + friend class JSFastMath; + friend JSValue jsNumber(ExecState* exec, double d); + friend JSValue jsNumber(ExecState*, char i); + friend JSValue jsNumber(ExecState*, unsigned char i); + friend JSValue jsNumber(ExecState*, short i); + friend JSValue jsNumber(ExecState*, unsigned short i); + friend JSValue jsNumber(ExecState* exec, int i); + friend JSValue jsNumber(ExecState* exec, unsigned i); + friend JSValue jsNumber(ExecState* exec, long i); + friend JSValue jsNumber(ExecState* exec, unsigned long i); + friend JSValue jsNumber(ExecState* exec, long long i); + friend JSValue jsNumber(ExecState* exec, unsigned long long i); + friend JSValue jsNumber(JSGlobalData* globalData, double d); + friend JSValue jsNumber(JSGlobalData* globalData, short i); + friend JSValue jsNumber(JSGlobalData* globalData, unsigned short i); + friend JSValue jsNumber(JSGlobalData* globalData, int i); + friend JSValue jsNumber(JSGlobalData* globalData, unsigned i); + friend JSValue jsNumber(JSGlobalData* globalData, long i); + friend JSValue jsNumber(JSGlobalData* globalData, unsigned long i); + friend JSValue jsNumber(JSGlobalData* globalData, long long i); + friend JSValue jsNumber(JSGlobalData* globalData, unsigned long long i); + +#if USE(ALTERNATE_JSIMMEDIATE) + // If all bits in the mask are set, this indicates an integer number, + // if any but not all are set this value is a double precision number. + static const intptr_t TagTypeNumber = 0xffff000000000000ll; + // This value is 2^48, used to encode doubles such that the encoded value will begin + // with a 16-bit pattern within the range 0x0001..0xFFFE. + static const intptr_t DoubleEncodeOffset = 0x1000000000000ll; +#else + static const intptr_t TagTypeNumber = 0x1; // bottom bit set indicates integer, this dominates the following bit +#endif + static const intptr_t TagBitTypeOther = 0x2; // second bit set indicates immediate other than an integer + static const intptr_t TagMask = TagTypeNumber | TagBitTypeOther; + + static const intptr_t ExtendedTagMask = 0xC; // extended tag holds a further two bits + static const intptr_t ExtendedTagBitBool = 0x4; + static const intptr_t ExtendedTagBitUndefined = 0x8; + + static const intptr_t FullTagTypeMask = TagMask | ExtendedTagMask; + static const intptr_t FullTagTypeBool = TagBitTypeOther | ExtendedTagBitBool; + static const intptr_t FullTagTypeUndefined = TagBitTypeOther | ExtendedTagBitUndefined; + static const intptr_t FullTagTypeNull = TagBitTypeOther; + +#if USE(ALTERNATE_JSIMMEDIATE) + static const int32_t IntegerPayloadShift = 0; +#else + static const int32_t IntegerPayloadShift = 1; +#endif + static const int32_t ExtendedPayloadShift = 4; + + static const intptr_t ExtendedPayloadBitBoolValue = 1 << ExtendedPayloadShift; + + static const int32_t signBit = 0x80000000; + + static ALWAYS_INLINE bool isImmediate(JSValue v) + { + return rawValue(v) & TagMask; + } + + static ALWAYS_INLINE bool isNumber(JSValue v) + { + return rawValue(v) & TagTypeNumber; + } + + static ALWAYS_INLINE bool isIntegerNumber(JSValue v) + { +#if USE(ALTERNATE_JSIMMEDIATE) + return (rawValue(v) & TagTypeNumber) == TagTypeNumber; +#else + return isNumber(v); +#endif + } + +#if USE(ALTERNATE_JSIMMEDIATE) + static ALWAYS_INLINE bool isDoubleNumber(JSValue v) + { + return isNumber(v) && !isIntegerNumber(v); + } +#endif + + static ALWAYS_INLINE bool isPositiveIntegerNumber(JSValue v) + { + // A single mask to check for the sign bit and the number tag all at once. + return (rawValue(v) & (signBit | TagTypeNumber)) == TagTypeNumber; + } + + static ALWAYS_INLINE bool isBoolean(JSValue v) + { + return (rawValue(v) & FullTagTypeMask) == FullTagTypeBool; + } + + static ALWAYS_INLINE bool isUndefinedOrNull(JSValue v) + { + // Undefined and null share the same value, bar the 'undefined' bit in the extended tag. + return (rawValue(v) & ~ExtendedTagBitUndefined) == FullTagTypeNull; + } + + static JSValue from(char); + static JSValue from(signed char); + static JSValue from(unsigned char); + static JSValue from(short); + static JSValue from(unsigned short); + static JSValue from(int); + static JSValue from(unsigned); + static JSValue from(long); + static JSValue from(unsigned long); + static JSValue from(long long); + static JSValue from(unsigned long long); + static JSValue from(double); + + static ALWAYS_INLINE bool isEitherImmediate(JSValue v1, JSValue v2) + { + return (rawValue(v1) | rawValue(v2)) & TagMask; + } + + static ALWAYS_INLINE bool areBothImmediate(JSValue v1, JSValue v2) + { + return isImmediate(v1) & isImmediate(v2); + } + + static ALWAYS_INLINE bool areBothImmediateIntegerNumbers(JSValue v1, JSValue v2) + { +#if USE(ALTERNATE_JSIMMEDIATE) + return (rawValue(v1) & rawValue(v2) & TagTypeNumber) == TagTypeNumber; +#else + return rawValue(v1) & rawValue(v2) & TagTypeNumber; +#endif + } + + static double toDouble(JSValue); + static bool toBoolean(JSValue); + static JSObject* toObject(JSValue, ExecState*); + static JSObject* toThisObject(JSValue, ExecState*); + static UString toString(JSValue); + + static bool getUInt32(JSValue, uint32_t&); + static bool getTruncatedInt32(JSValue, int32_t&); + static bool getTruncatedUInt32(JSValue, uint32_t&); + + static int32_t getTruncatedInt32(JSValue); + static uint32_t getTruncatedUInt32(JSValue); + + static JSValue trueImmediate(); + static JSValue falseImmediate(); + static JSValue undefinedImmediate(); + static JSValue nullImmediate(); + static JSValue zeroImmediate(); + static JSValue oneImmediate(); + + static JSObject* prototype(JSValue, ExecState*); + + private: +#if USE(ALTERNATE_JSIMMEDIATE) + static const int minImmediateInt = ((-INT_MAX) - 1); + static const int maxImmediateInt = INT_MAX; +#else + static const int minImmediateInt = ((-INT_MAX) - 1) >> IntegerPayloadShift; + static const int maxImmediateInt = INT_MAX >> IntegerPayloadShift; +#endif + static const unsigned maxImmediateUInt = maxImmediateInt; + + static ALWAYS_INLINE JSValue makeValue(intptr_t integer) + { + return JSValue::makeImmediate(integer); + } + + // With USE(ALTERNATE_JSIMMEDIATE) we want the argument to be zero extended, so the + // integer doesn't interfere with the tag bits in the upper word. In the default encoding, + // if intptr_t id larger then int32_t we sign extend the value through the upper word. +#if USE(ALTERNATE_JSIMMEDIATE) + static ALWAYS_INLINE JSValue makeInt(uint32_t value) +#else + static ALWAYS_INLINE JSValue makeInt(int32_t value) +#endif + { + return makeValue((static_cast<intptr_t>(value) << IntegerPayloadShift) | TagTypeNumber); + } + +#if USE(ALTERNATE_JSIMMEDIATE) + static ALWAYS_INLINE JSValue makeDouble(double value) + { + return makeValue(reinterpretDoubleToIntptr(value) + DoubleEncodeOffset); + } +#endif + + static ALWAYS_INLINE JSValue makeBool(bool b) + { + return makeValue((static_cast<intptr_t>(b) << ExtendedPayloadShift) | FullTagTypeBool); + } + + static ALWAYS_INLINE JSValue makeUndefined() + { + return makeValue(FullTagTypeUndefined); + } + + static ALWAYS_INLINE JSValue makeNull() + { + return makeValue(FullTagTypeNull); + } + + template<typename T> + static JSValue fromNumberOutsideIntegerRange(T); + +#if USE(ALTERNATE_JSIMMEDIATE) + static ALWAYS_INLINE double doubleValue(JSValue v) + { + return reinterpretIntptrToDouble(rawValue(v) - DoubleEncodeOffset); + } +#endif + + static ALWAYS_INLINE int32_t intValue(JSValue v) + { + return static_cast<int32_t>(rawValue(v) >> IntegerPayloadShift); + } + + static ALWAYS_INLINE uint32_t uintValue(JSValue v) + { + return static_cast<uint32_t>(rawValue(v) >> IntegerPayloadShift); + } + + static ALWAYS_INLINE bool boolValue(JSValue v) + { + return rawValue(v) & ExtendedPayloadBitBoolValue; + } + + static ALWAYS_INLINE intptr_t rawValue(JSValue v) + { + return v.immediateValue(); + } + + static double nonInlineNaN(); + }; + + ALWAYS_INLINE JSValue JSImmediate::trueImmediate() { return makeBool(true); } + ALWAYS_INLINE JSValue JSImmediate::falseImmediate() { return makeBool(false); } + ALWAYS_INLINE JSValue JSImmediate::undefinedImmediate() { return makeUndefined(); } + ALWAYS_INLINE JSValue JSImmediate::nullImmediate() { return makeNull(); } + ALWAYS_INLINE JSValue JSImmediate::zeroImmediate() { return makeInt(0); } + ALWAYS_INLINE JSValue JSImmediate::oneImmediate() { return makeInt(1); } + +#if USE(ALTERNATE_JSIMMEDIATE) + inline bool doubleToBoolean(double value) + { + return value < 0.0 || value > 0.0; + } + + ALWAYS_INLINE bool JSImmediate::toBoolean(JSValue v) + { + ASSERT(isImmediate(v)); + return isNumber(v) ? isIntegerNumber(v) ? v != zeroImmediate() + : doubleToBoolean(doubleValue(v)) : v == trueImmediate(); + } +#else + ALWAYS_INLINE bool JSImmediate::toBoolean(JSValue v) + { + ASSERT(isImmediate(v)); + return isIntegerNumber(v) ? v != zeroImmediate() : v == trueImmediate(); + } +#endif + + ALWAYS_INLINE uint32_t JSImmediate::getTruncatedUInt32(JSValue v) + { + // FIXME: should probably be asserting isPositiveIntegerNumber here. + ASSERT(isIntegerNumber(v)); + return intValue(v); + } + +#if USE(ALTERNATE_JSIMMEDIATE) + template<typename T> + inline JSValue JSImmediate::fromNumberOutsideIntegerRange(T value) + { + return makeDouble(static_cast<double>(value)); + } +#else + template<typename T> + inline JSValue JSImmediate::fromNumberOutsideIntegerRange(T) + { + return JSValue(); + } +#endif + + ALWAYS_INLINE JSValue JSImmediate::from(char i) + { + return makeInt(i); + } + + ALWAYS_INLINE JSValue JSImmediate::from(signed char i) + { + return makeInt(i); + } + + ALWAYS_INLINE JSValue JSImmediate::from(unsigned char i) + { + return makeInt(i); + } + + ALWAYS_INLINE JSValue JSImmediate::from(short i) + { + return makeInt(i); + } + + ALWAYS_INLINE JSValue JSImmediate::from(unsigned short i) + { + return makeInt(i); + } + + ALWAYS_INLINE JSValue JSImmediate::from(int i) + { +#if !USE(ALTERNATE_JSIMMEDIATE) + if ((i < minImmediateInt) | (i > maxImmediateInt)) + return fromNumberOutsideIntegerRange(i); +#endif + return makeInt(i); + } + + ALWAYS_INLINE JSValue JSImmediate::from(unsigned i) + { + if (i > maxImmediateUInt) + return fromNumberOutsideIntegerRange(i); + return makeInt(i); + } + + ALWAYS_INLINE JSValue JSImmediate::from(long i) + { + if ((i < minImmediateInt) | (i > maxImmediateInt)) + return fromNumberOutsideIntegerRange(i); + return makeInt(i); + } + + ALWAYS_INLINE JSValue JSImmediate::from(unsigned long i) + { + if (i > maxImmediateUInt) + return fromNumberOutsideIntegerRange(i); + return makeInt(i); + } + + ALWAYS_INLINE JSValue JSImmediate::from(long long i) + { + if ((i < minImmediateInt) | (i > maxImmediateInt)) + return JSValue(); + return makeInt(static_cast<intptr_t>(i)); + } + + ALWAYS_INLINE JSValue JSImmediate::from(unsigned long long i) + { + if (i > maxImmediateUInt) + return fromNumberOutsideIntegerRange(i); + return makeInt(static_cast<intptr_t>(i)); + } + + ALWAYS_INLINE JSValue JSImmediate::from(double d) + { + const int intVal = static_cast<int>(d); + + // Check for data loss from conversion to int. + if (intVal != d || (!intVal && signbit(d))) + return fromNumberOutsideIntegerRange(d); + + return from(intVal); + } + + ALWAYS_INLINE int32_t JSImmediate::getTruncatedInt32(JSValue v) + { + ASSERT(isIntegerNumber(v)); + return intValue(v); + } + + ALWAYS_INLINE double JSImmediate::toDouble(JSValue v) + { + ASSERT(isImmediate(v)); + + if (isIntegerNumber(v)) + return intValue(v); + +#if USE(ALTERNATE_JSIMMEDIATE) + if (isNumber(v)) { + ASSERT(isDoubleNumber(v)); + return doubleValue(v); + } +#else + ASSERT(!isNumber(v)); +#endif + + if (rawValue(v) == FullTagTypeUndefined) + return nonInlineNaN(); + + ASSERT(JSImmediate::isBoolean(v) || (v == JSImmediate::nullImmediate())); + return rawValue(v) >> ExtendedPayloadShift; + } + + ALWAYS_INLINE bool JSImmediate::getUInt32(JSValue v, uint32_t& i) + { + i = uintValue(v); + return isPositiveIntegerNumber(v); + } + + ALWAYS_INLINE bool JSImmediate::getTruncatedInt32(JSValue v, int32_t& i) + { + i = intValue(v); + return isIntegerNumber(v); + } + + ALWAYS_INLINE bool JSImmediate::getTruncatedUInt32(JSValue v, uint32_t& i) + { + return getUInt32(v, i); + } + + // These are identical logic to the JSValue functions above, and faster than jsNumber(number).toInt32(). + int32_t toInt32(double); + uint32_t toUInt32(double); + int32_t toInt32SlowCase(double, bool& ok); + uint32_t toUInt32SlowCase(double, bool& ok); + + inline JSValue::JSValue(JSNullTag) + { + *this = JSImmediate::nullImmediate(); + } + + inline JSValue::JSValue(JSUndefinedTag) + { + *this = JSImmediate::undefinedImmediate(); + } + + inline JSValue::JSValue(JSTrueTag) + { + *this = JSImmediate::trueImmediate(); + } + + inline JSValue::JSValue(JSFalseTag) + { + *this = JSImmediate::falseImmediate(); + } + + inline bool JSValue::isUndefinedOrNull() const + { + return JSImmediate::isUndefinedOrNull(asValue()); + } + + inline bool JSValue::isBoolean() const + { + return JSImmediate::isBoolean(asValue()); + } + + inline bool JSValue::getBoolean(bool& v) const + { + if (JSImmediate::isBoolean(asValue())) { + v = JSImmediate::toBoolean(asValue()); + return true; + } + + return false; + } + + inline bool JSValue::getBoolean() const + { + return asValue() == jsBoolean(true); + } + + ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const + { + int32_t i; + if (getTruncatedInt32(i)) + return i; + bool ignored; + return toInt32SlowCase(toNumber(exec), ignored); + } + + inline uint32_t JSValue::toUInt32(ExecState* exec) const + { + uint32_t i; + if (getTruncatedUInt32(i)) + return i; + bool ignored; + return toUInt32SlowCase(toNumber(exec), ignored); + } + + inline int32_t toInt32(double val) + { + if (!(val >= -2147483648.0 && val < 2147483648.0)) { + bool ignored; + return toInt32SlowCase(val, ignored); + } + return static_cast<int32_t>(val); + } + + inline uint32_t toUInt32(double val) + { + if (!(val >= 0.0 && val < 4294967296.0)) { + bool ignored; + return toUInt32SlowCase(val, ignored); + } + return static_cast<uint32_t>(val); + } + + inline int32_t JSValue::toInt32(ExecState* exec, bool& ok) const + { + int32_t i; + if (getTruncatedInt32(i)) { + ok = true; + return i; + } + return toInt32SlowCase(toNumber(exec), ok); + } + + inline uint32_t JSValue::toUInt32(ExecState* exec, bool& ok) const + { + uint32_t i; + if (getTruncatedUInt32(i)) { + ok = true; + return i; + } + return toUInt32SlowCase(toNumber(exec), ok); + } + + inline bool JSValue::isCell() const + { + return !JSImmediate::isImmediate(asValue()); + } + + inline bool JSValue::isInt32Fast() const + { + return JSImmediate::isIntegerNumber(asValue()); + } + + inline int32_t JSValue::getInt32Fast() const + { + ASSERT(isInt32Fast()); + return JSImmediate::getTruncatedInt32(asValue()); + } + + inline bool JSValue::isUInt32Fast() const + { + return JSImmediate::isPositiveIntegerNumber(asValue()); + } + + inline uint32_t JSValue::getUInt32Fast() const + { + ASSERT(isUInt32Fast()); + return JSImmediate::getTruncatedUInt32(asValue()); + } + + inline JSValue JSValue::makeInt32Fast(int32_t i) + { + return JSImmediate::from(i); + } + + inline bool JSValue::areBothInt32Fast(JSValue v1, JSValue v2) + { + return JSImmediate::areBothImmediateIntegerNumbers(v1, v2); + } + + class JSFastMath { + public: + static ALWAYS_INLINE bool canDoFastBitwiseOperations(JSValue v1, JSValue v2) + { + return JSImmediate::areBothImmediateIntegerNumbers(v1, v2); + } + + static ALWAYS_INLINE JSValue equal(JSValue v1, JSValue v2) + { + ASSERT(canDoFastBitwiseOperations(v1, v2)); + return jsBoolean(v1 == v2); + } + + static ALWAYS_INLINE JSValue notEqual(JSValue v1, JSValue v2) + { + ASSERT(canDoFastBitwiseOperations(v1, v2)); + return jsBoolean(v1 != v2); + } + + static ALWAYS_INLINE JSValue andImmediateNumbers(JSValue v1, JSValue v2) + { + ASSERT(canDoFastBitwiseOperations(v1, v2)); + return JSImmediate::makeValue(JSImmediate::rawValue(v1) & JSImmediate::rawValue(v2)); + } + + static ALWAYS_INLINE JSValue xorImmediateNumbers(JSValue v1, JSValue v2) + { + ASSERT(canDoFastBitwiseOperations(v1, v2)); + return JSImmediate::makeValue((JSImmediate::rawValue(v1) ^ JSImmediate::rawValue(v2)) | JSImmediate::TagTypeNumber); + } + + static ALWAYS_INLINE JSValue orImmediateNumbers(JSValue v1, JSValue v2) + { + ASSERT(canDoFastBitwiseOperations(v1, v2)); + return JSImmediate::makeValue(JSImmediate::rawValue(v1) | JSImmediate::rawValue(v2)); + } + + static ALWAYS_INLINE bool canDoFastRshift(JSValue v1, JSValue v2) + { + return JSImmediate::areBothImmediateIntegerNumbers(v1, v2); + } + + static ALWAYS_INLINE bool canDoFastUrshift(JSValue v1, JSValue v2) + { + return JSImmediate::areBothImmediateIntegerNumbers(v1, v2) && !(JSImmediate::rawValue(v1) & JSImmediate::signBit); + } + + static ALWAYS_INLINE JSValue rightShiftImmediateNumbers(JSValue val, JSValue shift) + { + ASSERT(canDoFastRshift(val, shift) || canDoFastUrshift(val, shift)); +#if USE(ALTERNATE_JSIMMEDIATE) + return JSImmediate::makeValue(static_cast<intptr_t>(static_cast<uint32_t>(static_cast<int32_t>(JSImmediate::rawValue(val)) >> ((JSImmediate::rawValue(shift) >> JSImmediate::IntegerPayloadShift) & 0x1f))) | JSImmediate::TagTypeNumber); +#else + return JSImmediate::makeValue((JSImmediate::rawValue(val) >> ((JSImmediate::rawValue(shift) >> JSImmediate::IntegerPayloadShift) & 0x1f)) | JSImmediate::TagTypeNumber); +#endif + } + + static ALWAYS_INLINE bool canDoFastAdditiveOperations(JSValue v) + { + // Number is non-negative and an operation involving two of these can't overflow. + // Checking for allowed negative numbers takes more time than it's worth on SunSpider. + return (JSImmediate::rawValue(v) & (JSImmediate::TagTypeNumber + (JSImmediate::signBit | (JSImmediate::signBit >> 1)))) == JSImmediate::TagTypeNumber; + } + + static ALWAYS_INLINE bool canDoFastAdditiveOperations(JSValue v1, JSValue v2) + { + // Number is non-negative and an operation involving two of these can't overflow. + // Checking for allowed negative numbers takes more time than it's worth on SunSpider. + return canDoFastAdditiveOperations(v1) && canDoFastAdditiveOperations(v2); + } + + static ALWAYS_INLINE JSValue addImmediateNumbers(JSValue v1, JSValue v2) + { + ASSERT(canDoFastAdditiveOperations(v1, v2)); + return JSImmediate::makeValue(JSImmediate::rawValue(v1) + JSImmediate::rawValue(v2) - JSImmediate::TagTypeNumber); + } + + static ALWAYS_INLINE JSValue subImmediateNumbers(JSValue v1, JSValue v2) + { + ASSERT(canDoFastAdditiveOperations(v1, v2)); + return JSImmediate::makeValue(JSImmediate::rawValue(v1) - JSImmediate::rawValue(v2) + JSImmediate::TagTypeNumber); + } + + static ALWAYS_INLINE JSValue incImmediateNumber(JSValue v) + { + ASSERT(canDoFastAdditiveOperations(v)); + return JSImmediate::makeValue(JSImmediate::rawValue(v) + (1 << JSImmediate::IntegerPayloadShift)); + } + + static ALWAYS_INLINE JSValue decImmediateNumber(JSValue v) + { + ASSERT(canDoFastAdditiveOperations(v)); + return JSImmediate::makeValue(JSImmediate::rawValue(v) - (1 << JSImmediate::IntegerPayloadShift)); + } + }; + +} // namespace JSC + +#endif // JSImmediate_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSLock.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSLock.cpp new file mode 100644 index 0000000..8f056c8 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSLock.cpp @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2005, 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 NU + * 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 "JSLock.h" + +#include "Collector.h" +#include "CallFrame.h" + +#if ENABLE(JSC_MULTIPLE_THREADS) +#include <pthread.h> +#endif + +namespace JSC { + +#if ENABLE(JSC_MULTIPLE_THREADS) + +// Acquire this mutex before accessing lock-related data. +static pthread_mutex_t JSMutex = PTHREAD_MUTEX_INITIALIZER; + +// Thread-specific key that tells whether a thread holds the JSMutex, and how many times it was taken recursively. +pthread_key_t JSLockCount; + +static void createJSLockCount() +{ + pthread_key_create(&JSLockCount, 0); +} + +pthread_once_t createJSLockCountOnce = PTHREAD_ONCE_INIT; + +// Lock nesting count. +intptr_t JSLock::lockCount() +{ + pthread_once(&createJSLockCountOnce, createJSLockCount); + + return reinterpret_cast<intptr_t>(pthread_getspecific(JSLockCount)); +} + +static void setLockCount(intptr_t count) +{ + ASSERT(count >= 0); + pthread_setspecific(JSLockCount, reinterpret_cast<void*>(count)); +} + +JSLock::JSLock(ExecState* exec) + : m_lockBehavior(exec->globalData().isSharedInstance ? LockForReal : SilenceAssertionsOnly) +{ + lock(m_lockBehavior); +} + +void JSLock::lock(JSLockBehavior lockBehavior) +{ +#ifdef NDEBUG + // Locking "not for real" is a debug-only feature. + if (lockBehavior == SilenceAssertionsOnly) + return; +#endif + + pthread_once(&createJSLockCountOnce, createJSLockCount); + + intptr_t currentLockCount = lockCount(); + if (!currentLockCount && lockBehavior == LockForReal) { + int result; + result = pthread_mutex_lock(&JSMutex); + ASSERT(!result); + } + setLockCount(currentLockCount + 1); +} + +void JSLock::unlock(JSLockBehavior lockBehavior) +{ + ASSERT(lockCount()); + +#ifdef NDEBUG + // Locking "not for real" is a debug-only feature. + if (lockBehavior == SilenceAssertionsOnly) + return; +#endif + + intptr_t newLockCount = lockCount() - 1; + setLockCount(newLockCount); + if (!newLockCount && lockBehavior == LockForReal) { + int result; + result = pthread_mutex_unlock(&JSMutex); + ASSERT(!result); + } +} + +void JSLock::lock(ExecState* exec) +{ + lock(exec->globalData().isSharedInstance ? LockForReal : SilenceAssertionsOnly); +} + +void JSLock::unlock(ExecState* exec) +{ + unlock(exec->globalData().isSharedInstance ? LockForReal : SilenceAssertionsOnly); +} + +bool JSLock::currentThreadIsHoldingLock() +{ + pthread_once(&createJSLockCountOnce, createJSLockCount); + return !!pthread_getspecific(JSLockCount); +} + +// 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 RegisterFile). +// Whenever a thread calls into JSC it starts using the RegisterFile from the +// previous 'high water mark' - the maximum point the stack has ever grown to +// (returned by RegisterFile::end()). So if a first thread calls out to a +// callback, and a second thread enters JSC, then also exits by calling out +// to a callback, we can be left with stackframes from both threads in the +// RegisterFile. As such, a problem may occur should the first thread's +// 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. +// +// In 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 re 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. +// +static unsigned lockDropDepth = 0; + +JSLock::DropAllLocks::DropAllLocks(ExecState* exec) + : m_lockBehavior(exec->globalData().isSharedInstance ? LockForReal : SilenceAssertionsOnly) +{ + pthread_once(&createJSLockCountOnce, createJSLockCount); + + if (lockDropDepth++) { + m_lockCount = 0; + return; + } + + m_lockCount = JSLock::lockCount(); + for (intptr_t i = 0; i < m_lockCount; i++) + JSLock::unlock(m_lockBehavior); +} + +JSLock::DropAllLocks::DropAllLocks(JSLockBehavior JSLockBehavior) + : m_lockBehavior(JSLockBehavior) +{ + pthread_once(&createJSLockCountOnce, createJSLockCount); + + if (lockDropDepth++) { + m_lockCount = 0; + return; + } + + // It is necessary to drop even "unreal" locks, because having a non-zero lock count + // will prevent a real lock from being taken. + + m_lockCount = JSLock::lockCount(); + for (intptr_t i = 0; i < m_lockCount; i++) + JSLock::unlock(m_lockBehavior); +} + +JSLock::DropAllLocks::~DropAllLocks() +{ + for (intptr_t i = 0; i < m_lockCount; i++) + JSLock::lock(m_lockBehavior); + + --lockDropDepth; +} + +#else + +JSLock::JSLock(ExecState*) + : m_lockBehavior(SilenceAssertionsOnly) +{ +} + +// If threading support is off, set the lock count to a constant value of 1 so ssertions +// that the lock is held don't fail +intptr_t JSLock::lockCount() +{ + return 1; +} + +bool JSLock::currentThreadIsHoldingLock() +{ + return true; +} + +void JSLock::lock(JSLockBehavior) +{ +} + +void JSLock::unlock(JSLockBehavior) +{ +} + +void JSLock::lock(ExecState*) +{ +} + +void JSLock::unlock(ExecState*) +{ +} + +JSLock::DropAllLocks::DropAllLocks(ExecState*) +{ +} + +JSLock::DropAllLocks::DropAllLocks(JSLockBehavior) +{ +} + +JSLock::DropAllLocks::~DropAllLocks() +{ +} + +#endif // USE(MULTIPLE_THREADS) + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSLock.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSLock.h new file mode 100644 index 0000000..8b015c4 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSLock.h @@ -0,0 +1,104 @@ +/* + * 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 + * 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 JSLock_h +#define JSLock_h + +#include <wtf/Assertions.h> +#include <wtf/Noncopyable.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 JSLock object in the scope where the lock + // must be held. 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. + + // For contexts other than the single shared one, implicit locking is not done, + // but we still need to perform all the counting in order to keep debug + // assertions working, so that clients that use the shared context don't break. + + class ExecState; + + enum JSLockBehavior { SilenceAssertionsOnly, LockForReal }; + + class JSLock : public Noncopyable { + public: + JSLock(ExecState*); + + JSLock(JSLockBehavior lockBehavior) + : m_lockBehavior(lockBehavior) + { +#ifdef NDEBUG + // Locking "not for real" is a debug-only feature. + if (lockBehavior == SilenceAssertionsOnly) + return; +#endif + lock(lockBehavior); + } + + ~JSLock() + { +#ifdef NDEBUG + // Locking "not for real" is a debug-only feature. + if (m_lockBehavior == SilenceAssertionsOnly) + return; +#endif + unlock(m_lockBehavior); + } + + static void lock(JSLockBehavior); + static void unlock(JSLockBehavior); + static void lock(ExecState*); + static void unlock(ExecState*); + + static intptr_t lockCount(); + static bool currentThreadIsHoldingLock(); + + JSLockBehavior m_lockBehavior; + + class DropAllLocks : public Noncopyable { + public: + DropAllLocks(ExecState* exec); + DropAllLocks(JSLockBehavior); + ~DropAllLocks(); + + private: + intptr_t m_lockCount; + JSLockBehavior m_lockBehavior; + }; + }; + +} // namespace + +#endif // JSLock_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNotAnObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNotAnObject.cpp new file mode 100644 index 0000000..fb9cfe8 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNotAnObject.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "config.h" +#include "JSNotAnObject.h" + +#include <wtf/UnusedParam.h> + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(JSNotAnObject); + +// JSValue methods +JSValue JSNotAnObject::toPrimitive(ExecState* exec, PreferredPrimitiveType) const +{ + ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + return m_exception; +} + +bool JSNotAnObject::getPrimitiveNumber(ExecState* exec, double&, JSValue&) +{ + ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + return false; +} + +bool JSNotAnObject::toBoolean(ExecState* exec) const +{ + ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + return false; +} + +double JSNotAnObject::toNumber(ExecState* exec) const +{ + ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + return NaN; +} + +UString JSNotAnObject::toString(ExecState* exec) const +{ + ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + return ""; +} + +JSObject* JSNotAnObject::toObject(ExecState* exec) const +{ + ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + return m_exception; +} + +// Marking +void JSNotAnObject::mark() +{ + JSCell::mark(); + if (!m_exception->marked()) + m_exception->mark(); +} + +// JSObject methods +bool JSNotAnObject::getOwnPropertySlot(ExecState* exec, const Identifier&, PropertySlot&) +{ + ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + return false; +} + +bool JSNotAnObject::getOwnPropertySlot(ExecState* exec, unsigned, PropertySlot&) +{ + ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + return false; +} + +void JSNotAnObject::put(ExecState* exec, const Identifier& , JSValue, PutPropertySlot&) +{ + ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); +} + +void JSNotAnObject::put(ExecState* exec, unsigned, JSValue) +{ + ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); +} + +bool JSNotAnObject::deleteProperty(ExecState* exec, const Identifier&) +{ + ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + return false; +} + +bool JSNotAnObject::deleteProperty(ExecState* exec, unsigned) +{ + ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + return false; +} + +void JSNotAnObject::getPropertyNames(ExecState* exec, PropertyNameArray&, unsigned) +{ + ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNotAnObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNotAnObject.h new file mode 100644 index 0000000..0aca63b --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNotAnObject.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSNotAnObject_h +#define JSNotAnObject_h + +#include "JSObject.h" + +namespace JSC { + + class JSNotAnObjectErrorStub : public JSObject { + public: + JSNotAnObjectErrorStub(ExecState* exec, bool isNull) + : JSObject(exec->globalData().notAnObjectErrorStubStructure) + , m_isNull(isNull) + { + } + + bool isNull() const { return m_isNull; } + + private: + virtual bool isNotAnObjectErrorStub() const { return true; } + + bool m_isNull; + }; + + // This unholy class is used to allow us to avoid multiple exception checks + // in certain SquirrelFish bytecodes -- effectively it just silently consumes + // any operations performed on the result of a failed toObject call. + class JSNotAnObject : public JSObject { + public: + JSNotAnObject(ExecState* exec, JSNotAnObjectErrorStub* exception) + : JSObject(exec->globalData().notAnObjectStructure) + , m_exception(exception) + { + } + + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType)); + } + + private: + // JSValue methods + virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; + virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue&); + virtual bool toBoolean(ExecState*) const; + virtual double toNumber(ExecState*) const; + virtual UString toString(ExecState*) const; + virtual JSObject* toObject(ExecState*) const; + + // Marking + virtual void mark(); + + // JSObject methods + virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); + virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); + + virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); + virtual void put(ExecState*, unsigned propertyName, JSValue); + + virtual bool deleteProperty(ExecState*, const Identifier& propertyName); + virtual bool deleteProperty(ExecState*, unsigned propertyName); + + virtual void getPropertyNames(ExecState*, PropertyNameArray&, unsigned listedAttributes = Structure::Prototype); + + JSNotAnObjectErrorStub* m_exception; + }; + +} // namespace JSC + +#endif // JSNotAnObject_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNumberCell.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNumberCell.cpp new file mode 100644 index 0000000..669440b --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNumberCell.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2004, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "JSNumberCell.h" + +#include "NumberObject.h" +#include "UString.h" + +namespace JSC { + +#if !USE(ALTERNATE_JSIMMEDIATE) + +JSValue JSNumberCell::toPrimitive(ExecState*, PreferredPrimitiveType) const +{ + return const_cast<JSNumberCell*>(this); +} + +bool JSNumberCell::getPrimitiveNumber(ExecState*, double& number, JSValue& value) +{ + number = m_value; + value = this; + return true; +} + +bool JSNumberCell::toBoolean(ExecState*) const +{ + return m_value < 0.0 || m_value > 0.0; // false for NaN +} + +double JSNumberCell::toNumber(ExecState*) const +{ + return m_value; +} + +UString JSNumberCell::toString(ExecState*) const +{ + if (m_value == 0.0) // +0.0 or -0.0 + return "0"; + return UString::from(m_value); +} + +UString JSNumberCell::toThisString(ExecState*) const +{ + if (m_value == 0.0) // +0.0 or -0.0 + return "0"; + return UString::from(m_value); +} + +JSObject* JSNumberCell::toObject(ExecState* exec) const +{ + return constructNumber(exec, const_cast<JSNumberCell*>(this)); +} + +JSObject* JSNumberCell::toThisObject(ExecState* exec) const +{ + return constructNumber(exec, const_cast<JSNumberCell*>(this)); +} + +bool JSNumberCell::getUInt32(uint32_t& uint32) const +{ + uint32 = static_cast<uint32_t>(m_value); + return uint32 == m_value; +} + +bool JSNumberCell::getTruncatedInt32(int32_t& int32) const +{ + if (!(m_value >= -2147483648.0 && m_value < 2147483648.0)) + return false; + int32 = static_cast<int32_t>(m_value); + return true; +} + +bool JSNumberCell::getTruncatedUInt32(uint32_t& uint32) const +{ + if (!(m_value >= 0.0 && m_value < 4294967296.0)) + return false; + uint32 = static_cast<uint32_t>(m_value); + return true; +} + +JSValue JSNumberCell::getJSNumber() +{ + return this; +} + +JSValue jsNumberCell(ExecState* exec, double d) +{ + return new (exec) JSNumberCell(exec, d); +} + +JSValue jsNumberCell(JSGlobalData* globalData, double d) +{ + return new (globalData) JSNumberCell(globalData, d); +} + +JSValue jsAPIMangledNumber(ExecState* exec, double d) +{ + return new (exec) JSNumberCell(JSNumberCell::APIMangled, d); +} + +#else + +JSValue jsNumberCell(ExecState*, double) +{ + ASSERT_NOT_REACHED(); + return JSValue(); +} + +JSValue jsAPIMangledNumber(ExecState*, double) +{ + ASSERT_NOT_REACHED(); + return JSValue(); +} + +#endif + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNumberCell.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNumberCell.h new file mode 100644 index 0000000..a35e210 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNumberCell.h @@ -0,0 +1,480 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003, 2004, 2005, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef JSNumberCell_h +#define JSNumberCell_h + +#include "CallFrame.h" +#include "JSCell.h" +#include "JSImmediate.h" +#include "Collector.h" +#include "UString.h" +#include <stddef.h> // for size_t + +namespace JSC { + + extern const double NaN; + extern const double Inf; + + JSValue jsNumberCell(ExecState*, double); + JSValue jsAPIMangledNumber(ExecState*, double); + +#if !USE(ALTERNATE_JSIMMEDIATE) + + class Identifier; + class JSCell; + class JSObject; + class JSString; + class PropertySlot; + + struct ClassInfo; + struct Instruction; + + class JSNumberCell : public JSCell { + friend class JIT; + friend JSValue jsNumberCell(JSGlobalData*, double); + friend JSValue jsNumberCell(ExecState*, double); + friend JSValue jsAPIMangledNumber(ExecState*, double); + public: + double value() const { return m_value; } + + virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; + virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value); + virtual bool toBoolean(ExecState*) const; + virtual double toNumber(ExecState*) const; + virtual UString toString(ExecState*) const; + virtual JSObject* toObject(ExecState*) const; + + virtual UString toThisString(ExecState*) const; + virtual JSObject* toThisObject(ExecState*) const; + virtual JSValue getJSNumber(); + + static const uintptr_t JSAPIMangledMagicNumber = 0xbbadbeef; + bool isAPIMangledNumber() const { return m_structure == reinterpret_cast<Structure*>(JSAPIMangledMagicNumber); } + + void* operator new(size_t size, ExecState* exec) + { + #ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE + return exec->heap()->inlineAllocateNumber(size); + #else + return exec->heap()->allocateNumber(size); + #endif + } + + void* operator new(size_t size, JSGlobalData* globalData) + { + #ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE + return globalData->heap.inlineAllocateNumber(size); + #else + return globalData->heap.allocateNumber(size); + #endif + } + + static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(NumberType, NeedsThisConversion)); } + + private: + JSNumberCell(JSGlobalData* globalData, double value) + : JSCell(globalData->numberStructure.get()) + , m_value(value) + { + } + + JSNumberCell(ExecState* exec, double value) + : JSCell(exec->globalData().numberStructure.get()) + , m_value(value) + { + } + + enum APIMangledTag { APIMangled }; + JSNumberCell(APIMangledTag, double value) + : JSCell(reinterpret_cast<Structure*>(JSAPIMangledMagicNumber)) + , m_value(value) + { + } + + virtual bool getUInt32(uint32_t&) const; + virtual bool getTruncatedInt32(int32_t&) const; + virtual bool getTruncatedUInt32(uint32_t&) const; + + double m_value; + }; + + JSValue jsNumberCell(JSGlobalData*, double); + + inline bool isNumberCell(JSValue v) + { + return v.isCell() && v.asCell()->isNumber(); + } + + inline JSNumberCell* asNumberCell(JSValue v) + { + ASSERT(isNumberCell(v)); + return static_cast<JSNumberCell*>(v.asCell()); + } + + + inline JSValue::JSValue(ExecState* exec, double d) + { + JSValue v = JSImmediate::from(d); + *this = v ? v : jsNumberCell(exec, d); + } + + inline JSValue::JSValue(ExecState* exec, int i) + { + JSValue v = JSImmediate::from(i); + *this = v ? v : jsNumberCell(exec, i); + } + + inline JSValue::JSValue(ExecState* exec, unsigned i) + { + JSValue v = JSImmediate::from(i); + *this = v ? v : jsNumberCell(exec, i); + } + + inline JSValue::JSValue(ExecState* exec, long i) + { + JSValue v = JSImmediate::from(i); + *this = v ? v : jsNumberCell(exec, i); + } + + inline JSValue::JSValue(ExecState* exec, unsigned long i) + { + JSValue v = JSImmediate::from(i); + *this = v ? v : jsNumberCell(exec, i); + } + + inline JSValue::JSValue(ExecState* exec, long long i) + { + JSValue v = JSImmediate::from(i); + *this = v ? v : jsNumberCell(exec, static_cast<double>(i)); + } + + inline JSValue::JSValue(ExecState* exec, unsigned long long i) + { + JSValue v = JSImmediate::from(i); + *this = v ? v : jsNumberCell(exec, static_cast<double>(i)); + } + + inline JSValue::JSValue(JSGlobalData* globalData, double d) + { + JSValue v = JSImmediate::from(d); + *this = v ? v : jsNumberCell(globalData, d); + } + + inline JSValue::JSValue(JSGlobalData* globalData, int i) + { + JSValue v = JSImmediate::from(i); + *this = v ? v : jsNumberCell(globalData, i); + } + + inline JSValue::JSValue(JSGlobalData* globalData, unsigned i) + { + JSValue v = JSImmediate::from(i); + *this = v ? v : jsNumberCell(globalData, i); + } + + inline JSValue::JSValue(JSGlobalData* globalData, long i) + { + JSValue v = JSImmediate::from(i); + *this = v ? v : jsNumberCell(globalData, i); + } + + inline JSValue::JSValue(JSGlobalData* globalData, unsigned long i) + { + JSValue v = JSImmediate::from(i); + *this = v ? v : jsNumberCell(globalData, i); + } + + inline JSValue::JSValue(JSGlobalData* globalData, long long i) + { + JSValue v = JSImmediate::from(i); + *this = v ? v : jsNumberCell(globalData, static_cast<double>(i)); + } + + inline JSValue::JSValue(JSGlobalData* globalData, unsigned long long i) + { + JSValue v = JSImmediate::from(i); + *this = v ? v : jsNumberCell(globalData, static_cast<double>(i)); + } + + inline bool JSValue::isDoubleNumber() const + { + return isNumberCell(asValue()); + } + + inline double JSValue::getDoubleNumber() const + { + return asNumberCell(asValue())->value(); + } + + inline bool JSValue::isNumber() const + { + return JSImmediate::isNumber(asValue()) || isDoubleNumber(); + } + + inline double JSValue::uncheckedGetNumber() const + { + ASSERT(isNumber()); + return JSImmediate::isImmediate(asValue()) ? JSImmediate::toDouble(asValue()) : getDoubleNumber(); + } + + inline bool JSValue::isAPIMangledNumber() + { + ASSERT(isNumber()); + return JSImmediate::isImmediate(asValue()) ? false : asNumberCell(asValue())->isAPIMangledNumber(); + } + +#else + + inline JSValue::JSValue(ExecState*, double d) + { + JSValue v = JSImmediate::from(d); + ASSERT(v); + *this = v; + } + + inline JSValue::JSValue(ExecState*, int i) + { + JSValue v = JSImmediate::from(i); + ASSERT(v); + *this = v; + } + + inline JSValue::JSValue(ExecState*, unsigned i) + { + JSValue v = JSImmediate::from(i); + ASSERT(v); + *this = v; + } + + inline JSValue::JSValue(ExecState*, long i) + { + JSValue v = JSImmediate::from(i); + ASSERT(v); + *this = v; + } + + inline JSValue::JSValue(ExecState*, unsigned long i) + { + JSValue v = JSImmediate::from(i); + ASSERT(v); + *this = v; + } + + inline JSValue::JSValue(ExecState*, long long i) + { + JSValue v = JSImmediate::from(static_cast<double>(i)); + ASSERT(v); + *this = v; + } + + inline JSValue::JSValue(ExecState*, unsigned long long i) + { + JSValue v = JSImmediate::from(static_cast<double>(i)); + ASSERT(v); + *this = v; + } + + inline JSValue::JSValue(JSGlobalData*, double d) + { + JSValue v = JSImmediate::from(d); + ASSERT(v); + *this = v; + } + + inline JSValue::JSValue(JSGlobalData*, int i) + { + JSValue v = JSImmediate::from(i); + ASSERT(v); + *this = v; + } + + inline JSValue::JSValue(JSGlobalData*, unsigned i) + { + JSValue v = JSImmediate::from(i); + ASSERT(v); + *this = v; + } + + inline JSValue::JSValue(JSGlobalData*, long i) + { + JSValue v = JSImmediate::from(i); + ASSERT(v); + *this = v; + } + + inline JSValue::JSValue(JSGlobalData*, unsigned long i) + { + JSValue v = JSImmediate::from(i); + ASSERT(v); + *this = v; + } + + inline JSValue::JSValue(JSGlobalData*, long long i) + { + JSValue v = JSImmediate::from(static_cast<double>(i)); + ASSERT(v); + *this = v; + } + + inline JSValue::JSValue(JSGlobalData*, unsigned long long i) + { + JSValue v = JSImmediate::from(static_cast<double>(i)); + ASSERT(v); + *this = v; + } + + inline bool JSValue::isDoubleNumber() const + { + return JSImmediate::isDoubleNumber(asValue()); + } + + inline double JSValue::getDoubleNumber() const + { + return JSImmediate::doubleValue(asValue()); + } + + inline bool JSValue::isNumber() const + { + return JSImmediate::isNumber(asValue()); + } + + inline double JSValue::uncheckedGetNumber() const + { + ASSERT(isNumber()); + return JSImmediate::toDouble(asValue()); + } + +#endif + + inline JSValue::JSValue(ExecState*, char i) + { + ASSERT(JSImmediate::from(i)); + *this = JSImmediate::from(i); + } + + inline JSValue::JSValue(ExecState*, unsigned char i) + { + ASSERT(JSImmediate::from(i)); + *this = JSImmediate::from(i); + } + + inline JSValue::JSValue(ExecState*, short i) + { + ASSERT(JSImmediate::from(i)); + *this = JSImmediate::from(i); + } + + inline JSValue::JSValue(ExecState*, unsigned short i) + { + ASSERT(JSImmediate::from(i)); + *this = JSImmediate::from(i); + } + + inline JSValue::JSValue(JSGlobalData*, char i) + { + ASSERT(JSImmediate::from(i)); + *this = JSImmediate::from(i); + } + + inline JSValue::JSValue(JSGlobalData*, unsigned char i) + { + ASSERT(JSImmediate::from(i)); + *this = JSImmediate::from(i); + } + + inline JSValue::JSValue(JSGlobalData*, short i) + { + ASSERT(JSImmediate::from(i)); + *this = JSImmediate::from(i); + } + + inline JSValue::JSValue(JSGlobalData*, unsigned short i) + { + ASSERT(JSImmediate::from(i)); + *this = JSImmediate::from(i); + } + + inline JSValue jsNaN(ExecState* exec) + { + return jsNumber(exec, NaN); + } + + inline JSValue jsNaN(JSGlobalData* globalData) + { + return jsNumber(globalData, NaN); + } + + // --- JSValue inlines ---------------------------- + + ALWAYS_INLINE JSValue JSValue::toJSNumber(ExecState* exec) const + { + return isNumber() ? asValue() : jsNumber(exec, this->toNumber(exec)); + } + + inline bool JSValue::getNumber(double &result) const + { + if (isInt32Fast()) + result = getInt32Fast(); + else if (LIKELY(isDoubleNumber())) + result = getDoubleNumber(); + else { + ASSERT(!isNumber()); + return false; + } + return true; + } + + inline bool JSValue::numberToInt32(int32_t& arg) + { + if (isInt32Fast()) + arg = getInt32Fast(); + else if (LIKELY(isDoubleNumber())) + arg = JSC::toInt32(getDoubleNumber()); + else { + ASSERT(!isNumber()); + return false; + } + return true; + } + + inline bool JSValue::numberToUInt32(uint32_t& arg) + { + if (isUInt32Fast()) + arg = getUInt32Fast(); + else if (LIKELY(isDoubleNumber())) + arg = JSC::toUInt32(getDoubleNumber()); + else if (isInt32Fast()) { + // FIXME: I think this case can be merged with the uint case; toUInt32SlowCase + // on a negative value is equivalent to simple static_casting. + bool ignored; + arg = toUInt32SlowCase(getInt32Fast(), ignored); + } else { + ASSERT(!isNumber()); + return false; + } + return true; + } + +} // namespace JSC + +#endif // JSNumberCell_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSONObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSONObject.cpp new file mode 100644 index 0000000..bbbe3af --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSONObject.cpp @@ -0,0 +1,766 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSONObject.h" + +#include "BooleanObject.h" +#include "Error.h" +#include "ExceptionHelpers.h" +#include "JSArray.h" +#include "LiteralParser.h" +#include "PropertyNameArray.h" +#include <wtf/MathExtras.h> + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(JSONObject); + +static JSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*, JSObject*, JSValue, const ArgList&); + +} + +#include "JSONObject.lut.h" + +namespace JSC { + +// PropertyNameForFunctionCall objects must be on the stack, since the JSValue that they create is not marked. +class PropertyNameForFunctionCall { +public: + PropertyNameForFunctionCall(const Identifier&); + PropertyNameForFunctionCall(unsigned); + + JSValue value(ExecState*) const; + +private: + const Identifier* m_identifier; + unsigned m_number; + mutable JSValue m_value; +}; + +class Stringifier : public Noncopyable { +public: + Stringifier(ExecState*, JSValue replacer, JSValue space); + ~Stringifier(); + JSValue stringify(JSValue); + + void mark(); + +private: + typedef UString StringBuilder; + + class Holder { + public: + Holder(JSObject*); + + JSObject* object() const { return m_object; } + + bool appendNextProperty(Stringifier&, StringBuilder&); + + private: + JSObject* const m_object; + const bool m_isArray; + bool m_isJSArray; + unsigned m_index; + unsigned m_size; + RefPtr<PropertyNameArrayData> m_propertyNames; + }; + + friend class Holder; + + static void appendQuotedString(StringBuilder&, const UString&); + + JSValue toJSON(JSValue, const PropertyNameForFunctionCall&); + + enum StringifyResult { StringifyFailed, StringifySucceeded, StringifyFailedDueToUndefinedValue }; + StringifyResult appendStringifiedValue(StringBuilder&, JSValue, JSObject* holder, const PropertyNameForFunctionCall&); + + bool willIndent() const; + void indent(); + void unindent(); + void startNewLine(StringBuilder&) const; + + Stringifier* const m_nextStringifierToMark; + ExecState* const m_exec; + const JSValue m_replacer; + bool m_usingArrayReplacer; + PropertyNameArray m_arrayReplacerPropertyNames; + CallType m_replacerCallType; + CallData m_replacerCallData; + const UString m_gap; + + HashSet<JSObject*> m_holderCycleDetector; + Vector<Holder, 16> m_holderStack; + UString m_repeatedGap; + UString m_indent; +}; + +// ------------------------------ helper functions -------------------------------- + +static inline JSValue unwrapBoxedPrimitive(JSValue value) +{ + if (!value.isObject()) + return value; + if (!asObject(value)->inherits(&NumberObject::info) && !asObject(value)->inherits(&StringObject::info) && !asObject(value)->inherits(&BooleanObject::info)) + return value; + return static_cast<JSWrapperObject*>(asObject(value))->internalValue(); +} + +static inline UString gap(JSValue space) +{ + space = unwrapBoxedPrimitive(space); + + // If the space value is a number, create a gap string with that number of spaces. + double spaceCount; + if (space.getNumber(spaceCount)) { + const int maxSpaceCount = 100; + int count; + if (spaceCount > maxSpaceCount) + count = maxSpaceCount; + else if (!(spaceCount > 0)) + count = 0; + else + count = static_cast<int>(spaceCount); + UChar spaces[maxSpaceCount]; + for (int i = 0; i < count; ++i) + spaces[i] = ' '; + return UString(spaces, count); + } + + // If the space value is a string, use it as the gap string, otherwise use no gap string. + return space.getString(); +} + +// ------------------------------ PropertyNameForFunctionCall -------------------------------- + +inline PropertyNameForFunctionCall::PropertyNameForFunctionCall(const Identifier& identifier) + : m_identifier(&identifier) +{ +} + +inline PropertyNameForFunctionCall::PropertyNameForFunctionCall(unsigned number) + : m_identifier(0) + , m_number(number) +{ +} + +JSValue PropertyNameForFunctionCall::value(ExecState* exec) const +{ + if (!m_value) { + if (m_identifier) + m_value = jsString(exec, m_identifier->ustring()); + else + m_value = jsNumber(exec, m_number); + } + return m_value; +} + +// ------------------------------ Stringifier -------------------------------- + +Stringifier::Stringifier(ExecState* exec, JSValue replacer, JSValue space) + : m_nextStringifierToMark(exec->globalData().firstStringifierToMark) + , m_exec(exec) + , m_replacer(replacer) + , m_usingArrayReplacer(false) + , m_arrayReplacerPropertyNames(exec) + , m_replacerCallType(CallTypeNone) + , m_gap(gap(space)) +{ + exec->globalData().firstStringifierToMark = this; + + if (!m_replacer.isObject()) + return; + + if (asObject(m_replacer)->inherits(&JSArray::info)) { + m_usingArrayReplacer = true; + JSObject* array = asObject(m_replacer); + unsigned length = array->get(exec, exec->globalData().propertyNames->length).toUInt32(exec); + for (unsigned i = 0; i < length; ++i) { + JSValue name = array->get(exec, i); + if (exec->hadException()) + break; + UString propertyName; + if (!name.getString(propertyName)) + continue; + if (exec->hadException()) + return; + m_arrayReplacerPropertyNames.add(Identifier(exec, propertyName)); + } + return; + } + + m_replacerCallType = asObject(m_replacer)->getCallData(m_replacerCallData); +} + +Stringifier::~Stringifier() +{ + ASSERT(m_exec->globalData().firstStringifierToMark == this); + m_exec->globalData().firstStringifierToMark = m_nextStringifierToMark; +} + +void Stringifier::mark() +{ + for (Stringifier* stringifier = this; stringifier; stringifier = stringifier->m_nextStringifierToMark) { + size_t size = m_holderStack.size(); + for (size_t i = 0; i < size; ++i) { + JSObject* object = m_holderStack[i].object(); + if (!object->marked()) + object->mark(); + } + } +} + +JSValue Stringifier::stringify(JSValue value) +{ + JSObject* object = constructEmptyObject(m_exec); + if (m_exec->hadException()) + return jsNull(); + + PropertyNameForFunctionCall emptyPropertyName(m_exec->globalData().propertyNames->emptyIdentifier); + object->putDirect(m_exec->globalData().propertyNames->emptyIdentifier, value); + + StringBuilder result; + if (appendStringifiedValue(result, value, object, emptyPropertyName) != StringifySucceeded) + return jsUndefined(); + if (m_exec->hadException()) + return jsNull(); + + return jsString(m_exec, result); +} + +void Stringifier::appendQuotedString(StringBuilder& builder, const UString& value) +{ + int length = value.size(); + + // String length plus 2 for quote marks plus 8 so we can accomodate a few escaped characters. + builder.reserveCapacity(builder.size() + length + 2 + 8); + + builder.append('"'); + + const UChar* data = value.data(); + 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]; + UChar hex[] = { '\\', 'u', hexDigits[(ch >> 12) & 0xF], hexDigits[(ch >> 8) & 0xF], hexDigits[(ch >> 4) & 0xF], hexDigits[ch & 0xF] }; + builder.append(hex, sizeof(hex) / sizeof(UChar)); + break; + } + } + + 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->globalData().propertyNames->toJSON)) + return value; + + JSValue toJSONFunction = asObject(value)->get(m_exec, m_exec->globalData().propertyNames->toJSON); + if (m_exec->hadException()) + return jsNull(); + + if (!toJSONFunction.isObject()) + return value; + + JSObject* object = asObject(toJSONFunction); + CallData callData; + CallType callType = object->getCallData(callData); + if (callType == CallTypeNone) + return value; + + JSValue list[] = { propertyName.value(m_exec) }; + ArgList args(list, sizeof(list) / sizeof(JSValue)); + return call(m_exec, object, callType, callData, value, args); +} + +Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder& builder, JSValue value, JSObject* holder, const PropertyNameForFunctionCall& propertyName) +{ + // Call the toJSON function. + value = toJSON(value, propertyName); + if (m_exec->hadException()) + return StringifyFailed; + if (value.isUndefined() && !holder->inherits(&JSArray::info)) + return StringifyFailedDueToUndefinedValue; + + // Call the replacer function. + if (m_replacerCallType != CallTypeNone) { + JSValue list[] = { propertyName.value(m_exec), value }; + ArgList args(list, sizeof(list) / sizeof(JSValue)); + value = call(m_exec, m_replacer, m_replacerCallType, m_replacerCallData, holder, args); + if (m_exec->hadException()) + return StringifyFailed; + } + + if (value.isNull()) { + builder.append("null"); + return StringifySucceeded; + } + + value = unwrapBoxedPrimitive(value); + + if (value.isBoolean()) { + builder.append(value.getBoolean() ? "true" : "false"); + return StringifySucceeded; + } + + UString stringValue; + if (value.getString(stringValue)) { + appendQuotedString(builder, stringValue); + return StringifySucceeded; + } + + double numericValue; + if (value.getNumber(numericValue)) { + if (!isfinite(numericValue)) + builder.append("null"); + else + builder.append(UString::from(numericValue)); + return StringifySucceeded; + } + + if (!value.isObject()) + return StringifyFailed; + + JSObject* object = asObject(value); + + // Handle cycle detection, and put the holder on the stack. + if (!m_holderCycleDetector.add(object).second) { + throwError(m_exec, TypeError); + return StringifyFailed; + } + bool holderStackWasEmpty = m_holderStack.isEmpty(); + m_holderStack.append(object); + if (!holderStackWasEmpty) + return StringifySucceeded; + + // If this is the outermost call, then loop to handle everything on the holder stack. + TimeoutChecker localTimeoutChecker(*m_exec->globalData().timeoutChecker); + localTimeoutChecker.reset(); + unsigned tickCount = localTimeoutChecker.ticksUntilNextCheck(); + do { + while (m_holderStack.last().appendNextProperty(*this, builder)) { + if (m_exec->hadException()) + return StringifyFailed; + if (!--tickCount) { + if (localTimeoutChecker.didTimeOut(m_exec)) { + m_exec->setException(createInterruptedExecutionException(&m_exec->globalData())); + return StringifyFailed; + } + tickCount = localTimeoutChecker.ticksUntilNextCheck(); + } + } + m_holderCycleDetector.remove(m_holderStack.last().object()); + m_holderStack.removeLast(); + } while (!m_holderStack.isEmpty()); + return StringifySucceeded; +} + +inline bool Stringifier::willIndent() const +{ + return !m_gap.isEmpty(); +} + +inline void Stringifier::indent() +{ + // Use a single shared string, m_repeatedGap, so we don't keep allocating new ones as we indent and unindent. + int newSize = m_indent.size() + m_gap.size(); + if (newSize > m_repeatedGap.size()) + m_repeatedGap.append(m_gap); + ASSERT(newSize <= m_repeatedGap.size()); + m_indent = m_repeatedGap.substr(0, newSize); +} + +inline void Stringifier::unindent() +{ + ASSERT(m_indent.size() >= m_gap.size()); + m_indent = m_repeatedGap.substr(0, m_indent.size() - m_gap.size()); +} + +inline void Stringifier::startNewLine(StringBuilder& builder) const +{ + if (m_gap.isEmpty()) + return; + builder.append('\n'); + builder.append(m_indent); +} + +inline Stringifier::Holder::Holder(JSObject* object) + : m_object(object) + , m_isArray(object->inherits(&JSArray::info)) + , m_index(0) +{ +} + +bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBuilder& builder) +{ + ASSERT(m_index <= m_size); + + ExecState* exec = stringifier.m_exec; + + // First time through, initialize. + if (!m_index) { + if (m_isArray) { + m_isJSArray = isJSArray(&exec->globalData(), m_object); + m_size = m_object->get(exec, exec->globalData().propertyNames->length).toUInt32(exec); + builder.append('['); + } else { + if (stringifier.m_usingArrayReplacer) + m_propertyNames = stringifier.m_arrayReplacerPropertyNames.data(); + else { + PropertyNameArray objectPropertyNames(exec); + m_object->getPropertyNames(exec, objectPropertyNames); + m_propertyNames = objectPropertyNames.releaseData(); + } + m_size = m_propertyNames->propertyNameVector().size(); + builder.append('{'); + } + stringifier.indent(); + } + + // Last time through, finish up and return false. + if (m_index == m_size) { + stringifier.unindent(); + if (m_size && builder[builder.size() - 1] != '{') + stringifier.startNewLine(builder); + builder.append(m_isArray ? ']' : '}'); + return false; + } + + // Handle a single element of the array or object. + unsigned index = m_index++; + unsigned rollBackPoint = 0; + StringifyResult stringifyResult; + if (m_isArray) { + // Get the value. + JSValue value; + if (m_isJSArray && asArray(m_object)->canGetIndex(index)) + value = asArray(m_object)->getIndex(index); + else { + PropertySlot slot(m_object); + if (!m_object->getOwnPropertySlot(exec, index, slot)) + slot.setUndefined(); + if (exec->hadException()) + return false; + value = slot.getValue(exec, index); + } + + // Append the separator string. + if (index) + builder.append(','); + stringifier.startNewLine(builder); + + // Append the stringified value. + stringifyResult = stringifier.appendStringifiedValue(builder, value, m_object, index); + } else { + // Get the value. + PropertySlot slot(m_object); + Identifier& propertyName = m_propertyNames->propertyNameVector()[index]; + if (!m_object->getOwnPropertySlot(exec, propertyName, slot)) + return true; + JSValue value = slot.getValue(exec, propertyName); + if (exec->hadException()) + return false; + + rollBackPoint = builder.size(); + + // Append the separator string. + if (builder[rollBackPoint - 1] != '{') + builder.append(','); + stringifier.startNewLine(builder); + + // Append the property name. + appendQuotedString(builder, propertyName.ustring()); + builder.append(':'); + if (stringifier.willIndent()) + builder.append(' '); + + // Append the stringified value. + stringifyResult = stringifier.appendStringifiedValue(builder, value, m_object, propertyName); + } + + // From this point on, no access to the this pointer or to any members, because the + // Holder object may have moved if the call to stringify pushed a new Holder onto + // m_holderStack. + + switch (stringifyResult) { + case StringifyFailed: + builder.append("null"); + break; + case StringifySucceeded: + break; + case StringifyFailedDueToUndefinedValue: + // This only occurs when get an undefined value for an object property. + // In this case we don't want the separator and property name that we + // already appended, so roll back. + builder = builder.substr(0, rollBackPoint); + break; + } + + return true; +} + +// ------------------------------ JSONObject -------------------------------- + +const ClassInfo JSONObject::info = { "JSON", 0, 0, ExecState::jsonTable }; + +/* Source for JSONObject.lut.h +@begin jsonTable + parse JSONProtoFuncParse DontEnum|Function 1 + stringify JSONProtoFuncStringify DontEnum|Function 1 +@end +*/ + +// ECMA 15.8 + +bool JSONObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +{ + const HashEntry* entry = ExecState::jsonTable(exec)->entry(exec, propertyName); + if (!entry) + return JSObject::getOwnPropertySlot(exec, propertyName, slot); + + ASSERT(entry->attributes() & Function); + setUpStaticFunctionSlot(exec, entry, this, propertyName, slot); + return true; +} + +void JSONObject::markStringifiers(Stringifier* stringifier) +{ + stringifier->mark(); +} + +class Walker { +public: + Walker(ExecState* exec, JSObject* function, CallType callType, CallData callData) + : m_exec(exec) + , m_function(function) + , m_callType(callType) + , m_callData(callData) + { + } + JSValue walk(JSValue unfiltered); +private: + JSValue callReviver(JSValue property, JSValue unfiltered) + { + JSValue args[] = { property, unfiltered }; + ArgList argList(args, 2); + return call(m_exec, m_function, m_callType, m_callData, jsNull(), argList); + } + + friend class Holder; + + ExecState* m_exec; + JSObject* m_function; + CallType m_callType; + CallData m_callData; +}; + +enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember, + ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember }; +NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) +{ + Vector<PropertyNameArray, 16> propertyStack; + Vector<uint32_t, 16> indexStack; + Vector<JSObject*, 16> objectStack; + Vector<JSArray*, 16> arrayStack; + + Vector<WalkerState, 16> stateStack; + WalkerState state = StateUnknown; + JSValue inValue = unfiltered; + JSValue outValue = jsNull(); + while (1) { + switch (state) { + arrayStartState: + case ArrayStartState: { + ASSERT(inValue.isObject()); + ASSERT(isJSArray(&m_exec->globalData(), asObject(inValue))); + JSArray* array = asArray(inValue); + arrayStack.append(array); + indexStack.append(0); + // fallthrough + } + arrayStartVisitMember: + case ArrayStartVisitMember: { + JSArray* array = arrayStack.last(); + uint32_t index = indexStack.last(); + if (index == array->length()) { + outValue = array; + arrayStack.removeLast(); + indexStack.removeLast(); + break; + } + inValue = array->getIndex(index); + if (inValue.isObject()) { + stateStack.append(ArrayEndVisitMember); + goto stateUnknown; + } else + outValue = inValue; + // fallthrough + } + case ArrayEndVisitMember: { + JSArray* array = arrayStack.last(); + array->setIndex(indexStack.last(), callReviver(jsString(m_exec, UString::from(indexStack.last())), outValue)); + if (m_exec->hadException()) + return jsNull(); + indexStack.last()++; + goto arrayStartVisitMember; + } + objectStartState: + case ObjectStartState: { + ASSERT(inValue.isObject()); + ASSERT(!isJSArray(&m_exec->globalData(), asObject(inValue))); + JSObject* object = asObject(inValue); + objectStack.append(object); + indexStack.append(0); + propertyStack.append(PropertyNameArray(m_exec)); + object->getPropertyNames(m_exec, propertyStack.last()); + // fallthrough + } + objectStartVisitMember: + case ObjectStartVisitMember: { + JSObject* object = objectStack.last(); + uint32_t index = indexStack.last(); + PropertyNameArray& properties = propertyStack.last(); + if (index == properties.size()) { + outValue = object; + objectStack.removeLast(); + indexStack.removeLast(); + propertyStack.removeLast(); + break; + } + PropertySlot slot; + object->getOwnPropertySlot(m_exec, properties[index], slot); + inValue = slot.getValue(m_exec, properties[index]); + ASSERT(!m_exec->hadException()); + if (inValue.isObject()) { + stateStack.append(ObjectEndVisitMember); + goto stateUnknown; + } else + outValue = inValue; + // fallthrough + } + case ObjectEndVisitMember: { + JSObject* object = objectStack.last(); + Identifier prop = propertyStack.last()[indexStack.last()]; + PutPropertySlot slot; + object->put(m_exec, prop, callReviver(jsString(m_exec, prop.ustring()), outValue), slot); + if (m_exec->hadException()) + return jsNull(); + indexStack.last()++; + goto objectStartVisitMember; + } + stateUnknown: + case StateUnknown: + if (!inValue.isObject()) { + outValue = inValue; + break; + } + if (isJSArray(&m_exec->globalData(), asObject(inValue))) + goto arrayStartState; + goto objectStartState; + } + if (stateStack.isEmpty()) + break; + state = stateStack.last(); + stateStack.removeLast(); + } + return callReviver(jsEmptyString(m_exec), outValue); +} + +// ECMA-262 v5 15.12.2 +JSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + if (args.isEmpty()) + return throwError(exec, GeneralError, "JSON.parse requires at least one parameter"); + JSValue value = args.at(0); + UString source = value.toString(exec); + if (exec->hadException()) + return jsNull(); + + LiteralParser jsonParser(exec, source, LiteralParser::StrictJSON); + JSValue unfiltered = jsonParser.tryLiteralParse(); + if (!unfiltered) + return throwError(exec, SyntaxError, "Unable to parse JSON string"); + + if (args.size() < 2) + return unfiltered; + + JSValue function = args.at(1); + CallData callData; + CallType callType = function.getCallData(callData); + if (callType == CallTypeNone) + return unfiltered; + return Walker(exec, asObject(function), callType, callData).walk(unfiltered); +} + +// ECMA-262 v5 15.12.3 +JSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + if (args.isEmpty()) + return throwError(exec, GeneralError, "No input to stringify"); + JSValue value = args.at(0); + JSValue replacer = args.at(1); + JSValue space = args.at(2); + return Stringifier(exec, replacer, space).stringify(value); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSONObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSONObject.h new file mode 100644 index 0000000..8d5364a --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSONObject.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSONObject_h +#define JSONObject_h + +#include "JSObject.h" + +namespace JSC { + + class Stringifier; + + class JSONObject : public JSObject { + public: + JSONObject(PassRefPtr<Structure> structure) + : JSObject(structure) + { + } + + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType)); + } + + static void markStringifiers(Stringifier*); + + private: + virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + }; + +} // namespace JSC + +#endif // JSONObject_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.cpp new file mode 100644 index 0000000..ded842d --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.cpp @@ -0,0 +1,546 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003, 2004, 2005, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007 Eric Seidel (eric@webkit.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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 "JSObject.h" + +#include "DatePrototype.h" +#include "ErrorConstructor.h" +#include "GetterSetter.h" +#include "JSGlobalObject.h" +#include "NativeErrorConstructor.h" +#include "ObjectPrototype.h" +#include "PropertyNameArray.h" +#include "Lookup.h" +#include "Nodes.h" +#include "Operations.h" +#include <math.h> +#include <wtf/Assertions.h> + +#define JSOBJECT_MARK_TRACING 0 + +#if JSOBJECT_MARK_TRACING + +#define JSOBJECT_MARK_BEGIN() \ + static int markStackDepth = 0; \ + for (int i = 0; i < markStackDepth; i++) \ + putchar('-'); \ + printf("%s (%p)\n", className().UTF8String().c_str(), this); \ + markStackDepth++; \ + +#define JSOBJECT_MARK_END() \ + markStackDepth--; + +#else // JSOBJECT_MARK_TRACING + +#define JSOBJECT_MARK_BEGIN() +#define JSOBJECT_MARK_END() + +#endif // JSOBJECT_MARK_TRACING + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(JSObject); + +void JSObject::mark() +{ + JSOBJECT_MARK_BEGIN(); + + JSCell::mark(); + m_structure->mark(); + + PropertyStorage storage = propertyStorage(); + + size_t storageSize = m_structure->propertyStorageSize(); + for (size_t i = 0; i < storageSize; ++i) { + JSValue v = JSValue::decode(storage[i]); + if (!v.marked()) + v.mark(); + } + + JSOBJECT_MARK_END(); +} + +UString JSObject::className() const +{ + const ClassInfo* info = classInfo(); + if (info) + return info->className; + return "Object"; +} + +bool JSObject::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) +{ + return getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot); +} + +static void throwSetterError(ExecState* exec) +{ + throwError(exec, TypeError, "setting a property that has only a getter"); +} + +// ECMA 8.6.2.2 +void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) +{ + ASSERT(value); + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); + + if (propertyName == exec->propertyNames().underscoreProto) { + // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla. + if (!value.isObject() && !value.isNull()) + return; + + JSValue nextPrototypeValue = value; + while (nextPrototypeValue && nextPrototypeValue.isObject()) { + JSObject* nextPrototype = asObject(nextPrototypeValue)->unwrappedObject(); + if (nextPrototype == this) { + throwError(exec, GeneralError, "cyclic __proto__ value"); + return; + } + nextPrototypeValue = nextPrototype->prototype(); + } + + setPrototype(value); + return; + } + + // Check if there are any setters or getters in the prototype chain + JSValue prototype; + for (JSObject* obj = this; !obj->structure()->hasGetterSetterProperties(); obj = asObject(prototype)) { + prototype = obj->prototype(); + if (prototype.isNull()) { + putDirectInternal(exec->globalData(), propertyName, value, 0, true, slot); + return; + } + } + + unsigned attributes; + JSCell* specificValue; + if ((m_structure->get(propertyName, attributes, specificValue) != WTF::notFound) && attributes & ReadOnly) + return; + + for (JSObject* obj = this; ; obj = asObject(prototype)) { + if (JSValue gs = obj->getDirect(propertyName)) { + if (gs.isGetterSetter()) { + JSObject* setterFunc = asGetterSetter(gs)->setter(); + if (!setterFunc) { + throwSetterError(exec); + return; + } + + CallData callData; + CallType callType = setterFunc->getCallData(callData); + MarkedArgumentBuffer args; + args.append(value); + call(exec, setterFunc, callType, callData, this, args); + return; + } + + // If there's an existing property on the object or one of its + // prototypes it should be replaced, so break here. + break; + } + + prototype = obj->prototype(); + if (prototype.isNull()) + break; + } + + putDirectInternal(exec->globalData(), propertyName, value, 0, true, slot); + return; +} + +void JSObject::put(ExecState* exec, unsigned propertyName, JSValue value) +{ + PutPropertySlot slot; + put(exec, Identifier::from(exec, propertyName), value, slot); +} + +void JSObject::putWithAttributes(ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot) +{ + putDirectInternal(exec->globalData(), propertyName, value, attributes, checkReadOnly, slot); +} + +void JSObject::putWithAttributes(ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes) +{ + putDirectInternal(exec->globalData(), propertyName, value, attributes); +} + +void JSObject::putWithAttributes(ExecState* exec, unsigned propertyName, JSValue value, unsigned attributes) +{ + putWithAttributes(exec, Identifier::from(exec, propertyName), value, attributes); +} + +bool JSObject::hasProperty(ExecState* exec, const Identifier& propertyName) const +{ + PropertySlot slot; + return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot); +} + +bool JSObject::hasProperty(ExecState* exec, unsigned propertyName) const +{ + PropertySlot slot; + return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot); +} + +// ECMA 8.6.2.5 +bool JSObject::deleteProperty(ExecState* exec, const Identifier& propertyName, bool checkDontDelete) +{ + unsigned attributes; + JSCell* specificValue; + if (m_structure->get(propertyName, attributes, specificValue) != WTF::notFound) { + if ((attributes & DontDelete) && checkDontDelete) + return false; + removeDirect(propertyName); + return true; + } + + // Look in the static hashtable of properties + const HashEntry* entry = findPropertyHashEntry(exec, propertyName); + if (entry && (entry->attributes() & DontDelete) && checkDontDelete) + return false; // this builtin property can't be deleted + + // FIXME: Should the code here actually do some deletion? + return true; +} + +bool JSObject::hasOwnProperty(ExecState* exec, const Identifier& propertyName) const +{ + PropertySlot slot; + return const_cast<JSObject*>(this)->getOwnPropertySlot(exec, propertyName, slot); +} + +bool JSObject::deleteProperty(ExecState* exec, unsigned propertyName, bool checkDontDelete) +{ + return deleteProperty(exec, Identifier::from(exec, propertyName), checkDontDelete); +} + +static ALWAYS_INLINE JSValue callDefaultValueFunction(ExecState* exec, const JSObject* object, const Identifier& propertyName) +{ + JSValue function = object->get(exec, propertyName); + CallData callData; + CallType callType = function.getCallData(callData); + if (callType == CallTypeNone) + return exec->exception(); + + // Prevent "toString" and "valueOf" from observing execution if an exception + // is pending. + if (exec->hadException()) + return exec->exception(); + + JSValue result = call(exec, function, callType, callData, const_cast<JSObject*>(object), exec->emptyList()); + ASSERT(!result.isGetterSetter()); + if (exec->hadException()) + return exec->exception(); + if (result.isObject()) + return JSValue(); + return result; +} + +bool JSObject::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result) +{ + result = defaultValue(exec, PreferNumber); + number = result.toNumber(exec); + return !result.isString(); +} + +// ECMA 8.6.2.6 +JSValue JSObject::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const +{ + // Must call toString first for Date objects. + if ((hint == PreferString) || (hint != PreferNumber && prototype() == exec->lexicalGlobalObject()->datePrototype())) { + JSValue value = callDefaultValueFunction(exec, this, exec->propertyNames().toString); + if (value) + return value; + value = callDefaultValueFunction(exec, this, exec->propertyNames().valueOf); + if (value) + return value; + } else { + JSValue value = callDefaultValueFunction(exec, this, exec->propertyNames().valueOf); + if (value) + return value; + value = callDefaultValueFunction(exec, this, exec->propertyNames().toString); + if (value) + return value; + } + + ASSERT(!exec->hadException()); + + return throwError(exec, TypeError, "No default value"); +} + +const HashEntry* JSObject::findPropertyHashEntry(ExecState* exec, const Identifier& propertyName) const +{ + for (const ClassInfo* info = classInfo(); info; info = info->parentClass) { + if (const HashTable* propHashTable = info->propHashTable(exec)) { + if (const HashEntry* entry = propHashTable->entry(exec, propertyName)) + return entry; + } + } + return 0; +} + +void JSObject::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction) +{ + JSValue object = getDirect(propertyName); + if (object && object.isGetterSetter()) { + ASSERT(m_structure->hasGetterSetterProperties()); + asGetterSetter(object)->setGetter(getterFunction); + return; + } + + PutPropertySlot slot; + GetterSetter* getterSetter = new (exec) GetterSetter; + putDirectInternal(exec->globalData(), propertyName, getterSetter, Getter, true, slot); + + // putDirect will change our Structure if we add a new property. For + // getters and setters, though, we also need to change our Structure + // if we override an existing non-getter or non-setter. + if (slot.type() != PutPropertySlot::NewProperty) { + if (!m_structure->isDictionary()) { + RefPtr<Structure> structure = Structure::getterSetterTransition(m_structure); + setStructure(structure.release()); + } + } + + m_structure->setHasGetterSetterProperties(true); + getterSetter->setGetter(getterFunction); +} + +void JSObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction) +{ + JSValue object = getDirect(propertyName); + if (object && object.isGetterSetter()) { + ASSERT(m_structure->hasGetterSetterProperties()); + asGetterSetter(object)->setSetter(setterFunction); + return; + } + + PutPropertySlot slot; + GetterSetter* getterSetter = new (exec) GetterSetter; + putDirectInternal(exec->globalData(), propertyName, getterSetter, Setter, true, slot); + + // putDirect will change our Structure if we add a new property. For + // getters and setters, though, we also need to change our Structure + // if we override an existing non-getter or non-setter. + if (slot.type() != PutPropertySlot::NewProperty) { + if (!m_structure->isDictionary()) { + RefPtr<Structure> structure = Structure::getterSetterTransition(m_structure); + setStructure(structure.release()); + } + } + + m_structure->setHasGetterSetterProperties(true); + getterSetter->setSetter(setterFunction); +} + +JSValue JSObject::lookupGetter(ExecState*, const Identifier& propertyName) +{ + JSObject* object = this; + while (true) { + if (JSValue value = object->getDirect(propertyName)) { + if (!value.isGetterSetter()) + return jsUndefined(); + JSObject* functionObject = asGetterSetter(value)->getter(); + if (!functionObject) + return jsUndefined(); + return functionObject; + } + + if (!object->prototype() || !object->prototype().isObject()) + return jsUndefined(); + object = asObject(object->prototype()); + } +} + +JSValue JSObject::lookupSetter(ExecState*, const Identifier& propertyName) +{ + JSObject* object = this; + while (true) { + if (JSValue value = object->getDirect(propertyName)) { + if (!value.isGetterSetter()) + return jsUndefined(); + JSObject* functionObject = asGetterSetter(value)->setter(); + if (!functionObject) + return jsUndefined(); + return functionObject; + } + + if (!object->prototype() || !object->prototype().isObject()) + return jsUndefined(); + object = asObject(object->prototype()); + } +} + +bool JSObject::hasInstance(ExecState* exec, JSValue value, JSValue proto) +{ + if (!value.isObject()) + return false; + + if (!proto.isObject()) { + throwError(exec, TypeError, "instanceof called on an object with an invalid prototype property."); + return false; + } + + JSObject* object = asObject(value); + while ((object = object->prototype().getObject())) { + if (proto == object) + return true; + } + return false; +} + +bool JSObject::propertyIsEnumerable(ExecState* exec, const Identifier& propertyName) const +{ + unsigned attributes; + if (!getPropertyAttributes(exec, propertyName, attributes)) + return false; + return !(attributes & DontEnum); +} + +bool JSObject::getPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const +{ + JSCell* specificValue; + if (m_structure->get(propertyName, attributes, specificValue) != WTF::notFound) + return true; + + // Look in the static hashtable of properties + const HashEntry* entry = findPropertyHashEntry(exec, propertyName); + if (entry) { + attributes = entry->attributes(); + return true; + } + + return false; +} + +bool JSObject::getPropertySpecificValue(ExecState*, const Identifier& propertyName, JSCell*& specificValue) const +{ + unsigned attributes; + if (m_structure->get(propertyName, attributes, specificValue) != WTF::notFound) + 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(ExecState* exec, PropertyNameArray& propertyNames, unsigned listedAttributes) +{ + m_structure->getPropertyNames(exec, propertyNames, this, listedAttributes); +} + +bool JSObject::toBoolean(ExecState*) const +{ + return true; +} + +double JSObject::toNumber(ExecState* exec) const +{ + JSValue primitive = toPrimitive(exec, PreferNumber); + if (exec->hadException()) // should be picked up soon in Nodes.cpp + return 0.0; + return primitive.toNumber(exec); +} + +UString JSObject::toString(ExecState* exec) const +{ + JSValue primitive = toPrimitive(exec, PreferString); + if (exec->hadException()) + return ""; + return primitive.toString(exec); +} + +JSObject* JSObject::toObject(ExecState*) const +{ + return const_cast<JSObject*>(this); +} + +JSObject* JSObject::toThisObject(ExecState*) const +{ + return const_cast<JSObject*>(this); +} + +JSObject* JSObject::unwrappedObject() +{ + return this; +} + +void JSObject::removeDirect(const Identifier& propertyName) +{ + size_t offset; + if (m_structure->isDictionary()) { + offset = m_structure->removePropertyWithoutTransition(propertyName); + if (offset != WTF::notFound) + putDirectOffset(offset, jsUndefined()); + return; + } + + RefPtr<Structure> structure = Structure::removePropertyTransition(m_structure, propertyName, offset); + setStructure(structure.release()); + if (offset != WTF::notFound) + putDirectOffset(offset, jsUndefined()); +} + +void JSObject::putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr) +{ + putDirectFunction(Identifier(exec, function->name(&exec->globalData())), function, attr); +} + +void JSObject::putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr) +{ + putDirectFunctionWithoutTransition(Identifier(exec, function->name(&exec->globalData())), function, attr); +} + +NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue* location) +{ + if (JSObject* getterFunction = asGetterSetter(*location)->getter()) + slot.setGetterSlot(getterFunction); + else + slot.setUndefined(); +} + +Structure* JSObject::createInheritorID() +{ +#ifdef QT_BUILD_SCRIPT_LIB + // ### QtScript needs the hasOwnProperty() calls etc. for QScriptObject + m_inheritorID = Structure::create(this, TypeInfo(ObjectType, ImplementsHasInstance)); +#else + m_inheritorID = JSObject::createStructure(this); +#endif + return m_inheritorID.get(); +} + +void JSObject::allocatePropertyStorage(size_t oldSize, size_t newSize) +{ + allocatePropertyStorageInline(oldSize, newSize); +} + +JSObject* constructEmptyObject(ExecState* exec) +{ + return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure()); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.h new file mode 100644 index 0000000..15b7957 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.h @@ -0,0 +1,629 @@ +/* + * 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 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef JSObject_h +#define JSObject_h + +#include "ArgList.h" +#include "ClassInfo.h" +#include "CommonIdentifiers.h" +#include "CallFrame.h" +#include "JSNumberCell.h" +#include "PropertySlot.h" +#include "PutPropertySlot.h" +#include "ScopeChain.h" +#include "Structure.h" +#include "JSGlobalData.h" + +namespace JSC { + + inline JSCell* getJSFunction(JSGlobalData& globalData, JSValue value) + { + if (value.isCell() && (value.asCell()->vptr() == globalData.jsFunctionVPtr)) + return value.asCell(); + return 0; + } + + class InternalFunction; + class PropertyNameArray; + class Structure; + struct HashEntry; + struct HashTable; + + // 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 + Getter = 1 << 5, // property is a getter + Setter = 1 << 6 // property is a setter + }; + + typedef EncodedJSValue* PropertyStorage; + typedef const EncodedJSValue* ConstPropertyStorage; + + class JSObject : public JSCell { + friend class BatchedTransitionOptimizer; + friend class JIT; + friend class JSCell; + + public: + explicit JSObject(PassRefPtr<Structure>); + + virtual void mark(); + + // The inline virtual destructor cannot be the first virtual function declared + // in the class as it results in the vtable being generated as a weak symbol + virtual ~JSObject(); + + bool inherits(const ClassInfo* classInfo) const { return JSCell::isObject(classInfo); } + + JSValue prototype() const; + void setPrototype(JSValue prototype); + + void setStructure(PassRefPtr<Structure>); + Structure* inheritorID(); + + virtual UString className() const; + + JSValue get(ExecState*, const Identifier& propertyName) const; + JSValue get(ExecState*, unsigned propertyName) const; + + bool getPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); + bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); + + virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); + virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); + + virtual void put(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot&); + virtual void put(ExecState*, unsigned propertyName, JSValue value); + + virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot); + virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes); + virtual void putWithAttributes(ExecState*, unsigned propertyName, JSValue value, unsigned attributes); + + bool propertyIsEnumerable(ExecState*, const Identifier& propertyName) const; + + bool hasProperty(ExecState*, const Identifier& propertyName) const; + bool hasProperty(ExecState*, unsigned propertyName) const; + bool hasOwnProperty(ExecState*, const Identifier& propertyName) const; + + virtual bool deleteProperty(ExecState*, const Identifier& propertyName, bool checkDontDelete = true); + virtual bool deleteProperty(ExecState*, unsigned propertyName, bool checkDontDelete = true); + + virtual JSValue defaultValue(ExecState*, PreferredPrimitiveType) const; + + virtual bool hasInstance(ExecState*, JSValue, JSValue prototypeProperty); + virtual void getPropertyNames(ExecState*, PropertyNameArray&, unsigned listedAttributes = Structure::Prototype); + + virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const; + virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value); + virtual bool toBoolean(ExecState*) const; + virtual double toNumber(ExecState*) const; + virtual UString toString(ExecState*) const; + virtual JSObject* toObject(ExecState*) const; + + virtual JSObject* toThisObject(ExecState*) const; + virtual JSObject* unwrappedObject(); + + virtual bool getPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned& attributes) const; + bool getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificFunction) const; + + // This get function only looks at the property map. + JSValue getDirect(const Identifier& propertyName) const + { + size_t offset = m_structure->get(propertyName); + return offset != WTF::notFound ? getDirectOffset(offset) : JSValue(); + } + + JSValue* getDirectLocation(const Identifier& propertyName) + { + size_t offset = m_structure->get(propertyName); + return offset != WTF::notFound ? locationForOffset(offset) : 0; + } + + JSValue* getDirectLocation(const Identifier& propertyName, unsigned& attributes) + { + JSCell* specificFunction; + size_t offset = m_structure->get(propertyName, attributes, specificFunction); + return offset != WTF::notFound ? locationForOffset(offset) : 0; + } + + size_t offsetForLocation(JSValue* location) const + { + return location - reinterpret_cast<const JSValue*>(propertyStorage()); + } + + void transitionTo(Structure*); + + void removeDirect(const Identifier& propertyName); + bool hasCustomProperties() { return !m_structure->isEmpty(); } + bool hasGetterSetterProperties() { return m_structure->hasGetterSetterProperties(); } + + void putDirect(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot); + void putDirect(const Identifier& propertyName, JSValue value, unsigned attr = 0); + + void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr = 0); + void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot); + void putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr = 0); + + void putDirectWithoutTransition(const Identifier& propertyName, JSValue value, unsigned attr = 0); + void putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attr = 0); + void putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr = 0); + + // Fast access to known property offsets. + JSValue getDirectOffset(size_t offset) const { return JSValue::decode(propertyStorage()[offset]); } + void putDirectOffset(size_t offset, JSValue value) { propertyStorage()[offset] = JSValue::encode(value); } + + void fillGetterPropertySlot(PropertySlot&, JSValue* location); + + virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunction); + virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunction); + virtual JSValue lookupGetter(ExecState*, const Identifier& propertyName); + virtual JSValue lookupSetter(ExecState*, const Identifier& propertyName); + + virtual bool isGlobalObject() const { return false; } + virtual bool isVariableObject() const { return false; } + virtual bool isActivationObject() const { return false; } + virtual bool isWatchdogException() const { return false; } + virtual bool isNotAnObjectErrorStub() const { return false; } + + void allocatePropertyStorage(size_t oldSize, size_t newSize); + void allocatePropertyStorageInline(size_t oldSize, size_t newSize); + bool isUsingInlineStorage() const { return m_structure->isUsingInlineStorage(); } + + static const size_t inlineStorageCapacity = 3; + static const size_t nonInlineBaseStorageCapacity = 16; + + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot)); + } + + private: + ConstPropertyStorage propertyStorage() const { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); } + PropertyStorage propertyStorage() { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); } + + const JSValue* locationForOffset(size_t offset) const + { + return reinterpret_cast<const JSValue*>(&propertyStorage()[offset]); + } + + JSValue* locationForOffset(size_t offset) + { + return reinterpret_cast<JSValue*>(&propertyStorage()[offset]); + } + + void putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot, JSCell*); + void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot); + void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr = 0); + + bool inlineGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); + + const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const; + Structure* createInheritorID(); + + RefPtr<Structure> m_inheritorID; + + union { + PropertyStorage m_externalStorage; + EncodedJSValue m_inlineStorage[inlineStorageCapacity]; + }; + }; + + JSObject* asObject(JSValue); + + JSObject* constructEmptyObject(ExecState*); + +inline JSObject* asObject(JSValue value) +{ + ASSERT(asCell(value)->isObject()); + return static_cast<JSObject*>(asCell(value)); +} + +inline JSObject::JSObject(PassRefPtr<Structure> structure) + : JSCell(structure.releaseRef()) // ~JSObject balances this ref() +{ + ASSERT(m_structure); + ASSERT(m_structure->propertyStorageCapacity() == inlineStorageCapacity); + ASSERT(m_structure->isEmpty()); + ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype())); +} + +inline JSObject::~JSObject() +{ + ASSERT(m_structure); + if (!isUsingInlineStorage()) + delete [] m_externalStorage; + m_structure->deref(); +} + +inline JSValue JSObject::prototype() const +{ + return m_structure->storedPrototype(); +} + +inline void JSObject::setPrototype(JSValue prototype) +{ + ASSERT(prototype); + RefPtr<Structure> newStructure = Structure::changePrototypeTransition(m_structure, prototype); + setStructure(newStructure.release()); +} + +inline void JSObject::setStructure(PassRefPtr<Structure> structure) +{ + m_structure->deref(); + m_structure = structure.releaseRef(); // ~JSObject balances this ref() +} + +inline Structure* JSObject::inheritorID() +{ + if (m_inheritorID) + return m_inheritorID.get(); + return createInheritorID(); +} + +inline bool Structure::isUsingInlineStorage() const +{ + return (propertyStorageCapacity() == JSObject::inlineStorageCapacity); +} + +inline bool JSCell::isObject(const ClassInfo* info) const +{ + for (const ClassInfo* ci = classInfo(); ci; ci = ci->parentClass) { + if (ci == info) + return true; + } + return false; +} + +// this method is here to be after the inline declaration of JSCell::isObject +inline bool JSValue::isObject(const ClassInfo* classInfo) const +{ + return isCell() && asCell()->isObject(classInfo); +} + +ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +{ + if (JSValue* location = getDirectLocation(propertyName)) { + if (m_structure->hasGetterSetterProperties() && location[0].isGetterSetter()) + fillGetterPropertySlot(slot, location); + else + slot.setValueSlot(this, location, offsetForLocation(location)); + return true; + } + + // non-standard Netscape extension + if (propertyName == exec->propertyNames().underscoreProto) { + slot.setValue(prototype()); + return true; + } + + return false; +} + +// It may seem crazy to inline a function this large, especially a virtual function, +// but it makes a big difference to property lookup that derived classes can inline their +// base class call to this. +ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +{ + return inlineGetOwnPropertySlot(exec, propertyName, slot); +} + +ALWAYS_INLINE bool JSCell::fastGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +{ + if (structure()->typeInfo().hasStandardGetOwnPropertySlot()) + return asObject(this)->inlineGetOwnPropertySlot(exec, propertyName, slot); + return getOwnPropertySlot(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 +inline bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +{ + JSObject* object = this; + while (true) { + if (object->fastGetOwnPropertySlot(exec, propertyName, slot)) + return true; + JSValue prototype = object->prototype(); + if (!prototype.isObject()) + return false; + object = asObject(prototype); + } +} + +inline bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) +{ + JSObject* object = this; + while (true) { + if (object->getOwnPropertySlot(exec, propertyName, slot)) + return true; + JSValue prototype = object->prototype(); + if (!prototype.isObject()) + return false; + object = asObject(prototype); + } +} + +inline JSValue JSObject::get(ExecState* exec, const Identifier& propertyName) const +{ + PropertySlot slot(this); + if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot)) + return slot.getValue(exec, propertyName); + + return jsUndefined(); +} + +inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const +{ + PropertySlot slot(this); + if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot)) + return slot.getValue(exec, propertyName); + + return jsUndefined(); +} + +inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot, JSCell* specificFunction) +{ + ASSERT(value); + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); + + if (m_structure->isDictionary()) { + unsigned currentAttributes; + JSCell* currentSpecificFunction; + size_t offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction); + if (offset != WTF::notFound) { + if (currentSpecificFunction && (specificFunction != currentSpecificFunction)) + m_structure->despecifyDictionaryFunction(propertyName); + if (checkReadOnly && currentAttributes & ReadOnly) + return; + putDirectOffset(offset, value); + if (!specificFunction && !currentSpecificFunction) + slot.setExistingProperty(this, offset); + return; + } + + size_t currentCapacity = m_structure->propertyStorageCapacity(); + offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, specificFunction); + if (currentCapacity != m_structure->propertyStorageCapacity()) + allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity()); + + ASSERT(offset < m_structure->propertyStorageCapacity()); + putDirectOffset(offset, value); + // See comment on setNewProperty call below. + if (!specificFunction) + slot.setNewProperty(this, offset); + return; + } + + size_t offset; + size_t currentCapacity = m_structure->propertyStorageCapacity(); + if (RefPtr<Structure> structure = Structure::addPropertyTransitionToExistingStructure(m_structure, propertyName, attributes, specificFunction, offset)) { + if (currentCapacity != structure->propertyStorageCapacity()) + allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity()); + + ASSERT(offset < structure->propertyStorageCapacity()); + setStructure(structure.release()); + putDirectOffset(offset, value); + // See comment on setNewProperty call below. + if (!specificFunction) + slot.setNewProperty(this, offset); + return; + } + + unsigned currentAttributes; + JSCell* currentSpecificFunction; + offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction); + if (offset != WTF::notFound) { + if (checkReadOnly && currentAttributes & ReadOnly) + return; + + if (currentSpecificFunction && (specificFunction != currentSpecificFunction)) { + setStructure(Structure::despecifyFunctionTransition(m_structure, propertyName)); + putDirectOffset(offset, value); + // Function transitions are not currently cachable, so leave the slot in an uncachable state. + return; + } + putDirectOffset(offset, value); + slot.setExistingProperty(this, offset); + return; + } + + RefPtr<Structure> structure = Structure::addPropertyTransition(m_structure, propertyName, attributes, specificFunction, offset); + if (currentCapacity != structure->propertyStorageCapacity()) + allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity()); + + ASSERT(offset < structure->propertyStorageCapacity()); + setStructure(structure.release()); + putDirectOffset(offset, value); + // Function transitions are not currently cachable, so leave the slot in an uncachable state. + if (!specificFunction) + slot.setNewProperty(this, offset); +} + +inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot) +{ + ASSERT(value); + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); + + putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, getJSFunction(globalData, value)); +} + +inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes) +{ + PutPropertySlot slot; + putDirectInternal(propertyName, value, attributes, false, slot, getJSFunction(globalData, value)); +} + +inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot) +{ + ASSERT(value); + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); + + putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, 0); +} + +inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes) +{ + PutPropertySlot slot; + putDirectInternal(propertyName, value, attributes, false, slot, 0); +} + +inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot) +{ + putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, value); +} + +inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr) +{ + PutPropertySlot slot; + putDirectInternal(propertyName, value, attr, false, slot, value); +} + +inline void JSObject::putDirectWithoutTransition(const Identifier& propertyName, JSValue value, unsigned attributes) +{ + size_t currentCapacity = m_structure->propertyStorageCapacity(); + size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, 0); + if (currentCapacity != m_structure->propertyStorageCapacity()) + allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity()); + putDirectOffset(offset, value); +} + +inline void JSObject::putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attributes) +{ + size_t currentCapacity = m_structure->propertyStorageCapacity(); + size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, value); + if (currentCapacity != m_structure->propertyStorageCapacity()) + allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity()); + putDirectOffset(offset, value); +} + +inline void JSObject::transitionTo(Structure* newStructure) +{ + if (m_structure->propertyStorageCapacity() != newStructure->propertyStorageCapacity()) + allocatePropertyStorage(m_structure->propertyStorageCapacity(), newStructure->propertyStorageCapacity()); + setStructure(newStructure); +} + +inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const +{ + return defaultValue(exec, preferredType); +} + +inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName) const +{ + PropertySlot slot(asValue()); + return get(exec, propertyName, slot); +} + +inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) const +{ + if (UNLIKELY(!isCell())) { + JSObject* prototype = JSImmediate::prototype(asValue(), exec); + if (propertyName == exec->propertyNames().underscoreProto) + return prototype; + if (!prototype->getPropertySlot(exec, propertyName, slot)) + return jsUndefined(); + return slot.getValue(exec, propertyName); + } + JSCell* cell = asCell(); + while (true) { + if (cell->fastGetOwnPropertySlot(exec, propertyName, slot)) + return slot.getValue(exec, propertyName); + ASSERT(cell->isObject()); + JSValue prototype = static_cast<JSObject*>(cell)->prototype(); + if (!prototype.isObject()) + return jsUndefined(); + cell = asObject(prototype); + } +} + +inline JSValue JSValue::get(ExecState* exec, unsigned propertyName) const +{ + PropertySlot slot(asValue()); + return get(exec, propertyName, slot); +} + +inline JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const +{ + if (UNLIKELY(!isCell())) { + JSObject* prototype = JSImmediate::prototype(asValue(), exec); + if (!prototype->getPropertySlot(exec, propertyName, slot)) + return jsUndefined(); + return slot.getValue(exec, propertyName); + } + JSCell* cell = const_cast<JSCell*>(asCell()); + while (true) { + if (cell->getOwnPropertySlot(exec, propertyName, slot)) + return slot.getValue(exec, propertyName); + ASSERT(cell->isObject()); + JSValue prototype = static_cast<JSObject*>(cell)->prototype(); + if (!prototype.isObject()) + return jsUndefined(); + cell = prototype.asCell(); + } +} + +inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) +{ + if (UNLIKELY(!isCell())) { + JSImmediate::toObject(asValue(), exec)->put(exec, propertyName, value, slot); + return; + } + asCell()->put(exec, propertyName, value, slot); +} + +inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue value) +{ + if (UNLIKELY(!isCell())) { + JSImmediate::toObject(asValue(), exec)->put(exec, propertyName, value); + return; + } + asCell()->put(exec, propertyName, value); +} + +ALWAYS_INLINE void JSObject::allocatePropertyStorageInline(size_t oldSize, size_t newSize) +{ + ASSERT(newSize > oldSize); + + // It's important that this function not rely on m_structure, since + // we might be in the middle of a transition. + bool wasInline = (oldSize == JSObject::inlineStorageCapacity); + + PropertyStorage oldPropertyStorage = (wasInline ? m_inlineStorage : m_externalStorage); + PropertyStorage newPropertyStorage = new EncodedJSValue[newSize]; + + for (unsigned i = 0; i < oldSize; ++i) + newPropertyStorage[i] = oldPropertyStorage[i]; + + if (!wasInline) + delete [] oldPropertyStorage; + + m_externalStorage = newPropertyStorage; +} + +} // namespace JSC + +#endif // JSObject_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSPropertyNameIterator.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSPropertyNameIterator.cpp new file mode 100644 index 0000000..8c7b53d --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSPropertyNameIterator.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSPropertyNameIterator.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(JSPropertyNameIterator); + +JSPropertyNameIterator::~JSPropertyNameIterator() +{ +} + +JSValue JSPropertyNameIterator::toPrimitive(ExecState*, PreferredPrimitiveType) const +{ + ASSERT_NOT_REACHED(); + return JSValue(); +} + +bool JSPropertyNameIterator::getPrimitiveNumber(ExecState*, double&, JSValue&) +{ + ASSERT_NOT_REACHED(); + return false; +} + +bool JSPropertyNameIterator::toBoolean(ExecState*) const +{ + ASSERT_NOT_REACHED(); + return false; +} + +double JSPropertyNameIterator::toNumber(ExecState*) const +{ + ASSERT_NOT_REACHED(); + return 0; +} + +UString JSPropertyNameIterator::toString(ExecState*) const +{ + ASSERT_NOT_REACHED(); + return ""; +} + +JSObject* JSPropertyNameIterator::toObject(ExecState*) const +{ + ASSERT_NOT_REACHED(); + return 0; +} + +void JSPropertyNameIterator::mark() +{ + JSCell::mark(); + if (m_object && !m_object->marked()) + m_object->mark(); +} + +void JSPropertyNameIterator::invalidate() +{ + ASSERT(m_position == m_end); + m_object = 0; + m_data.clear(); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSPropertyNameIterator.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSPropertyNameIterator.h new file mode 100644 index 0000000..9817c07 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSPropertyNameIterator.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSPropertyNameIterator_h +#define JSPropertyNameIterator_h + +#include "JSObject.h" +#include "JSString.h" +#include "PropertyNameArray.h" + +namespace JSC { + + class Identifier; + class JSObject; + + class JSPropertyNameIterator : public JSCell { + public: + static JSPropertyNameIterator* create(ExecState*, JSValue); + + virtual ~JSPropertyNameIterator(); + + virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; + virtual bool getPrimitiveNumber(ExecState*, double&, JSValue&); + virtual bool toBoolean(ExecState*) const; + virtual double toNumber(ExecState*) const; + virtual UString toString(ExecState*) const; + virtual JSObject* toObject(ExecState*) const; + + virtual void mark(); + + JSValue next(ExecState*); + void invalidate(); + + private: + JSPropertyNameIterator(); + JSPropertyNameIterator(JSObject*, PassRefPtr<PropertyNameArrayData> propertyNameArrayData); + + JSObject* m_object; + RefPtr<PropertyNameArrayData> m_data; + PropertyNameArrayData::const_iterator m_position; + PropertyNameArrayData::const_iterator m_end; + }; + +inline JSPropertyNameIterator::JSPropertyNameIterator() + : JSCell(0) + , m_object(0) + , m_position(0) + , m_end(0) +{ +} + +inline JSPropertyNameIterator::JSPropertyNameIterator(JSObject* object, PassRefPtr<PropertyNameArrayData> propertyNameArrayData) + : JSCell(0) + , m_object(object) + , m_data(propertyNameArrayData) + , m_position(m_data->begin()) + , m_end(m_data->end()) +{ +} + +inline JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSValue v) +{ + if (v.isUndefinedOrNull()) + return new (exec) JSPropertyNameIterator; + + JSObject* o = v.toObject(exec); + PropertyNameArray propertyNames(exec); + o->getPropertyNames(exec, propertyNames); + return new (exec) JSPropertyNameIterator(o, propertyNames.releaseData()); +} + +inline JSValue JSPropertyNameIterator::next(ExecState* exec) +{ + if (m_position == m_end) + return JSValue(); + + if (m_data->cachedStructure() == m_object->structure() && m_data->cachedPrototypeChain() == m_object->structure()->prototypeChain(exec)) + return jsOwnedString(exec, (*m_position++).ustring()); + + do { + if (m_object->hasProperty(exec, *m_position)) + return jsOwnedString(exec, (*m_position++).ustring()); + m_position++; + } while (m_position != m_end); + + return JSValue(); +} + +} // namespace JSC + +#endif // JSPropertyNameIterator_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSStaticScopeObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSStaticScopeObject.cpp new file mode 100644 index 0000000..85907c8 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSStaticScopeObject.cpp @@ -0,0 +1,79 @@ +/* + * 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. + */ + +#include "config.h" + +#include "JSStaticScopeObject.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(JSStaticScopeObject); + +void JSStaticScopeObject::mark() +{ + JSVariableObject::mark(); + + if (!d()->registerStore.marked()) + d()->registerStore.mark(); +} + +JSObject* JSStaticScopeObject::toThisObject(ExecState* exec) const +{ + return exec->globalThisValue(); +} + +void JSStaticScopeObject::put(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot&) +{ + if (symbolTablePut(propertyName, value)) + return; + + ASSERT_NOT_REACHED(); +} + +void JSStaticScopeObject::putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes) +{ + if (symbolTablePutWithAttributes(propertyName, value, attributes)) + return; + + ASSERT_NOT_REACHED(); +} + +bool JSStaticScopeObject::isDynamicScope() const +{ + return false; +} + +JSStaticScopeObject::~JSStaticScopeObject() +{ + ASSERT(d()); + delete d(); +} + +inline bool JSStaticScopeObject::getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot& slot) +{ + return symbolTableGet(propertyName, slot); +} + +} diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSStaticScopeObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSStaticScopeObject.h new file mode 100644 index 0000000..2caf540 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSStaticScopeObject.h @@ -0,0 +1,68 @@ +/* + * 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. + */ + +#ifndef JSStaticScopeObject_h +#define JSStaticScopeObject_h + +#include "JSVariableObject.h" + +namespace JSC{ + + class JSStaticScopeObject : public JSVariableObject { + protected: + using JSVariableObject::JSVariableObjectData; + struct JSStaticScopeObjectData : public JSVariableObjectData { + JSStaticScopeObjectData() + : JSVariableObjectData(&symbolTable, ®isterStore + 1) + { + } + SymbolTable symbolTable; + Register registerStore; + }; + + public: + JSStaticScopeObject(ExecState* exec, const Identifier& ident, JSValue value, unsigned attributes) + : JSVariableObject(exec->globalData().staticScopeStructure, new JSStaticScopeObjectData()) + { + d()->registerStore = value; + symbolTable().add(ident.ustring().rep(), SymbolTableEntry(-1, attributes)); + } + virtual ~JSStaticScopeObject(); + virtual void mark(); + bool isDynamicScope() const; + virtual JSObject* toThisObject(ExecState*) const; + virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&); + void putWithAttributes(ExecState*, const Identifier&, JSValue, unsigned attributes); + + static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, NeedsThisConversion)); } + + private: + JSStaticScopeObjectData* d() { return static_cast<JSStaticScopeObjectData*>(JSVariableObject::d); } + }; + +} + +#endif // JSStaticScopeObject_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSString.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSString.cpp new file mode 100644 index 0000000..e1fc66d --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSString.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2004, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "JSString.h" + +#include "JSGlobalObject.h" +#include "JSObject.h" +#include "StringObject.h" +#include "StringPrototype.h" + +namespace JSC { + +JSValue JSString::toPrimitive(ExecState*, PreferredPrimitiveType) const +{ + return const_cast<JSString*>(this); +} + +bool JSString::getPrimitiveNumber(ExecState*, double& number, JSValue& value) +{ + value = this; + number = m_value.toDouble(); + return false; +} + +bool JSString::toBoolean(ExecState*) const +{ + return !m_value.isEmpty(); +} + +double JSString::toNumber(ExecState*) const +{ + return m_value.toDouble(); +} + +UString JSString::toString(ExecState*) const +{ + return m_value; +} + +UString JSString::toThisString(ExecState*) const +{ + return m_value; +} + +JSString* JSString::toThisJSString(ExecState*) +{ + return this; +} + +inline StringObject* StringObject::create(ExecState* exec, JSString* string) +{ + return new (exec) StringObject(exec->lexicalGlobalObject()->stringObjectStructure(), string); +} + +JSObject* JSString::toObject(ExecState* exec) const +{ + return StringObject::create(exec, const_cast<JSString*>(this)); +} + +JSObject* JSString::toThisObject(ExecState* exec) const +{ + return StringObject::create(exec, const_cast<JSString*>(this)); +} + +bool JSString::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +{ + // The semantics here are really getPropertySlot, not getOwnPropertySlot. + // This function should only be called by JSValue::get. + if (getStringPropertySlot(exec, propertyName, slot)) + return true; + if (propertyName == exec->propertyNames().underscoreProto) { + slot.setValue(exec->lexicalGlobalObject()->stringPrototype()); + return true; + } + slot.setBase(this); + JSObject* object; + for (JSValue prototype = exec->lexicalGlobalObject()->stringPrototype(); !prototype.isNull(); prototype = object->prototype()) { + object = asObject(prototype); + if (object->getOwnPropertySlot(exec, propertyName, slot)) + return true; + } + slot.setUndefined(); + return true; +} + +bool JSString::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) +{ + // The semantics here are really getPropertySlot, not getOwnPropertySlot. + // This function should only be called by JSValue::get. + if (getStringPropertySlot(exec, propertyName, slot)) + return true; + return JSString::getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot); +} + +bool JSString::getStringPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const +{ + if (propertyName == exec->propertyNames().length) { + attributes = DontEnum | DontDelete | ReadOnly; + return true; + } + bool isStrictUInt32; + unsigned i = propertyName.toStrictUInt32(&isStrictUInt32); + if (isStrictUInt32 && i < static_cast<unsigned>(m_value.size())) { + attributes = DontDelete | ReadOnly; + return true; + } + return false; +} + +JSString* jsString(JSGlobalData* globalData, const UString& s) +{ + int size = s.size(); + if (!size) + return globalData->smallStrings.emptyString(globalData); + if (size == 1) { + UChar c = s.data()[0]; + if (c <= 0xFF) + return globalData->smallStrings.singleCharacterString(globalData, c); + } + return new (globalData) JSString(globalData, s); +} + +JSString* jsSubstring(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length) +{ + ASSERT(offset <= static_cast<unsigned>(s.size())); + ASSERT(length <= static_cast<unsigned>(s.size())); + ASSERT(offset + length <= static_cast<unsigned>(s.size())); + if (!length) + return globalData->smallStrings.emptyString(globalData); + if (length == 1) { + UChar c = s.data()[offset]; + if (c <= 0xFF) + return globalData->smallStrings.singleCharacterString(globalData, c); + } + return new (globalData) JSString(globalData, UString::Rep::create(s.rep(), offset, length)); +} + +JSString* jsOwnedString(JSGlobalData* globalData, const UString& s) +{ + int size = s.size(); + if (!size) + return globalData->smallStrings.emptyString(globalData); + if (size == 1) { + UChar c = s.data()[0]; + if (c <= 0xFF) + return globalData->smallStrings.singleCharacterString(globalData, c); + } + return new (globalData) JSString(globalData, s, JSString::HasOtherOwner); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSString.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSString.h new file mode 100644 index 0000000..6db9322 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSString.h @@ -0,0 +1,218 @@ +/* + * 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 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef JSString_h +#define JSString_h + +#include "CommonIdentifiers.h" +#include "CallFrame.h" +#include "Identifier.h" +#include "JSNumberCell.h" +#include "PropertySlot.h" + +namespace JSC { + + class JSString; + + JSString* jsEmptyString(JSGlobalData*); + JSString* jsEmptyString(ExecState*); + JSString* jsString(JSGlobalData*, const UString&); // returns empty string if passed null string + JSString* jsString(ExecState*, const UString&); // returns empty string if passed null string + + JSString* jsSingleCharacterString(JSGlobalData*, UChar); + JSString* jsSingleCharacterString(ExecState*, UChar); + JSString* jsSingleCharacterSubstring(JSGlobalData*, const UString&, unsigned offset); + JSString* jsSingleCharacterSubstring(ExecState*, const UString&, unsigned offset); + JSString* jsSubstring(JSGlobalData*, const UString&, unsigned offset, unsigned length); + JSString* jsSubstring(ExecState*, const UString&, unsigned offset, unsigned length); + + // Non-trivial strings are two or more characters long. + // These functions are faster than just calling jsString. + JSString* jsNontrivialString(JSGlobalData*, const UString&); + JSString* jsNontrivialString(ExecState*, const UString&); + JSString* jsNontrivialString(JSGlobalData*, const char*); + JSString* jsNontrivialString(ExecState*, const char*); + + // 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 UString + JSString* jsOwnedString(JSGlobalData*, const UString&); + JSString* jsOwnedString(ExecState*, const UString&); + + class JSString : public JSCell { + friend class JIT; + friend class VPtrSet; + + public: + JSString(JSGlobalData* globalData, const UString& value) + : JSCell(globalData->stringStructure.get()) + , m_value(value) + { + Heap::heap(this)->reportExtraMemoryCost(value.cost()); + } + + enum HasOtherOwnerType { HasOtherOwner }; + JSString(JSGlobalData* globalData, const UString& value, HasOtherOwnerType) + : JSCell(globalData->stringStructure.get()) + , m_value(value) + { + } + JSString(JSGlobalData* globalData, PassRefPtr<UString::Rep> value, HasOtherOwnerType) + : JSCell(globalData->stringStructure.get()) + , m_value(value) + { + } + + const UString& value() const { return m_value; } + + bool getStringPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); + bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); + + bool getStringPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned&) const; + + bool canGetIndex(unsigned i) { return i < static_cast<unsigned>(m_value.size()); } + JSString* getIndex(JSGlobalData*, unsigned); + + static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, NeedsThisConversion)); } + + private: + enum VPtrStealingHackType { VPtrStealingHack }; + JSString(VPtrStealingHackType) + : JSCell(0) + { + } + + virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; + virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value); + virtual bool toBoolean(ExecState*) const; + virtual double toNumber(ExecState*) const; + virtual JSObject* toObject(ExecState*) const; + virtual UString toString(ExecState*) const; + + virtual JSObject* toThisObject(ExecState*) const; + virtual UString toThisString(ExecState*) const; + virtual JSString* toThisJSString(ExecState*); + + // Actually getPropertySlot, not getOwnPropertySlot (see JSCell). + virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); + virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); + + UString m_value; + }; + + JSString* asString(JSValue); + + inline JSString* asString(JSValue value) + { + ASSERT(asCell(value)->isString()); + return static_cast<JSString*>(asCell(value)); + } + + inline JSString* jsEmptyString(JSGlobalData* globalData) + { + return globalData->smallStrings.emptyString(globalData); + } + + inline JSString* jsSingleCharacterString(JSGlobalData* globalData, UChar c) + { + if (c <= 0xFF) + return globalData->smallStrings.singleCharacterString(globalData, c); + return new (globalData) JSString(globalData, UString(&c, 1)); + } + + inline JSString* jsSingleCharacterSubstring(JSGlobalData* globalData, const UString& s, unsigned offset) + { + ASSERT(offset < static_cast<unsigned>(s.size())); + UChar c = s.data()[offset]; + if (c <= 0xFF) + return globalData->smallStrings.singleCharacterString(globalData, c); + return new (globalData) JSString(globalData, UString::Rep::create(s.rep(), offset, 1)); + } + + inline JSString* jsNontrivialString(JSGlobalData* globalData, const char* s) + { + ASSERT(s); + ASSERT(s[0]); + ASSERT(s[1]); + return new (globalData) JSString(globalData, s); + } + + inline JSString* jsNontrivialString(JSGlobalData* globalData, const UString& s) + { + ASSERT(s.size() > 1); + return new (globalData) JSString(globalData, s); + } + + inline JSString* JSString::getIndex(JSGlobalData* globalData, unsigned i) + { + ASSERT(canGetIndex(i)); + return jsSingleCharacterSubstring(globalData, m_value, i); + } + + inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->globalData()); } + inline JSString* jsString(ExecState* exec, const UString& s) { return jsString(&exec->globalData(), s); } + inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->globalData(), c); } + inline JSString* jsSingleCharacterSubstring(ExecState* exec, const UString& s, unsigned offset) { return jsSingleCharacterSubstring(&exec->globalData(), s, offset); } + inline JSString* jsSubstring(ExecState* exec, const UString& s, unsigned offset, unsigned length) { return jsSubstring(&exec->globalData(), s, offset, length); } + inline JSString* jsNontrivialString(ExecState* exec, const UString& s) { return jsNontrivialString(&exec->globalData(), s); } + inline JSString* jsNontrivialString(ExecState* exec, const char* s) { return jsNontrivialString(&exec->globalData(), s); } + inline JSString* jsOwnedString(ExecState* exec, const UString& s) { return jsOwnedString(&exec->globalData(), s); } + + ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) + { + if (propertyName == exec->propertyNames().length) { + slot.setValue(jsNumber(exec, m_value.size())); + return true; + } + + bool isStrictUInt32; + unsigned i = propertyName.toStrictUInt32(&isStrictUInt32); + if (isStrictUInt32 && i < static_cast<unsigned>(m_value.size())) { + slot.setValue(jsSingleCharacterSubstring(exec, m_value, i)); + return true; + } + + return false; + } + + ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) + { + if (propertyName < static_cast<unsigned>(m_value.size())) { + slot.setValue(jsSingleCharacterSubstring(exec, m_value, propertyName)); + return true; + } + + return false; + } + + inline bool isJSString(JSGlobalData* globalData, JSValue v) { return v.isCell() && v.asCell()->vptr() == globalData->jsStringVPtr; } + + // --- JSValue inlines ---------------------------- + + inline JSString* JSValue::toThisJSString(ExecState* exec) + { + return JSImmediate::isImmediate(asValue()) ? jsString(exec, JSImmediate::toString(asValue())) : asCell()->toThisJSString(exec); + } + +} // namespace JSC + +#endif // JSString_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSType.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSType.h new file mode 100644 index 0000000..68f2890 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSType.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 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 + * 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 JSType_h +#define JSType_h + +namespace JSC { + + /** + * Primitive types + */ + enum JSType { + UnspecifiedType = 0, + UndefinedType = 1, + BooleanType = 2, + NumberType = 3, + NullType = 4, + StringType = 5, + ObjectType = 6, + GetterSetterType = 7 + }; + +} // namespace JSC + +#endif diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSTypeInfo.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSTypeInfo.h new file mode 100644 index 0000000..bea188b --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSTypeInfo.h @@ -0,0 +1,72 @@ +// -*- mode: c++; c-basic-offset: 4 -*- +/* + * 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 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 JSTypeInfo_h +#define JSTypeInfo_h + +#include "JSType.h" + +namespace JSC { + + // WebCore uses MasqueradesAsUndefined to make document.all and style.filter undetectable. + static const unsigned MasqueradesAsUndefined = 1; + static const unsigned ImplementsHasInstance = 1 << 1; + static const unsigned OverridesHasInstance = 1 << 2; + static const unsigned ImplementsDefaultHasInstance = 1 << 3; + static const unsigned NeedsThisConversion = 1 << 4; + static const unsigned HasStandardGetOwnPropertySlot = 1 << 5; + + class TypeInfo { + friend class JIT; + public: + TypeInfo(JSType type, unsigned flags = 0) + : m_type(type) + { + // ImplementsDefaultHasInstance means (ImplementsHasInstance & !OverridesHasInstance) + if ((flags & (ImplementsHasInstance | OverridesHasInstance)) == ImplementsHasInstance) + m_flags = flags | ImplementsDefaultHasInstance; + else + m_flags = flags; + } + + JSType type() const { return m_type; } + + bool masqueradesAsUndefined() const { return m_flags & MasqueradesAsUndefined; } + bool implementsHasInstance() const { return m_flags & ImplementsHasInstance; } + bool overridesHasInstance() const { return m_flags & OverridesHasInstance; } + bool needsThisConversion() const { return m_flags & NeedsThisConversion; } + bool hasStandardGetOwnPropertySlot() const { return m_flags & HasStandardGetOwnPropertySlot; } + + unsigned flags() const { return m_flags; } + + private: + JSType m_type; + unsigned m_flags; + }; + +} + +#endif // JSTypeInfo_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSValue.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSValue.cpp new file mode 100644 index 0000000..885914d --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSValue.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "JSValue.h" + +#include "JSFunction.h" +#include <wtf/MathExtras.h> + +namespace JSC { + +static const double D32 = 4294967296.0; + +// ECMA 9.4 +double JSValue::toInteger(ExecState* exec) const +{ + if (isInt32Fast()) + return getInt32Fast(); + double d = toNumber(exec); + return isnan(d) ? 0.0 : trunc(d); +} + +double JSValue::toIntegerPreserveNaN(ExecState* exec) const +{ + if (isInt32Fast()) + return getInt32Fast(); + return trunc(toNumber(exec)); +} + +int32_t toInt32SlowCase(double d, bool& ok) +{ + ok = true; + + if (d >= -D32 / 2 && d < D32 / 2) + return static_cast<int32_t>(d); + + if (isnan(d) || isinf(d)) { + ok = false; + return 0; + } + + double d32 = fmod(trunc(d), D32); + if (d32 >= D32 / 2) + d32 -= D32; + else if (d32 < -D32 / 2) + d32 += D32; + return static_cast<int32_t>(d32); +} + +uint32_t toUInt32SlowCase(double d, bool& ok) +{ + ok = true; + + if (d >= 0.0 && d < D32) + return static_cast<uint32_t>(d); + + if (isnan(d) || isinf(d)) { + ok = false; + return 0; + } + + double d32 = fmod(trunc(d), D32); + if (d32 < 0) + d32 += D32; + return static_cast<uint32_t>(d32); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSValue.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSValue.h new file mode 100644 index 0000000..391425c --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSValue.h @@ -0,0 +1,420 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003, 2004, 2005, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include <stddef.h> // for size_t +#include <stdint.h> + +#ifndef JSValue_h +#define JSValue_h + +#include "CallData.h" +#include "ConstructData.h" +#include <wtf/HashTraits.h> +#include <wtf/AlwaysInline.h> + +namespace JSC { + + class Identifier; + class JSCell; + class JSGlobalData; + class JSImmediate; + class JSObject; + class JSString; + class PropertySlot; + class PutPropertySlot; + class UString; + + struct ClassInfo; + struct Instruction; + + enum PreferredPrimitiveType { NoPreference, PreferNumber, PreferString }; + + typedef void* EncodedJSValue; + + class JSValue { + friend class JSImmediate; + friend struct JSValueHashTraits; + + static JSValue makeImmediate(intptr_t value) + { + return JSValue(reinterpret_cast<JSCell*>(value)); + } + + intptr_t immediateValue() + { + return reinterpret_cast<intptr_t>(m_ptr); + } + + public: + enum JSNullTag { JSNull }; + enum JSUndefinedTag { JSUndefined }; + enum JSTrueTag { JSTrue }; + enum JSFalseTag { JSFalse }; + + static EncodedJSValue encode(JSValue value); + static JSValue decode(EncodedJSValue ptr); + + JSValue(); + JSValue(JSNullTag); + JSValue(JSUndefinedTag); + JSValue(JSTrueTag); + JSValue(JSFalseTag); + JSValue(JSCell* ptr); + JSValue(const JSCell* ptr); + + // Numbers + JSValue(ExecState*, double); + JSValue(ExecState*, char); + JSValue(ExecState*, unsigned char); + JSValue(ExecState*, short); + JSValue(ExecState*, unsigned short); + JSValue(ExecState*, int); + JSValue(ExecState*, unsigned); + JSValue(ExecState*, long); + JSValue(ExecState*, unsigned long); + JSValue(ExecState*, long long); + JSValue(ExecState*, unsigned long long); + JSValue(JSGlobalData*, double); + JSValue(JSGlobalData*, char); + JSValue(JSGlobalData*, unsigned char); + JSValue(JSGlobalData*, short); + JSValue(JSGlobalData*, unsigned short); + JSValue(JSGlobalData*, int); + JSValue(JSGlobalData*, unsigned); + JSValue(JSGlobalData*, long); + JSValue(JSGlobalData*, unsigned long); + JSValue(JSGlobalData*, long long); + JSValue(JSGlobalData*, unsigned long long); + + operator bool() const; + bool operator==(const JSValue other) const; + bool operator!=(const JSValue other) const; + + // Querying the type. + bool isUndefined() const; + bool isNull() const; + bool isUndefinedOrNull() const; + bool isBoolean() const; + bool isNumber() const; + bool isString() const; + bool isGetterSetter() const; + bool isObject() const; + bool isObject(const ClassInfo*) const; + + // Extracting the value. + bool getBoolean(bool&) const; + bool getBoolean() const; // false if not a boolean + bool getNumber(double&) const; + double uncheckedGetNumber() const; + bool getString(UString&) const; + UString getString() const; // null string if not a string + JSObject* getObject() const; // 0 if not an object + + CallType getCallData(CallData&); + ConstructType getConstructData(ConstructData&); + + // Extracting integer values. + bool getUInt32(uint32_t&) const; + bool getTruncatedInt32(int32_t&) const; + bool getTruncatedUInt32(uint32_t&) const; + + // Basic conversions. + JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const; + bool getPrimitiveNumber(ExecState*, double& number, JSValue&); + + bool toBoolean(ExecState*) const; + + // toNumber conversion is expected to be side effect free if an exception has + // been set in the ExecState already. + double toNumber(ExecState*) const; + JSValue toJSNumber(ExecState*) const; // Fast path for when you expect that the value is an immediate number. + UString toString(ExecState*) const; + JSObject* toObject(ExecState*) const; + + // Integer conversions. + // 'x.numberToInt32(output)' is equivalent to 'x.isNumber() && x.toInt32(output)' + double toInteger(ExecState*) const; + double toIntegerPreserveNaN(ExecState*) const; + int32_t toInt32(ExecState*) const; + int32_t toInt32(ExecState*, bool& ok) const; + bool numberToInt32(int32_t& arg); + uint32_t toUInt32(ExecState*) const; + uint32_t toUInt32(ExecState*, bool& ok) const; + bool numberToUInt32(uint32_t& arg); + + // Fast integer operations; these values return results where the value is trivially available + // in a convenient form, for use in optimizations. No assumptions should be made based on the + // results of these operations, for example !isInt32Fast() does not necessarily indicate the + // result of getNumber will not be 0. + bool isInt32Fast() const; + int32_t getInt32Fast() const; + bool isUInt32Fast() const; + uint32_t getUInt32Fast() const; + static JSValue makeInt32Fast(int32_t); + static bool areBothInt32Fast(JSValue, JSValue); + + // 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)); } + + // API Mangled Numbers + bool isAPIMangledNumber(); + + // Garbage collection. + void mark(); + bool marked() const; + + // Object operations, with the toObject operation included. + JSValue get(ExecState*, const Identifier& propertyName) const; + JSValue get(ExecState*, const Identifier& propertyName, PropertySlot&) const; + JSValue get(ExecState*, unsigned propertyName) const; + JSValue get(ExecState*, unsigned propertyName, PropertySlot&) const; + void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); + void put(ExecState*, unsigned propertyName, JSValue); + + bool needsThisConversion() const; + JSObject* toThisObject(ExecState*) const; + UString toThisString(ExecState*) const; + JSString* toThisJSString(ExecState*); + + static bool equal(ExecState* exec, JSValue v1, JSValue v2); + static bool equalSlowCase(ExecState* exec, JSValue v1, JSValue v2); + static bool equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2); + static bool strictEqual(JSValue v1, JSValue v2); + static bool strictEqualSlowCase(JSValue v1, JSValue v2); + static bool strictEqualSlowCaseInline(JSValue v1, JSValue v2); + + JSValue getJSNumber(); // JSValue() if this is not a JSNumber or number object + + bool isCell() const; + JSCell* asCell() const; + + private: + enum HashTableDeletedValueTag { HashTableDeletedValue }; + JSValue(HashTableDeletedValueTag); + + inline const JSValue asValue() const { return *this; } + + bool isDoubleNumber() const; + double getDoubleNumber() const; + + JSCell* m_ptr; + }; + + struct JSValueHashTraits : HashTraits<EncodedJSValue> { + static void constructDeletedValue(EncodedJSValue& slot) { slot = JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); } + static bool isDeletedValue(EncodedJSValue value) { return value == JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); } + }; + + // Stand-alone helper functions. + inline JSValue jsNull() + { + return JSValue(JSValue::JSNull); + } + + inline JSValue jsUndefined() + { + return JSValue(JSValue::JSUndefined); + } + + inline JSValue jsBoolean(bool b) + { + return b ? JSValue(JSValue::JSTrue) : JSValue(JSValue::JSFalse); + } + + ALWAYS_INLINE JSValue jsNumber(ExecState* exec, double d) + { + return JSValue(exec, d); + } + + ALWAYS_INLINE JSValue jsNumber(ExecState* exec, char i) + { + return JSValue(exec, i); + } + + ALWAYS_INLINE JSValue jsNumber(ExecState* exec, unsigned char i) + { + return JSValue(exec, i); + } + + ALWAYS_INLINE JSValue jsNumber(ExecState* exec, short i) + { + return JSValue(exec, i); + } + + ALWAYS_INLINE JSValue jsNumber(ExecState* exec, unsigned short i) + { + return JSValue(exec, i); + } + + ALWAYS_INLINE JSValue jsNumber(ExecState* exec, int i) + { + return JSValue(exec, i); + } + + ALWAYS_INLINE JSValue jsNumber(ExecState* exec, unsigned i) + { + return JSValue(exec, i); + } + + ALWAYS_INLINE JSValue jsNumber(ExecState* exec, long i) + { + return JSValue(exec, i); + } + + ALWAYS_INLINE JSValue jsNumber(ExecState* exec, unsigned long i) + { + return JSValue(exec, i); + } + + ALWAYS_INLINE JSValue jsNumber(ExecState* exec, long long i) + { + return JSValue(exec, i); + } + + ALWAYS_INLINE JSValue jsNumber(ExecState* exec, unsigned long long i) + { + return JSValue(exec, i); + } + + ALWAYS_INLINE JSValue jsNumber(JSGlobalData* globalData, double d) + { + return JSValue(globalData, d); + } + + ALWAYS_INLINE JSValue jsNumber(JSGlobalData* globalData, char i) + { + return JSValue(globalData, i); + } + + ALWAYS_INLINE JSValue jsNumber(JSGlobalData* globalData, unsigned char i) + { + return JSValue(globalData, i); + } + + ALWAYS_INLINE JSValue jsNumber(JSGlobalData* globalData, short i) + { + return JSValue(globalData, i); + } + + ALWAYS_INLINE JSValue jsNumber(JSGlobalData* globalData, unsigned short i) + { + return JSValue(globalData, i); + } + + ALWAYS_INLINE JSValue jsNumber(JSGlobalData* globalData, int i) + { + return JSValue(globalData, i); + } + + ALWAYS_INLINE JSValue jsNumber(JSGlobalData* globalData, unsigned i) + { + return JSValue(globalData, i); + } + + ALWAYS_INLINE JSValue jsNumber(JSGlobalData* globalData, long i) + { + return JSValue(globalData, i); + } + + ALWAYS_INLINE JSValue jsNumber(JSGlobalData* globalData, unsigned long i) + { + return JSValue(globalData, i); + } + + ALWAYS_INLINE JSValue jsNumber(JSGlobalData* globalData, long long i) + { + return JSValue(globalData, i); + } + + ALWAYS_INLINE JSValue jsNumber(JSGlobalData* globalData, unsigned long long i) + { + return JSValue(globalData, i); + } + + inline bool operator==(const JSValue a, const JSCell* b) { return a == JSValue(b); } + inline bool operator==(const JSCell* a, const JSValue b) { return JSValue(a) == b; } + + inline bool operator!=(const JSValue a, const JSCell* b) { return a != JSValue(b); } + inline bool operator!=(const JSCell* a, const JSValue b) { return JSValue(a) != b; } + + // JSValue member functions. + inline EncodedJSValue JSValue::encode(JSValue value) + { + return reinterpret_cast<EncodedJSValue>(value.m_ptr); + } + + inline JSValue JSValue::decode(EncodedJSValue ptr) + { + return JSValue(reinterpret_cast<JSCell*>(ptr)); + } + + // 0x0 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x0, which is in the (invalid) zero page. + inline JSValue::JSValue() + : m_ptr(0) + { + } + + // 0x4 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x4, which is in the (invalid) zero page. + inline JSValue::JSValue(HashTableDeletedValueTag) + : m_ptr(reinterpret_cast<JSCell*>(0x4)) + { + } + + inline JSValue::JSValue(JSCell* ptr) + : m_ptr(ptr) + { + } + + inline JSValue::JSValue(const JSCell* ptr) + : m_ptr(const_cast<JSCell*>(ptr)) + { + } + + inline JSValue::operator bool() const + { + return m_ptr; + } + + inline bool JSValue::operator==(const JSValue other) const + { + return m_ptr == other.m_ptr; + } + + inline bool JSValue::operator!=(const JSValue other) const + { + return m_ptr != other.m_ptr; + } + + inline bool JSValue::isUndefined() const + { + return asValue() == jsUndefined(); + } + + inline bool JSValue::isNull() const + { + return asValue() == jsNull(); + } + +} // namespace JSC + +#endif // JSValue_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSVariableObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSVariableObject.cpp new file mode 100644 index 0000000..78993b6 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSVariableObject.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSVariableObject.h" + +#include "PropertyNameArray.h" + +namespace JSC { + +bool JSVariableObject::deleteProperty(ExecState* exec, const Identifier& propertyName, bool checkDontDelete) +{ + if (symbolTable().contains(propertyName.ustring().rep())) + return false; + + return JSObject::deleteProperty(exec, propertyName, checkDontDelete); +} + +void JSVariableObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, unsigned listedAttributes) +{ + SymbolTable::const_iterator end = symbolTable().end(); + for (SymbolTable::const_iterator it = symbolTable().begin(); it != end; ++it) { + if ((listedAttributes & Structure::NonEnumerable) || !(it->second.getAttributes() & DontEnum)) + propertyNames.add(Identifier(exec, it->first.get())); + } + + JSObject::getPropertyNames(exec, propertyNames, listedAttributes); +} + +bool JSVariableObject::getPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const +{ + SymbolTableEntry entry = symbolTable().get(propertyName.ustring().rep()); + if (!entry.isNull()) { + attributes = entry.getAttributes() | DontDelete; + return true; + } + return JSObject::getPropertyAttributes(exec, propertyName, attributes); +} + +bool JSVariableObject::isVariableObject() const +{ + return true; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSVariableObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSVariableObject.h new file mode 100644 index 0000000..310efb1 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSVariableObject.h @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSVariableObject_h +#define JSVariableObject_h + +#include "JSObject.h" +#include "Register.h" +#include "SymbolTable.h" +#include "UnusedParam.h" +#include <wtf/OwnArrayPtr.h> +#include <wtf/UnusedParam.h> + +namespace JSC { + + class Register; + + class JSVariableObject : public JSObject { + friend class JIT; + + public: + SymbolTable& symbolTable() const { return *d->symbolTable; } + + virtual void putWithAttributes(ExecState*, const Identifier&, JSValue, unsigned attributes) = 0; + + virtual bool deleteProperty(ExecState*, const Identifier&, bool checkDontDelete = true); + virtual void getPropertyNames(ExecState*, PropertyNameArray&, unsigned listedAttributes = Structure::Prototype); + + virtual bool isVariableObject() const; + virtual bool isDynamicScope() const = 0; + + virtual bool getPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned& attributes) const; + + Register& registerAt(int index) const { return d->registers[index]; } + + protected: + // Subclasses of JSVariableObject can subclass this struct to add data + // without increasing their own size (since there's a hard limit on the + // size of a JSCell). + struct JSVariableObjectData { + JSVariableObjectData(SymbolTable* symbolTable, Register* registers) + : symbolTable(symbolTable) + , registers(registers) + { + ASSERT(symbolTable); + } + + SymbolTable* symbolTable; // Maps name -> offset from "r" in register file. + Register* registers; // "r" in the register file. + OwnArrayPtr<Register> registerArray; // Independent copy of registers, used when a variable object copies its registers out of the register file. + + private: + JSVariableObjectData(const JSVariableObjectData&); + JSVariableObjectData& operator=(const JSVariableObjectData&); + }; + + JSVariableObject(PassRefPtr<Structure> structure, JSVariableObjectData* data) + : JSObject(structure) + , d(data) // Subclass owns this pointer. + { + } + + Register* copyRegisterArray(Register* src, size_t count); + void setRegisters(Register* r, Register* registerArray); + + bool symbolTableGet(const Identifier&, PropertySlot&); + bool symbolTableGet(const Identifier&, PropertySlot&, bool& slotIsWriteable); + bool symbolTablePut(const Identifier&, JSValue); + bool symbolTablePutWithAttributes(const Identifier&, JSValue, unsigned attributes); + + JSVariableObjectData* d; + }; + + inline bool JSVariableObject::symbolTableGet(const Identifier& propertyName, PropertySlot& slot) + { + SymbolTableEntry entry = symbolTable().inlineGet(propertyName.ustring().rep()); + if (!entry.isNull()) { + slot.setRegisterSlot(®isterAt(entry.getIndex())); + return true; + } + return false; + } + + inline bool JSVariableObject::symbolTableGet(const Identifier& propertyName, PropertySlot& slot, bool& slotIsWriteable) + { + SymbolTableEntry entry = symbolTable().inlineGet(propertyName.ustring().rep()); + if (!entry.isNull()) { + slot.setRegisterSlot(®isterAt(entry.getIndex())); + slotIsWriteable = !entry.isReadOnly(); + return true; + } + return false; + } + + inline bool JSVariableObject::symbolTablePut(const Identifier& propertyName, JSValue value) + { + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); + + SymbolTableEntry entry = symbolTable().inlineGet(propertyName.ustring().rep()); + if (entry.isNull()) + return false; + if (entry.isReadOnly()) + return true; + registerAt(entry.getIndex()) = value; + return true; + } + + inline bool JSVariableObject::symbolTablePutWithAttributes(const Identifier& propertyName, JSValue value, unsigned attributes) + { + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); + + SymbolTable::iterator iter = symbolTable().find(propertyName.ustring().rep()); + if (iter == symbolTable().end()) + return false; + SymbolTableEntry& entry = iter->second; + ASSERT(!entry.isNull()); + entry.setAttributes(attributes); + registerAt(entry.getIndex()) = value; + return true; + } + + inline Register* JSVariableObject::copyRegisterArray(Register* src, size_t count) + { + Register* registerArray = new Register[count]; + memcpy(registerArray, src, count * sizeof(Register)); + + return registerArray; + } + + inline void JSVariableObject::setRegisters(Register* registers, Register* registerArray) + { + ASSERT(registerArray != d->registerArray.get()); + d->registerArray.set(registerArray); + d->registers = registers; + } + +} // namespace JSC + +#endif // JSVariableObject_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSWrapperObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSWrapperObject.cpp new file mode 100644 index 0000000..fb57018 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSWrapperObject.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2006 Maks Orlovich + * Copyright (C) 2006 Apple Computer, Inc. + * + * 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 "JSWrapperObject.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(JSWrapperObject); + +void JSWrapperObject::mark() +{ + JSObject::mark(); + if (m_internalValue && !m_internalValue.marked()) + m_internalValue.mark(); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSWrapperObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSWrapperObject.h new file mode 100644 index 0000000..2a2e3c6 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSWrapperObject.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2006 Maks Orlovich + * Copyright (C) 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 + * 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 JSWrapperObject_h +#define JSWrapperObject_h + +#include "JSObject.h" + +namespace JSC { + + // This class is used as a base for classes such as String, + // Number, Boolean and Date which are wrappers for primitive types. + class JSWrapperObject : public JSObject { + protected: + explicit JSWrapperObject(PassRefPtr<Structure>); + + public: + JSValue internalValue() const { return m_internalValue; } + void setInternalValue(JSValue); + + virtual void mark(); + + private: + JSValue m_internalValue; + }; + + inline JSWrapperObject::JSWrapperObject(PassRefPtr<Structure> structure) + : JSObject(structure) + { + } + + inline void JSWrapperObject::setInternalValue(JSValue value) + { + ASSERT(value); + ASSERT(!value.isObject()); + m_internalValue = value; + } + +} // namespace JSC + +#endif // JSWrapperObject_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/LiteralParser.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/LiteralParser.cpp new file mode 100644 index 0000000..798013a --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/LiteralParser.cpp @@ -0,0 +1,449 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "LiteralParser.h" + +#include "JSArray.h" +#include "JSString.h" +#include "Lexer.h" +#include <wtf/ASCIICType.h> +#include <wtf/dtoa.h> + +namespace JSC { + +LiteralParser::TokenType LiteralParser::Lexer::lex(LiteralParserToken& token) +{ + while (m_ptr < m_end && isASCIISpace(*m_ptr)) + ++m_ptr; + + ASSERT(m_ptr <= m_end); + if (m_ptr >= m_end) { + token.type = TokEnd; + token.start = token.end = m_ptr; + return TokEnd; + } + token.type = TokError; + token.start = m_ptr; + switch (*m_ptr) { + case '[': + token.type = TokLBracket; + token.end = ++m_ptr; + return TokLBracket; + case ']': + token.type = TokRBracket; + token.end = ++m_ptr; + return TokRBracket; + case '(': + token.type = TokLParen; + token.end = ++m_ptr; + return TokLBracket; + case ')': + token.type = TokRParen; + token.end = ++m_ptr; + return TokRBracket; + case '{': + token.type = TokLBrace; + token.end = ++m_ptr; + return TokLBrace; + case '}': + token.type = TokRBrace; + token.end = ++m_ptr; + return TokRBrace; + case ',': + token.type = TokComma; + token.end = ++m_ptr; + return TokComma; + case ':': + token.type = TokColon; + token.end = ++m_ptr; + return TokColon; + case '"': + if (m_mode == StrictJSON) + return lexString<StrictJSON>(token); + return lexString<NonStrictJSON>(token); + case 't': + if (m_end - m_ptr >= 4 && m_ptr[1] == 'r' && m_ptr[2] == 'u' && m_ptr[3] == 'e') { + m_ptr += 4; + token.type = TokTrue; + token.end = m_ptr; + return TokTrue; + } + break; + case 'f': + if (m_end - m_ptr >= 5 && m_ptr[1] == 'a' && m_ptr[2] == 'l' && m_ptr[3] == 's' && m_ptr[4] == 'e') { + m_ptr += 5; + token.type = TokFalse; + token.end = m_ptr; + return TokFalse; + } + break; + case 'n': + if (m_end - m_ptr >= 4 && m_ptr[1] == 'u' && m_ptr[2] == 'l' && m_ptr[3] == 'l') { + m_ptr += 4; + token.type = TokNull; + token.end = m_ptr; + return TokNull; + } + break; + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return lexNumber(token); + } + return TokError; +} + +template <LiteralParser::ParserMode mode> static inline bool isSafeStringCharacter(UChar c) +{ + return (c >= ' ' && (mode == LiteralParser::StrictJSON || c <= 0xff) && c != '\\' && c != '"') || c == '\t'; +} + +template <LiteralParser::ParserMode mode> LiteralParser::TokenType LiteralParser::Lexer::lexString(LiteralParserToken& token) +{ + ++m_ptr; + const UChar* runStart; + token.stringToken = UString(); + do { + runStart = m_ptr; + while (m_ptr < m_end && isSafeStringCharacter<mode>(*m_ptr)) + ++m_ptr; + if (runStart < m_ptr) + token.stringToken.append(runStart, m_ptr - runStart); + if ((mode == StrictJSON) && m_ptr < m_end && *m_ptr == '\\') { + ++m_ptr; + if (m_ptr >= m_end) + return TokError; + switch (*m_ptr) { + case '"': + token.stringToken.append('"'); + m_ptr++; + break; + case '\\': + token.stringToken.append('\\'); + m_ptr++; + break; + case '/': + token.stringToken.append('/'); + m_ptr++; + break; + case 'b': + token.stringToken.append('\b'); + m_ptr++; + break; + case 'f': + token.stringToken.append('\f'); + m_ptr++; + break; + case 'n': + token.stringToken.append('\n'); + m_ptr++; + break; + case 'r': + token.stringToken.append('\r'); + m_ptr++; + break; + case 't': + token.stringToken.append('\t'); + m_ptr++; + break; + + case 'u': + if ((m_end - m_ptr) < 5) // uNNNN == 5 characters + return TokError; + for (int i = 1; i < 5; i++) { + if (!isASCIIHexDigit(m_ptr[i])) + return TokError; + } + token.stringToken.append(JSC::Lexer::convertUnicode(m_ptr[1], m_ptr[2], m_ptr[3], m_ptr[4])); + m_ptr += 5; + break; + + default: + return TokError; + } + } + } while ((mode == StrictJSON) && m_ptr != runStart && (m_ptr < m_end) && *m_ptr != '"'); + + if (m_ptr >= m_end || *m_ptr != '"') + return TokError; + + token.type = TokString; + token.end = ++m_ptr; + return TokString; +} + +LiteralParser::TokenType LiteralParser::Lexer::lexNumber(LiteralParserToken& token) +{ + // ES5 and json.org define numbers as + // number + // int + // int frac? exp? + // + // int + // -? 0 + // -? digit1-9 digits? + // + // digits + // digit digits? + // + // -?(0 | [1-9][0-9]*) ('.' [0-9]+)? ([eE][+-]? [0-9]+)? + + if (m_ptr < m_end && *m_ptr == '-') // -? + ++m_ptr; + + // (0 | [1-9][0-9]*) + if (m_ptr < m_end && *m_ptr == '0') // 0 + ++m_ptr; + else if (m_ptr < m_end && *m_ptr >= '1' && *m_ptr <= '9') { // [1-9] + ++m_ptr; + // [0-9]* + while (m_ptr < m_end && isASCIIDigit(*m_ptr)) + ++m_ptr; + } else + return TokError; + + // ('.' [0-9]+)? + if (m_ptr < m_end && *m_ptr == '.') { + ++m_ptr; + // [0-9]+ + if (m_ptr >= m_end || !isASCIIDigit(*m_ptr)) + return TokError; + + ++m_ptr; + while (m_ptr < m_end && isASCIIDigit(*m_ptr)) + ++m_ptr; + } + + // ([eE][+-]? [0-9]+)? + if (m_ptr < m_end && (*m_ptr == 'e' || *m_ptr == 'E')) { // [eE] + ++m_ptr; + + // [-+]? + if (m_ptr < m_end && (*m_ptr == '-' || *m_ptr == '+')) + ++m_ptr; + + // [0-9]+ + if (m_ptr >= m_end || !isASCIIDigit(*m_ptr)) + return TokError; + + ++m_ptr; + while (m_ptr < m_end && isASCIIDigit(*m_ptr)) + ++m_ptr; + } + + token.type = TokNumber; + token.end = m_ptr; + Vector<char, 64> buffer(token.end - token.start + 1); + int i; + for (i = 0; i < token.end - token.start; i++) { + ASSERT(static_cast<char>(token.start[i]) == token.start[i]); + buffer[i] = static_cast<char>(token.start[i]); + } + buffer[i] = 0; + char* end; + token.numberToken = WTF::strtod(buffer.data(), &end); + ASSERT(buffer.data() + (token.end - token.start) == end); + return TokNumber; +} + +JSValue LiteralParser::parse(ParserState initialState) +{ + ParserState state = initialState; + MarkedArgumentBuffer objectStack; + JSValue lastValue; + Vector<ParserState, 16> stateStack; + Vector<Identifier, 16> identifierStack; + while (1) { + switch(state) { + startParseArray: + case StartParseArray: { + JSArray* array = constructEmptyArray(m_exec); + objectStack.append(array); + // fallthrough + } + doParseArrayStartExpression: + case DoParseArrayStartExpression: { + if (m_lexer.next() == TokRBracket) { + m_lexer.next(); + lastValue = objectStack.last(); + objectStack.removeLast(); + break; + } + + stateStack.append(DoParseArrayEndExpression); + goto startParseExpression; + } + case DoParseArrayEndExpression: { + asArray(objectStack.last())->push(m_exec, lastValue); + + if (m_lexer.currentToken().type == TokComma) + goto doParseArrayStartExpression; + + if (m_lexer.currentToken().type != TokRBracket) + return JSValue(); + + m_lexer.next(); + lastValue = objectStack.last(); + objectStack.removeLast(); + break; + } + startParseObject: + case StartParseObject: { + JSObject* object = constructEmptyObject(m_exec); + objectStack.append(object); + + TokenType type = m_lexer.next(); + if (type == TokString) { + Lexer::LiteralParserToken identifierToken = m_lexer.currentToken(); + + // Check for colon + if (m_lexer.next() != TokColon) + return JSValue(); + + m_lexer.next(); + identifierStack.append(Identifier(m_exec, identifierToken.stringToken)); + stateStack.append(DoParseObjectEndExpression); + goto startParseExpression; + } else if (type != TokRBrace) + return JSValue(); + m_lexer.next(); + lastValue = objectStack.last(); + objectStack.removeLast(); + break; + } + doParseObjectStartExpression: + case DoParseObjectStartExpression: { + TokenType type = m_lexer.next(); + if (type != TokString) + return JSValue(); + Lexer::LiteralParserToken identifierToken = m_lexer.currentToken(); + + // Check for colon + if (m_lexer.next() != TokColon) + return JSValue(); + + m_lexer.next(); + identifierStack.append(Identifier(m_exec, identifierToken.stringToken)); + stateStack.append(DoParseObjectEndExpression); + goto startParseExpression; + } + case DoParseObjectEndExpression: + { + asObject(objectStack.last())->putDirect(identifierStack.last(), lastValue); + identifierStack.removeLast(); + if (m_lexer.currentToken().type == TokComma) + goto doParseObjectStartExpression; + if (m_lexer.currentToken().type != TokRBrace) + return JSValue(); + m_lexer.next(); + lastValue = objectStack.last(); + objectStack.removeLast(); + break; + } + startParseExpression: + case StartParseExpression: { + switch (m_lexer.currentToken().type) { + case TokLBracket: + goto startParseArray; + case TokLBrace: + goto startParseObject; + case TokString: { + Lexer::LiteralParserToken stringToken = m_lexer.currentToken(); + m_lexer.next(); + lastValue = jsString(m_exec, stringToken.stringToken); + break; + } + case TokNumber: { + Lexer::LiteralParserToken numberToken = m_lexer.currentToken(); + m_lexer.next(); + lastValue = jsNumber(m_exec, numberToken.numberToken); + break; + } + case TokNull: + m_lexer.next(); + lastValue = jsNull(); + break; + + case TokTrue: + m_lexer.next(); + lastValue = jsBoolean(true); + break; + + case TokFalse: + m_lexer.next(); + lastValue = jsBoolean(false); + break; + + default: + // Error + return JSValue(); + } + break; + } + case StartParseStatement: { + switch (m_lexer.currentToken().type) { + case TokLBracket: + case TokNumber: + case TokString: + goto startParseExpression; + + case TokLParen: { + m_lexer.next(); + stateStack.append(StartParseStatementEndStatement); + goto startParseExpression; + } + default: + return JSValue(); + } + } + case StartParseStatementEndStatement: { + ASSERT(stateStack.isEmpty()); + if (m_lexer.currentToken().type != TokRParen) + return JSValue(); + if (m_lexer.next() == TokEnd) + return lastValue; + return JSValue(); + } + default: + ASSERT_NOT_REACHED(); + } + if (stateStack.isEmpty()) + return lastValue; + state = stateStack.last(); + stateStack.removeLast(); + continue; + } +} + +} diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/LiteralParser.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/LiteralParser.h new file mode 100644 index 0000000..bceee7c --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/LiteralParser.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LiteralParser_h +#define LiteralParser_h + +#include "JSGlobalObjectFunctions.h" +#include "JSValue.h" +#include "UString.h" + +namespace JSC { + + class LiteralParser { + public: + typedef enum { StrictJSON, NonStrictJSON } ParserMode; + LiteralParser(ExecState* exec, const UString& s, ParserMode mode) + : m_exec(exec) + , m_lexer(s, mode) + , m_mode(mode) + { + } + + JSValue tryLiteralParse() + { + m_lexer.next(); + JSValue result = parse(m_mode == StrictJSON ? StartParseExpression : StartParseStatement); + if (m_lexer.currentToken().type != TokEnd) + return JSValue(); + return result; + } + private: + enum ParserState { StartParseObject, StartParseArray, StartParseExpression, + StartParseStatement, StartParseStatementEndStatement, + DoParseObjectStartExpression, DoParseObjectEndExpression, + DoParseArrayStartExpression, DoParseArrayEndExpression }; + enum TokenType { TokLBracket, TokRBracket, TokLBrace, TokRBrace, + TokString, TokIdentifier, TokNumber, TokColon, + TokLParen, TokRParen, TokComma, TokTrue, TokFalse, + TokNull, TokEnd, TokError }; + + class Lexer { + public: + struct LiteralParserToken { + TokenType type; + const UChar* start; + const UChar* end; + UString stringToken; + double numberToken; + }; + Lexer(const UString& s, ParserMode mode) + : m_string(s) + , m_mode(mode) + , m_ptr(s.data()) + , m_end(s.data() + s.size()) + { + } + + TokenType next() + { + return lex(m_currentToken); + } + + const LiteralParserToken& currentToken() + { + return m_currentToken; + } + + private: + TokenType lex(LiteralParserToken&); + template <ParserMode parserMode> TokenType lexString(LiteralParserToken&); + TokenType lexNumber(LiteralParserToken&); + LiteralParserToken m_currentToken; + UString m_string; + ParserMode m_mode; + const UChar* m_ptr; + const UChar* m_end; + }; + + class StackGuard; + JSValue parse(ParserState); + + ExecState* m_exec; + LiteralParser::Lexer m_lexer; + ParserMode m_mode; + }; +} + +#endif diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Lookup.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Lookup.cpp new file mode 100644 index 0000000..8359ff7 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Lookup.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "Lookup.h" + +#include "JSFunction.h" +#include "PrototypeFunction.h" + +namespace JSC { + +void HashTable::createTable(JSGlobalData* globalData) const +{ + 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) { + UString::Rep* identifier = Identifier::add(globalData, values[i].key).releaseRef(); + int hashIndex = identifier->computedHash() & 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); + } + table = entries; +} + +void HashTable::deleteTable() const +{ + if (table) { + int max = compactSize; + for (int i = 0; i != max; ++i) { + if (UString::Rep* key = table[i].key()) + key->deref(); + } + delete [] table; + table = 0; + } +} + +void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot) +{ + ASSERT(entry->attributes() & Function); + JSValue* location = thisObj->getDirectLocation(propertyName); + + if (!location) { + InternalFunction* function = new (exec) NativeFunctionWrapper(exec, exec->lexicalGlobalObject()->prototypeFunctionStructure(), entry->functionLength(), propertyName, entry->function()); + + thisObj->putDirectFunction(propertyName, function, entry->attributes()); + location = thisObj->getDirectLocation(propertyName); + } + + slot.setValueSlot(thisObj, location, thisObj->offsetForLocation(location)); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Lookup.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Lookup.h new file mode 100644 index 0000000..167f2bc --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Lookup.h @@ -0,0 +1,265 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef Lookup_h +#define Lookup_h + +#include "CallFrame.h" +#include "Identifier.h" +#include "JSGlobalObject.h" +#include "JSObject.h" +#include "PropertySlot.h" +#include <stdio.h> +#include <wtf/Assertions.h> + +// Bug #26843: Work around Metrowerks compiler bug +#if COMPILER(WINSCW) +#define JSC_CONST_HASHTABLE +#else +#define JSC_CONST_HASHTABLE const +#endif + +namespace JSC { + + // Hash table generated by the create_hash_table script. + struct HashTableValue { + const char* key; // property name + unsigned char attributes; // JSObject attributes + intptr_t value1; + intptr_t value2; + }; + + // FIXME: There is no reason this get function can't be simpler. + // ie. typedef JSValue (*GetFunction)(ExecState*, JSObject* baseObject) + typedef PropertySlot::GetValueFunc GetFunction; + typedef void (*PutFunction)(ExecState*, JSObject* baseObject, JSValue value); + + class HashEntry { + public: + void initialize(UString::Rep* key, unsigned char attributes, intptr_t v1, intptr_t v2) + { + m_key = key; + m_attributes = attributes; + m_u.store.value1 = v1; + m_u.store.value2 = v2; + m_next = 0; + } + + void setKey(UString::Rep* key) { m_key = key; } + UString::Rep* key() const { return m_key; } + + unsigned char attributes() const { return m_attributes; } + + 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); } + + GetFunction propertyGetter() const { ASSERT(!(m_attributes & Function)); return m_u.property.get; } + PutFunction propertyPutter() const { ASSERT(!(m_attributes & Function)); return m_u.property.put; } + + intptr_t lexerValue() const { ASSERT(!m_attributes); return m_u.lexer.value; } + + void setNext(HashEntry *next) { m_next = next; } + HashEntry* next() const { return m_next; } + + private: + UString::Rep* m_key; + unsigned char m_attributes; // JSObject attributes + + 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; + }; + + struct HashTable { + + int compactSize; + int compactHashSizeMask; + + const HashTableValue* values; // Fixed values generated by script. + mutable const HashEntry* table; // Table allocated at runtime. + + ALWAYS_INLINE void initializeIfNeeded(JSGlobalData* globalData) const + { + if (!table) + createTable(globalData); + } + + ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const + { + if (!table) + createTable(&exec->globalData()); + } + + void deleteTable() const; + + // Find an entry in the table, and return the entry. + ALWAYS_INLINE const HashEntry* entry(JSGlobalData* globalData, const Identifier& identifier) const + { + initializeIfNeeded(globalData); + return entry(identifier); + } + + ALWAYS_INLINE const HashEntry* entry(ExecState* exec, const Identifier& identifier) const + { + initializeIfNeeded(exec); + return entry(identifier); + } + + private: + ALWAYS_INLINE const HashEntry* entry(const Identifier& identifier) const + { + ASSERT(table); + + const HashEntry* entry = &table[identifier.ustring().rep()->computedHash() & compactHashSizeMask]; + + if (!entry->key()) + return 0; + + do { + if (entry->key() == identifier.ustring().rep()) + return entry; + entry = entry->next(); + } while (entry); + + return 0; + } + + // Convert the hash table keys to identifiers. + void createTable(JSGlobalData*) const; + }; + + void setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, const Identifier& 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, const Identifier& propertyName, PropertySlot& slot) + { + const HashEntry* entry = table->entry(exec, propertyName); + + if (!entry) // not found, forward to parent + return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot); + + if (entry->attributes() & Function) + setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot); + else + slot.setCustom(thisObj, 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, const Identifier& propertyName, PropertySlot& slot) + { + if (static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertySlot(exec, propertyName, slot)) + return true; + + const HashEntry* entry = table->entry(exec, propertyName); + if (!entry) + return false; + + setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot); + return true; + } + + /** + * 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, const Identifier& propertyName, PropertySlot& slot) + { + const HashEntry* entry = table->entry(exec, propertyName); + + if (!entry) // not found, forward to parent + return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot); + + ASSERT(!(entry->attributes() & Function)); + + slot.setCustom(thisObj, entry->propertyGetter()); + return true; + } + + /** + * 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. + */ + template <class ThisImp> + inline bool lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj) + { + const HashEntry* entry = table->entry(exec, propertyName); + + if (!entry) + return false; + + if (entry->attributes() & Function) { // function: put as override property + if (LIKELY(value.isCell())) + thisObj->putDirectFunction(propertyName, value.asCell()); + else + thisObj->putDirect(propertyName, value); + } else if (!(entry->attributes() & ReadOnly)) + entry->propertyPutter()(exec, thisObj, value); + + return true; + } + + /** + * This one is for "put". + * It calls lookupPut<ThisImp>() to set the value. If that call + * returns false (meaning no entry in the hash table was found), + * then it calls put() on the ParentImp class. + */ + template <class ThisImp, class ParentImp> + inline void lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, PutPropertySlot& slot) + { + if (!lookupPut<ThisImp>(exec, propertyName, value, table, thisObj)) + thisObj->ParentImp::put(exec, propertyName, value, slot); // not found: forward to parent + } + +} // namespace JSC + +#endif // Lookup_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MathObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MathObject.cpp new file mode 100644 index 0000000..2572bc9 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MathObject.cpp @@ -0,0 +1,242 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "MathObject.h" + +#include "ObjectPrototype.h" +#include "Operations.h" +#include <time.h> +#include <wtf/Assertions.h> +#include <wtf/MathExtras.h> +#include <wtf/RandomNumber.h> +#include <wtf/RandomNumberSeed.h> + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(MathObject); + +static JSValue JSC_HOST_CALL mathProtoFuncAbs(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL mathProtoFuncACos(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL mathProtoFuncASin(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL mathProtoFuncATan(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL mathProtoFuncATan2(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL mathProtoFuncCos(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL mathProtoFuncExp(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL mathProtoFuncLog(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL mathProtoFuncMax(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL mathProtoFuncMin(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL mathProtoFuncPow(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL mathProtoFuncRound(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL mathProtoFuncSin(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL mathProtoFuncTan(ExecState*, JSObject*, JSValue, const ArgList&); + +} + +#include "MathObject.lut.h" + +namespace JSC { + +// ------------------------------ MathObject -------------------------------- + +const ClassInfo MathObject::info = { "Math", 0, 0, ExecState::mathTable }; + +/* Source for MathObject.lut.h +@begin mathTable + abs mathProtoFuncAbs DontEnum|Function 1 + acos mathProtoFuncACos DontEnum|Function 1 + asin mathProtoFuncASin DontEnum|Function 1 + atan mathProtoFuncATan DontEnum|Function 1 + atan2 mathProtoFuncATan2 DontEnum|Function 2 + ceil mathProtoFuncCeil DontEnum|Function 1 + cos mathProtoFuncCos DontEnum|Function 1 + exp mathProtoFuncExp DontEnum|Function 1 + floor mathProtoFuncFloor DontEnum|Function 1 + log mathProtoFuncLog DontEnum|Function 1 + max mathProtoFuncMax DontEnum|Function 2 + min mathProtoFuncMin DontEnum|Function 2 + pow mathProtoFuncPow DontEnum|Function 2 + random mathProtoFuncRandom DontEnum|Function 0 + round mathProtoFuncRound DontEnum|Function 1 + sin mathProtoFuncSin DontEnum|Function 1 + sqrt mathProtoFuncSqrt DontEnum|Function 1 + tan mathProtoFuncTan DontEnum|Function 1 +@end +*/ + +MathObject::MathObject(ExecState* exec, PassRefPtr<Structure> structure) + : JSObject(structure) +{ + putDirectWithoutTransition(Identifier(exec, "E"), jsNumber(exec, exp(1.0)), DontDelete | DontEnum | ReadOnly); + putDirectWithoutTransition(Identifier(exec, "LN2"), jsNumber(exec, log(2.0)), DontDelete | DontEnum | ReadOnly); + putDirectWithoutTransition(Identifier(exec, "LN10"), jsNumber(exec, log(10.0)), DontDelete | DontEnum | ReadOnly); + putDirectWithoutTransition(Identifier(exec, "LOG2E"), jsNumber(exec, 1.0 / log(2.0)), DontDelete | DontEnum | ReadOnly); + putDirectWithoutTransition(Identifier(exec, "LOG10E"), jsNumber(exec, 1.0 / log(10.0)), DontDelete | DontEnum | ReadOnly); + putDirectWithoutTransition(Identifier(exec, "PI"), jsNumber(exec, piDouble), DontDelete | DontEnum | ReadOnly); + putDirectWithoutTransition(Identifier(exec, "SQRT1_2"), jsNumber(exec, sqrt(0.5)), DontDelete | DontEnum | ReadOnly); + putDirectWithoutTransition(Identifier(exec, "SQRT2"), jsNumber(exec, sqrt(2.0)), DontDelete | DontEnum | ReadOnly); + WTF::initializeWeakRandomNumberGenerator(); +} + +// ECMA 15.8 + +bool MathObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot &slot) +{ + const HashEntry* entry = ExecState::mathTable(exec)->entry(exec, propertyName); + + if (!entry) + return JSObject::getOwnPropertySlot(exec, propertyName, slot); + + ASSERT(entry->attributes() & Function); + setUpStaticFunctionSlot(exec, entry, this, propertyName, slot); + return true; +} + +// ------------------------------ Functions -------------------------------- + +JSValue JSC_HOST_CALL mathProtoFuncAbs(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return jsNumber(exec, fabs(args.at(0).toNumber(exec))); +} + +JSValue JSC_HOST_CALL mathProtoFuncACos(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return jsNumber(exec, acos(args.at(0).toNumber(exec))); +} + +JSValue JSC_HOST_CALL mathProtoFuncASin(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return jsNumber(exec, asin(args.at(0).toNumber(exec))); +} + +JSValue JSC_HOST_CALL mathProtoFuncATan(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return jsNumber(exec, atan(args.at(0).toNumber(exec))); +} + +JSValue JSC_HOST_CALL mathProtoFuncATan2(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return jsNumber(exec, atan2(args.at(0).toNumber(exec), args.at(1).toNumber(exec))); +} + +JSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return jsNumber(exec, ceil(args.at(0).toNumber(exec))); +} + +JSValue JSC_HOST_CALL mathProtoFuncCos(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return jsNumber(exec, cos(args.at(0).toNumber(exec))); +} + +JSValue JSC_HOST_CALL mathProtoFuncExp(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return jsNumber(exec, exp(args.at(0).toNumber(exec))); +} + +JSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return jsNumber(exec, floor(args.at(0).toNumber(exec))); +} + +JSValue JSC_HOST_CALL mathProtoFuncLog(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return jsNumber(exec, log(args.at(0).toNumber(exec))); +} + +JSValue JSC_HOST_CALL mathProtoFuncMax(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + unsigned argsCount = args.size(); + double result = -Inf; + for (unsigned k = 0; k < argsCount; ++k) { + double val = args.at(k).toNumber(exec); + if (isnan(val)) { + result = NaN; + break; + } + if (val > result || (val == 0 && result == 0 && !signbit(val))) + result = val; + } + return jsNumber(exec, result); +} + +JSValue JSC_HOST_CALL mathProtoFuncMin(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + unsigned argsCount = args.size(); + double result = +Inf; + for (unsigned k = 0; k < argsCount; ++k) { + double val = args.at(k).toNumber(exec); + if (isnan(val)) { + result = NaN; + break; + } + if (val < result || (val == 0 && result == 0 && signbit(val))) + result = val; + } + return jsNumber(exec, result); +} + +JSValue JSC_HOST_CALL mathProtoFuncPow(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + // ECMA 15.8.2.1.13 + + double arg = args.at(0).toNumber(exec); + double arg2 = args.at(1).toNumber(exec); + + if (isnan(arg2)) + return jsNaN(exec); + if (isinf(arg2) && fabs(arg) == 1) + return jsNaN(exec); + return jsNumber(exec, pow(arg, arg2)); +} + +JSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState* exec, JSObject*, JSValue, const ArgList&) +{ + return jsNumber(exec, WTF::weakRandomNumber()); +} + +JSValue JSC_HOST_CALL mathProtoFuncRound(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + double arg = args.at(0).toNumber(exec); + if (signbit(arg) && arg >= -0.5) + return jsNumber(exec, -0.0); + return jsNumber(exec, floor(arg + 0.5)); +} + +JSValue JSC_HOST_CALL mathProtoFuncSin(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return jsNumber(exec, sin(args.at(0).toNumber(exec))); +} + +JSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return jsNumber(exec, sqrt(args.at(0).toNumber(exec))); +} + +JSValue JSC_HOST_CALL mathProtoFuncTan(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return jsNumber(exec, tan(args.at(0).toNumber(exec))); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MathObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MathObject.h new file mode 100644 index 0000000..3557d1e --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MathObject.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 MathObject_h +#define MathObject_h + +#include "JSObject.h" + +namespace JSC { + + class MathObject : public JSObject { + public: + MathObject(ExecState*, PassRefPtr<Structure>); + + virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType)); + } + }; + +} // namespace JSC + +#endif // MathObject_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorConstructor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorConstructor.cpp new file mode 100644 index 0000000..0205fc5 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorConstructor.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "NativeErrorConstructor.h" + +#include "ErrorInstance.h" +#include "JSFunction.h" +#include "JSString.h" +#include "NativeErrorPrototype.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(NativeErrorConstructor); + +const ClassInfo NativeErrorConstructor::info = { "Function", &InternalFunction::info, 0, 0 }; + +NativeErrorConstructor::NativeErrorConstructor(ExecState* exec, PassRefPtr<Structure> structure, NativeErrorPrototype* nativeErrorPrototype) + : InternalFunction(&exec->globalData(), structure, Identifier(exec, nativeErrorPrototype->getDirect(exec->propertyNames().name).getString())) + , m_errorStructure(ErrorInstance::createStructure(nativeErrorPrototype)) +{ + putDirect(exec->propertyNames().length, jsNumber(exec, 1), DontDelete | ReadOnly | DontEnum); // ECMA 15.11.7.5 + putDirect(exec->propertyNames().prototype, nativeErrorPrototype, DontDelete | ReadOnly | DontEnum); +} + +ErrorInstance* NativeErrorConstructor::construct(ExecState* exec, const ArgList& args) +{ + ErrorInstance* object = new (exec) ErrorInstance(m_errorStructure); + if (!args.at(0).isUndefined()) + object->putDirect(exec->propertyNames().message, jsString(exec, args.at(0).toString(exec))); + return object; +} + +static JSObject* constructWithNativeErrorConstructor(ExecState* exec, JSObject* constructor, const ArgList& args) +{ + return static_cast<NativeErrorConstructor*>(constructor)->construct(exec, args); +} + +ConstructType NativeErrorConstructor::getConstructData(ConstructData& constructData) +{ + constructData.native.function = constructWithNativeErrorConstructor; + return ConstructTypeHost; +} + +static JSValue JSC_HOST_CALL callNativeErrorConstructor(ExecState* exec, JSObject* constructor, JSValue, const ArgList& args) +{ + return static_cast<NativeErrorConstructor*>(constructor)->construct(exec, args); +} + +CallType NativeErrorConstructor::getCallData(CallData& callData) +{ + callData.native.function = callNativeErrorConstructor; + return CallTypeHost; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorConstructor.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorConstructor.h new file mode 100644 index 0000000..118d1f4 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorConstructor.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 NativeErrorConstructor_h +#define NativeErrorConstructor_h + +#include "InternalFunction.h" + +namespace JSC { + + class ErrorInstance; + class FunctionPrototype; + class NativeErrorPrototype; + + class NativeErrorConstructor : public InternalFunction { + public: + NativeErrorConstructor(ExecState*, PassRefPtr<Structure>, NativeErrorPrototype*); + + static const ClassInfo info; + + ErrorInstance* construct(ExecState*, const ArgList&); + + private: + virtual ConstructType getConstructData(ConstructData&); + virtual CallType getCallData(CallData&); + + virtual const ClassInfo* classInfo() const { return &info; } + + RefPtr<Structure> m_errorStructure; + }; + +} // namespace JSC + +#endif // NativeErrorConstructor_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorPrototype.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorPrototype.cpp new file mode 100644 index 0000000..650a0fd --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorPrototype.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "NativeErrorPrototype.h" + +#include "ErrorPrototype.h" +#include "JSString.h" +#include "UString.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(NativeErrorPrototype); + +NativeErrorPrototype::NativeErrorPrototype(ExecState* exec, PassRefPtr<Structure> structure, const UString& name, const UString& message) +#ifdef QT_BUILD_SCRIPT_LIB + : ErrorInstance(structure) +#else + : JSObject(structure) +#endif +{ + putDirect(exec->propertyNames().name, jsString(exec, name), 0); + putDirect(exec->propertyNames().message, jsString(exec, message), 0); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorPrototype.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorPrototype.h new file mode 100644 index 0000000..48a9d7e --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorPrototype.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 NativeErrorPrototype_h +#define NativeErrorPrototype_h + +#include "JSObject.h" +#ifdef QT_BUILD_SCRIPT_LIB +#include "ErrorInstance.h" +#endif + +namespace JSC { + + class NativeErrorPrototype : +#ifdef QT_BUILD_SCRIPT_LIB //According to ECMAScript Specification 15.11.7, errors must have the "Error" class + public ErrorInstance +#else + public JSObject +#endif + { + public: + NativeErrorPrototype(ExecState*, PassRefPtr<Structure>, const UString& name, const UString& message); + }; + +} // namespace JSC + +#endif // NativeErrorPrototype_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeFunctionWrapper.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeFunctionWrapper.h new file mode 100644 index 0000000..d4eeb3b --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeFunctionWrapper.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NativeFunctionWrapper_h +#define NativeFunctionWrapper_h + +namespace JSC { +#if ENABLE(JIT) && ENABLE(JIT_OPTIMIZE_NATIVE_CALL) + class JSFunction; + typedef JSFunction NativeFunctionWrapper; +#else + class PrototypeFunction; + typedef PrototypeFunction NativeFunctionWrapper; +#endif +} + +#endif diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberConstructor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberConstructor.cpp new file mode 100644 index 0000000..2840bf0 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberConstructor.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (C) 1999-2000,2003 Harri Porten (porten@kde.org) + * Copyright (C) 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + */ + +#include "config.h" +#include "NumberConstructor.h" + +#include "NumberObject.h" +#include "NumberPrototype.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(NumberConstructor); + +static JSValue numberConstructorNaNValue(ExecState*, const Identifier&, const PropertySlot&); +static JSValue numberConstructorNegInfinity(ExecState*, const Identifier&, const PropertySlot&); +static JSValue numberConstructorPosInfinity(ExecState*, const Identifier&, const PropertySlot&); +static JSValue numberConstructorMaxValue(ExecState*, const Identifier&, const PropertySlot&); +static JSValue numberConstructorMinValue(ExecState*, const Identifier&, const PropertySlot&); + +} // namespace JSC + +#include "NumberConstructor.lut.h" + +namespace JSC { + +const ClassInfo NumberConstructor::info = { "Function", &InternalFunction::info, 0, ExecState::numberTable }; + +/* Source for NumberConstructor.lut.h +@begin numberTable + 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(ExecState* exec, PassRefPtr<Structure> structure, NumberPrototype* numberPrototype) + : InternalFunction(&exec->globalData(), structure, Identifier(exec, numberPrototype->info.className)) +{ + // Number.Prototype + putDirectWithoutTransition(exec->propertyNames().prototype, numberPrototype, DontEnum | DontDelete | ReadOnly); + + // no. of arguments for constructor + putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 1), ReadOnly | DontEnum | DontDelete); +} + +bool NumberConstructor::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +{ + return getStaticValueSlot<NumberConstructor, InternalFunction>(exec, ExecState::numberTable(exec), this, propertyName, slot); +} + +static JSValue numberConstructorNaNValue(ExecState* exec, const Identifier&, const PropertySlot&) +{ + return jsNaN(exec); +} + +static JSValue numberConstructorNegInfinity(ExecState* exec, const Identifier&, const PropertySlot&) +{ + return jsNumber(exec, -Inf); +} + +static JSValue numberConstructorPosInfinity(ExecState* exec, const Identifier&, const PropertySlot&) +{ + return jsNumber(exec, Inf); +} + +static JSValue numberConstructorMaxValue(ExecState* exec, const Identifier&, const PropertySlot&) +{ + return jsNumber(exec, 1.7976931348623157E+308); +} + +static JSValue numberConstructorMinValue(ExecState* exec, const Identifier&, const PropertySlot&) +{ + return jsNumber(exec, 5E-324); +} + +// ECMA 15.7.1 +static JSObject* constructWithNumberConstructor(ExecState* exec, JSObject*, const ArgList& args) +{ + NumberObject* object = new (exec) NumberObject(exec->lexicalGlobalObject()->numberObjectStructure()); + double n = args.isEmpty() ? 0 : args.at(0).toNumber(exec); + object->setInternalValue(jsNumber(exec, n)); + return object; +} + +ConstructType NumberConstructor::getConstructData(ConstructData& constructData) +{ + constructData.native.function = constructWithNumberConstructor; + return ConstructTypeHost; +} + +// ECMA 15.7.2 +static JSValue JSC_HOST_CALL callNumberConstructor(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return jsNumber(exec, args.isEmpty() ? 0 : args.at(0).toNumber(exec)); +} + +CallType NumberConstructor::getCallData(CallData& callData) +{ + callData.native.function = callNumberConstructor; + return CallTypeHost; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberConstructor.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberConstructor.h new file mode 100644 index 0000000..b1224ec --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberConstructor.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 NumberConstructor_h +#define NumberConstructor_h + +#include "InternalFunction.h" + +namespace JSC { + + class NumberPrototype; + + class NumberConstructor : public InternalFunction { + public: + NumberConstructor(ExecState*, PassRefPtr<Structure>, NumberPrototype*); + + virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + JSValue getValueProperty(ExecState*, int token) const; + + static const ClassInfo info; + + static PassRefPtr<Structure> createStructure(JSValue proto) + { + return Structure::create(proto, TypeInfo(ObjectType, ImplementsHasInstance)); + } + + enum { NaNValue, NegInfinity, PosInfinity, MaxValue, MinValue }; + + private: + virtual ConstructType getConstructData(ConstructData&); + virtual CallType getCallData(CallData&); + + virtual const ClassInfo* classInfo() const { return &info; } + }; + +} // namespace JSC + +#endif // NumberConstructor_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberObject.cpp new file mode 100644 index 0000000..0e8df17 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberObject.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 1999-2000,2003 Harri Porten (porten@kde.org) + * Copyright (C) 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + */ + +#include "config.h" +#include "NumberObject.h" + +#include "JSGlobalObject.h" +#include "NumberPrototype.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(NumberObject); + +const ClassInfo NumberObject::info = { "Number", 0, 0, 0 }; + +NumberObject::NumberObject(PassRefPtr<Structure> structure) + : JSWrapperObject(structure) +{ +} + +JSValue NumberObject::getJSNumber() +{ + return internalValue(); +} + +NumberObject* constructNumber(ExecState* exec, JSValue number) +{ + NumberObject* object = new (exec) NumberObject(exec->lexicalGlobalObject()->numberObjectStructure()); + object->setInternalValue(number); + return object; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberObject.h new file mode 100644 index 0000000..d354b9b --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberObject.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 NumberObject_h +#define NumberObject_h + +#include "JSWrapperObject.h" + +namespace JSC { + + class NumberObject : public JSWrapperObject { + public: + explicit NumberObject(PassRefPtr<Structure>); + + static const ClassInfo info; + + private: + virtual const ClassInfo* classInfo() const { return &info; } + + virtual JSValue getJSNumber(); + }; + + NumberObject* constructNumber(ExecState*, JSValue); + +} // namespace JSC + +#endif // NumberObject_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberPrototype.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberPrototype.cpp new file mode 100644 index 0000000..947324c --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberPrototype.cpp @@ -0,0 +1,445 @@ +/* + * Copyright (C) 1999-2000,2003 Harri Porten (porten@kde.org) + * Copyright (C) 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + */ + +#include "config.h" +#include "NumberPrototype.h" + +#include "Error.h" +#include "JSFunction.h" +#include "JSString.h" +#include "PrototypeFunction.h" +#include "dtoa.h" +#include "Operations.h" +#include <wtf/Assertions.h> +#include <wtf/MathExtras.h> +#include <wtf/Vector.h> + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(NumberPrototype); + +static JSValue JSC_HOST_CALL numberProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState*, JSObject*, JSValue, const ArgList&); + +// ECMA 15.7.4 + +NumberPrototype::NumberPrototype(ExecState* exec, PassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) + : NumberObject(structure) +{ + setInternalValue(jsNumber(exec, 0)); + + // The constructor will be added later, after NumberConstructor has been constructed + + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().toString, numberProtoFuncToString), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().toLocaleString, numberProtoFuncToLocaleString), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().valueOf, numberProtoFuncValueOf), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().toFixed, numberProtoFuncToFixed), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().toExponential, numberProtoFuncToExponential), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().toPrecision, numberProtoFuncToPrecision), DontEnum); +} + +// ------------------------------ Functions --------------------------- + +// ECMA 15.7.4.2 - 15.7.4.7 + +static UString integerPartNoExp(double d) +{ + int decimalPoint; + int sign; + char result[80]; + WTF::dtoa(result, d, 0, &decimalPoint, &sign, NULL); + bool resultIsInfOrNan = (decimalPoint == 9999); + size_t length = strlen(result); + + UString str = sign ? "-" : ""; + if (resultIsInfOrNan) + str += result; + else if (decimalPoint <= 0) + str += "0"; + else { + Vector<char, 1024> buf(decimalPoint + 1); + + if (static_cast<int>(length) <= decimalPoint) { + ASSERT(decimalPoint < 1024); + memcpy(buf.data(), result, length); + memset(buf.data() + length, '0', decimalPoint - length); + } else + strncpy(buf.data(), result, decimalPoint); + buf[decimalPoint] = '\0'; + + str.append(buf.data()); + } + + return str; +} + +static UString charSequence(char c, int count) +{ + Vector<char, 2048> buf(count + 1, c); + buf[count] = '\0'; + + return UString(buf.data()); +} + +static double intPow10(int e) +{ + // This function uses the "exponentiation by squaring" algorithm and + // long double to quickly and precisely calculate integer powers of 10.0. + + // This is a handy workaround for <rdar://problem/4494756> + + if (e == 0) + return 1.0; + + bool negative = e < 0; + unsigned exp = negative ? -e : e; + + long double result = 10.0; + bool foundOne = false; + for (int bit = 31; bit >= 0; bit--) { + if (!foundOne) { + if ((exp >> bit) & 1) + foundOne = true; + } else { + result = result * result; + if ((exp >> bit) & 1) + result = result * 10.0; + } + } + + if (negative) + return static_cast<double>(1.0 / result); + return static_cast<double>(result); +} + +JSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + JSValue v = thisValue.getJSNumber(); + if (!v) + return throwError(exec, TypeError); + + double radixAsDouble = args.at(0).toInteger(exec); // nan -> 0 + if (radixAsDouble == 10 || args.at(0).isUndefined()) + return jsString(exec, v.toString(exec)); + + if (radixAsDouble < 2 || radixAsDouble > 36) + return throwError(exec, RangeError, "toString() radix argument must be between 2 and 36"); + + int radix = static_cast<int>(radixAsDouble); + const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + // INT_MAX results in 1024 characters left of the dot with radix 2 + // give the same space on the right side. safety checks are in place + // unless someone finds a precise rule. + char s[2048 + 3]; + const char* lastCharInString = s + sizeof(s) - 1; + double x = v.uncheckedGetNumber(); + if (isnan(x) || isinf(x)) + return jsString(exec, UString::from(x)); + + bool isNegative = x < 0.0; + if (isNegative) + x = -x; + + double integerPart = floor(x); + char* decimalPoint = s + sizeof(s) / 2; + + // convert integer portion + char* p = decimalPoint; + double d = integerPart; + do { + int remainderDigit = static_cast<int>(fmod(d, radix)); + *--p = digits[remainderDigit]; + d /= radix; + } while ((d <= -1.0 || d >= 1.0) && s < p); + + if (isNegative) + *--p = '-'; + char* startOfResultString = p; + ASSERT(s <= startOfResultString); + + d = x - integerPart; + p = decimalPoint; + const double epsilon = 0.001; // TODO: guessed. base on radix ? + bool hasFractionalPart = (d < -epsilon || d > epsilon); + if (hasFractionalPart) { + *p++ = '.'; + do { + d *= radix; + const int digit = static_cast<int>(d); + *p++ = digits[digit]; + d -= digit; + } while ((d < -epsilon || d > epsilon) && p < lastCharInString); + } + *p = '\0'; + ASSERT(p < s + sizeof(s)); + + return jsString(exec, startOfResultString); +} + +JSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + // FIXME: Not implemented yet. + + JSValue v = thisValue.getJSNumber(); + if (!v) + return throwError(exec, TypeError); + + return jsString(exec, v.toString(exec)); +} + +JSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + JSValue v = thisValue.getJSNumber(); + if (!v) + return throwError(exec, TypeError); + + return v; +} + +JSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + JSValue v = thisValue.getJSNumber(); + if (!v) + return throwError(exec, TypeError); + + JSValue fractionDigits = args.at(0); + double df = fractionDigits.toInteger(exec); + if (!(df >= 0 && df <= 20)) + return throwError(exec, RangeError, "toFixed() digits argument must be between 0 and 20"); + int f = static_cast<int>(df); + + double x = v.uncheckedGetNumber(); + if (isnan(x)) + return jsNontrivialString(exec, "NaN"); + + UString s; + if (x < 0) { + s.append('-'); + x = -x; + } else if (x == -0.0) + x = 0; + + if (x >= pow(10.0, 21.0)) + return jsString(exec, s + UString::from(x)); + + const double tenToTheF = pow(10.0, f); + double n = floor(x * tenToTheF); + if (fabs(n / tenToTheF - x) >= fabs((n + 1) / tenToTheF - x)) + n++; + + UString m = integerPartNoExp(n); + + int k = m.size(); + if (k <= f) { + UString z; + for (int i = 0; i < f + 1 - k; i++) + z.append('0'); + m = z + m; + k = f + 1; + ASSERT(k == m.size()); + } + int kMinusf = k - f; + if (kMinusf < m.size()) + return jsString(exec, s + m.substr(0, kMinusf) + "." + m.substr(kMinusf)); + return jsString(exec, s + m.substr(0, kMinusf)); +} + +static void fractionalPartToString(char* buf, int& i, const char* result, int resultLength, int fractionalDigits) +{ + if (fractionalDigits <= 0) + return; + + int fDigitsInResult = static_cast<int>(resultLength) - 1; + buf[i++] = '.'; + if (fDigitsInResult > 0) { + if (fractionalDigits < fDigitsInResult) { + strncpy(buf + i, result + 1, fractionalDigits); + i += fractionalDigits; + } else { + ASSERT(i + resultLength - 1 < 80); + memcpy(buf + i, result + 1, resultLength - 1); + i += static_cast<int>(resultLength) - 1; + } + } + + for (int j = 0; j < fractionalDigits - fDigitsInResult; j++) + buf[i++] = '0'; +} + +static void exponentialPartToString(char* buf, int& i, int decimalPoint) +{ + buf[i++] = 'e'; + // decimalPoint can't be more than 3 digits decimal given the + // nature of float representation + int exponential = decimalPoint - 1; + buf[i++] = (exponential >= 0) ? '+' : '-'; + if (exponential < 0) + exponential *= -1; + if (exponential >= 100) + buf[i++] = static_cast<char>('0' + exponential / 100); + if (exponential >= 10) + buf[i++] = static_cast<char>('0' + (exponential % 100) / 10); + buf[i++] = static_cast<char>('0' + exponential % 10); +} + +JSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + JSValue v = thisValue.getJSNumber(); + if (!v) + return throwError(exec, TypeError); + + double x = v.uncheckedGetNumber(); + + if (isnan(x) || isinf(x)) + return jsString(exec, UString::from(x)); + + JSValue fractionalDigitsValue = args.at(0); + double df = fractionalDigitsValue.toInteger(exec); + if (!(df >= 0 && df <= 20)) + return throwError(exec, RangeError, "toExponential() argument must between 0 and 20"); + int fractionalDigits = static_cast<int>(df); + bool includeAllDigits = fractionalDigitsValue.isUndefined(); + + int decimalAdjust = 0; + if (x && !includeAllDigits) { + double logx = floor(log10(fabs(x))); + x /= pow(10.0, logx); + const double tenToTheF = pow(10.0, fractionalDigits); + double fx = floor(x * tenToTheF) / tenToTheF; + double cx = ceil(x * tenToTheF) / tenToTheF; + + if (fabs(fx - x) < fabs(cx - x)) + x = fx; + else + x = cx; + + decimalAdjust = static_cast<int>(logx); + } + + if (isnan(x)) + return jsNontrivialString(exec, "NaN"); + + if (x == -0.0) // (-0.0).toExponential() should print as 0 instead of -0 + x = 0; + + int decimalPoint; + int sign; + char result[80]; + WTF::dtoa(result, x, 0, &decimalPoint, &sign, NULL); + size_t resultLength = strlen(result); + decimalPoint += decimalAdjust; + + int i = 0; + char buf[80]; // digit + '.' + fractionDigits (max 20) + 'e' + sign + exponent (max?) + if (sign) + buf[i++] = '-'; + + // ? 9999 is the magical "result is Inf or NaN" value. what's 999?? + if (decimalPoint == 999) { + ASSERT(i + resultLength < 80); + memcpy(buf + i, result, resultLength); + buf[i + resultLength] = '\0'; + } else { + buf[i++] = result[0]; + + if (includeAllDigits) + fractionalDigits = static_cast<int>(resultLength) - 1; + + fractionalPartToString(buf, i, result, resultLength, fractionalDigits); + exponentialPartToString(buf, i, decimalPoint); + buf[i++] = '\0'; + } + ASSERT(i <= 80); + + return jsString(exec, buf); +} + +JSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + JSValue v = thisValue.getJSNumber(); + if (!v) + return throwError(exec, TypeError); + + double doublePrecision = args.at(0).toIntegerPreserveNaN(exec); + double x = v.uncheckedGetNumber(); + if (args.at(0).isUndefined() || isnan(x) || isinf(x)) + return jsString(exec, v.toString(exec)); + + UString s; + if (x < 0) { + s = "-"; + x = -x; + } + + if (!(doublePrecision >= 1 && doublePrecision <= 21)) // true for NaN + return throwError(exec, RangeError, "toPrecision() argument must be between 1 and 21"); + int precision = static_cast<int>(doublePrecision); + + int e = 0; + UString m; + if (x) { + e = static_cast<int>(log10(x)); + double tens = intPow10(e - precision + 1); + double n = floor(x / tens); + if (n < intPow10(precision - 1)) { + e = e - 1; + tens = intPow10(e - precision + 1); + n = floor(x / tens); + } + + if (fabs((n + 1.0) * tens - x) <= fabs(n * tens - x)) + ++n; + // maintain n < 10^(precision) + if (n >= intPow10(precision)) { + n /= 10.0; + e += 1; + } + ASSERT(intPow10(precision - 1) <= n); + ASSERT(n < intPow10(precision)); + + m = integerPartNoExp(n); + if (e < -6 || e >= precision) { + if (m.size() > 1) + m = m.substr(0, 1) + "." + m.substr(1); + if (e >= 0) + return jsNontrivialString(exec, s + m + "e+" + UString::from(e)); + return jsNontrivialString(exec, s + m + "e-" + UString::from(-e)); + } + } else { + m = charSequence('0', precision); + e = 0; + } + + if (e == precision - 1) + return jsString(exec, s + m); + if (e >= 0) { + if (e + 1 < m.size()) + return jsString(exec, s + m.substr(0, e + 1) + "." + m.substr(e + 1)); + return jsString(exec, s + m); + } + return jsNontrivialString(exec, s + "0." + charSequence('0', -(e + 1)) + m); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberPrototype.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberPrototype.h new file mode 100644 index 0000000..0a3a544 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberPrototype.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 NumberPrototype_h +#define NumberPrototype_h + +#include "NumberObject.h" + +namespace JSC { + + class NumberPrototype : public NumberObject { + public: + NumberPrototype(ExecState*, PassRefPtr<Structure>, Structure* prototypeFunctionStructure); + }; + +} // namespace JSC + +#endif // NumberPrototype_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectConstructor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectConstructor.cpp new file mode 100644 index 0000000..cf1790f --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectConstructor.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "ObjectConstructor.h" + +#include "JSFunction.h" +#include "JSGlobalObject.h" +#include "ObjectPrototype.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(ObjectConstructor); + +ObjectConstructor::ObjectConstructor(ExecState* exec, PassRefPtr<Structure> structure, ObjectPrototype* objectPrototype) + : InternalFunction(&exec->globalData(), structure, Identifier(exec, "Object")) +{ + // ECMA 15.2.3.1 + putDirectWithoutTransition(exec->propertyNames().prototype, objectPrototype, DontEnum | DontDelete | ReadOnly); + + // no. of arguments for constructor + putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 1), ReadOnly | DontEnum | DontDelete); +} + +// ECMA 15.2.2 +static ALWAYS_INLINE JSObject* constructObject(ExecState* exec, const ArgList& args) +{ + JSValue arg = args.at(0); + if (arg.isUndefinedOrNull()) + return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure()); + return arg.toObject(exec); +} + +static JSObject* constructWithObjectConstructor(ExecState* exec, JSObject*, const ArgList& args) +{ + return constructObject(exec, args); +} + +ConstructType ObjectConstructor::getConstructData(ConstructData& constructData) +{ + constructData.native.function = constructWithObjectConstructor; + return ConstructTypeHost; +} + +static JSValue JSC_HOST_CALL callObjectConstructor(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return constructObject(exec, args); +} + +CallType ObjectConstructor::getCallData(CallData& callData) +{ + callData.native.function = callObjectConstructor; + return CallTypeHost; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectConstructor.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectConstructor.h new file mode 100644 index 0000000..f8c058a --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectConstructor.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 ObjectConstructor_h +#define ObjectConstructor_h + +#include "InternalFunction.h" + +namespace JSC { + + class ObjectPrototype; + + class ObjectConstructor : public InternalFunction { + public: + ObjectConstructor(ExecState*, PassRefPtr<Structure>, ObjectPrototype*); + + private: + virtual ConstructType getConstructData(ConstructData&); + virtual CallType getCallData(CallData&); + }; + +} // namespace JSC + +#endif // ObjectConstructor_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectPrototype.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectPrototype.cpp new file mode 100644 index 0000000..98e4713 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectPrototype.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "ObjectPrototype.h" + +#include "Error.h" +#include "JSFunction.h" +#include "JSString.h" +#include "PrototypeFunction.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(ObjectPrototype); + +static JSValue JSC_HOST_CALL objectProtoFuncValueOf(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL objectProtoFuncHasOwnProperty(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL objectProtoFuncIsPrototypeOf(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL objectProtoFuncDefineGetter(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL objectProtoFuncDefineSetter(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL objectProtoFuncLookupGetter(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState*, JSObject*, JSValue, const ArgList&); + +ObjectPrototype::ObjectPrototype(ExecState* exec, PassRefPtr<Structure> stucture, Structure* prototypeFunctionStructure) + : JSObject(stucture) +{ + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().toString, objectProtoFuncToString), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().toLocaleString, objectProtoFuncToLocaleString), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().valueOf, objectProtoFuncValueOf), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().hasOwnProperty, objectProtoFuncHasOwnProperty), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().propertyIsEnumerable, objectProtoFuncPropertyIsEnumerable), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().isPrototypeOf, objectProtoFuncIsPrototypeOf), DontEnum); + + // Mozilla extensions + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 2, exec->propertyNames().__defineGetter__, objectProtoFuncDefineGetter), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 2, exec->propertyNames().__defineSetter__, objectProtoFuncDefineSetter), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().__lookupGetter__, objectProtoFuncLookupGetter), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().__lookupSetter__, objectProtoFuncLookupSetter), DontEnum); +} + +// ------------------------------ Functions -------------------------------- + +// ECMA 15.2.4.2, 15.2.4.4, 15.2.4.5, 15.2.4.7 + +JSValue JSC_HOST_CALL objectProtoFuncValueOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + return thisValue.toThisObject(exec); +} + +JSValue JSC_HOST_CALL objectProtoFuncHasOwnProperty(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + return jsBoolean(thisValue.toThisObject(exec)->hasOwnProperty(exec, Identifier(exec, args.at(0).toString(exec)))); +} + +JSValue JSC_HOST_CALL objectProtoFuncIsPrototypeOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + JSObject* thisObj = thisValue.toThisObject(exec); + + if (!args.at(0).isObject()) + return jsBoolean(false); + + JSValue v = asObject(args.at(0))->prototype(); + + while (true) { + if (!v.isObject()) + return jsBoolean(false); + if (v == thisObj) + return jsBoolean(true); + v = asObject(v)->prototype(); + } +} + +JSValue JSC_HOST_CALL objectProtoFuncDefineGetter(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + CallData callData; + if (args.at(1).getCallData(callData) == CallTypeNone) + return throwError(exec, SyntaxError, "invalid getter usage"); + thisValue.toThisObject(exec)->defineGetter(exec, Identifier(exec, args.at(0).toString(exec)), asObject(args.at(1))); + return jsUndefined(); +} + +JSValue JSC_HOST_CALL objectProtoFuncDefineSetter(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + CallData callData; + if (args.at(1).getCallData(callData) == CallTypeNone) + return throwError(exec, SyntaxError, "invalid setter usage"); + thisValue.toThisObject(exec)->defineSetter(exec, Identifier(exec, args.at(0).toString(exec)), asObject(args.at(1))); + return jsUndefined(); +} + +JSValue JSC_HOST_CALL objectProtoFuncLookupGetter(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + return thisValue.toThisObject(exec)->lookupGetter(exec, Identifier(exec, args.at(0).toString(exec))); +} + +JSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + return thisValue.toThisObject(exec)->lookupSetter(exec, Identifier(exec, args.at(0).toString(exec))); +} + +JSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + return jsBoolean(thisValue.toThisObject(exec)->propertyIsEnumerable(exec, Identifier(exec, args.at(0).toString(exec)))); +} + +JSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + return thisValue.toThisJSString(exec); +} + +JSValue JSC_HOST_CALL objectProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + return jsNontrivialString(exec, "[object " + thisValue.toThisObject(exec)->className() + "]"); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectPrototype.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectPrototype.h new file mode 100644 index 0000000..7790ae0 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectPrototype.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 ObjectPrototype_h +#define ObjectPrototype_h + +#include "JSObject.h" + +namespace JSC { + + class ObjectPrototype : public JSObject { + public: + ObjectPrototype(ExecState*, PassRefPtr<Structure>, Structure* prototypeFunctionStructure); + }; + + JSValue JSC_HOST_CALL objectProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&); + +} // namespace JSC + +#endif // ObjectPrototype_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Operations.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Operations.cpp new file mode 100644 index 0000000..093bbec --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Operations.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 "Operations.h" + +#include "Error.h" +#include "JSObject.h" +#include "JSString.h" +#include <math.h> +#include <stdio.h> +#include <wtf/MathExtras.h> + +#if HAVE(FLOAT_H) +#include <float.h> +#endif + +namespace JSC { + +bool JSValue::equalSlowCase(ExecState* exec, JSValue v1, JSValue v2) +{ + return equalSlowCaseInline(exec, v1, v2); +} + +bool JSValue::strictEqualSlowCase(JSValue v1, JSValue v2) +{ + return strictEqualSlowCaseInline(v1, v2); +} + +NEVER_INLINE JSValue throwOutOfMemoryError(ExecState* exec) +{ + JSObject* error = Error::create(exec, GeneralError, "Out of memory"); + exec->setException(error); + return error; +} + +NEVER_INLINE JSValue jsAddSlowCase(CallFrame* callFrame, JSValue v1, JSValue v2) +{ + // exception for the Date exception in defaultValue() + JSValue p1 = v1.toPrimitive(callFrame); + JSValue p2 = v2.toPrimitive(callFrame); + + if (p1.isString() || p2.isString()) { + RefPtr<UString::Rep> value = concatenate(p1.toString(callFrame).rep(), p2.toString(callFrame).rep()); + if (!value) + return throwOutOfMemoryError(callFrame); + return jsString(callFrame, value.release()); + } + + return jsNumber(callFrame, p1.toNumber(callFrame) + p2.toNumber(callFrame)); +} + +JSValue jsTypeStringForValue(CallFrame* callFrame, JSValue v) +{ + if (v.isUndefined()) + return jsNontrivialString(callFrame, "undefined"); + if (v.isBoolean()) + return jsNontrivialString(callFrame, "boolean"); + if (v.isNumber()) + return jsNontrivialString(callFrame, "number"); + if (v.isString()) + return jsNontrivialString(callFrame, "string"); + if (v.isObject()) { + // Return "undefined" for objects that should be treated + // as null when doing comparisons. + if (asObject(v)->structure()->typeInfo().masqueradesAsUndefined()) + return jsNontrivialString(callFrame, "undefined"); + CallData callData; + if (asObject(v)->getCallData(callData) != CallTypeNone) + return jsNontrivialString(callFrame, "function"); + } + return jsNontrivialString(callFrame, "object"); +} + +bool jsIsObjectType(JSValue v) +{ + if (!v.isCell()) + return v.isNull(); + + JSType type = asCell(v)->structure()->typeInfo().type(); + if (type == NumberType || type == StringType) + return false; + if (type == ObjectType) { + if (asObject(v)->structure()->typeInfo().masqueradesAsUndefined()) + return false; + CallData callData; + if (asObject(v)->getCallData(callData) != CallTypeNone) + return false; + } + return true; +} + +bool jsIsFunctionType(JSValue v) +{ + if (v.isObject()) { + CallData callData; + if (asObject(v)->getCallData(callData) != CallTypeNone) + return true; + } + return false; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Operations.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Operations.h new file mode 100644 index 0000000..acfc6c2 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Operations.h @@ -0,0 +1,334 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2002, 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 + * 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 Operations_h +#define Operations_h + +#include "Interpreter.h" +#include "JSImmediate.h" +#include "JSNumberCell.h" +#include "JSString.h" + +namespace JSC { + + NEVER_INLINE JSValue throwOutOfMemoryError(ExecState*); + NEVER_INLINE JSValue jsAddSlowCase(CallFrame*, JSValue, JSValue); + JSValue jsTypeStringForValue(CallFrame*, JSValue); + bool jsIsObjectType(JSValue); + bool jsIsFunctionType(JSValue); + + // ECMA 11.9.3 + inline bool JSValue::equal(ExecState* exec, JSValue v1, JSValue v2) + { + if (JSImmediate::areBothImmediateIntegerNumbers(v1, v2)) + return v1 == v2; + + return equalSlowCase(exec, v1, v2); + } + + ALWAYS_INLINE bool JSValue::equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2) + { + ASSERT(!JSImmediate::areBothImmediateIntegerNumbers(v1, v2)); + + do { + if (v1.isNumber() && v2.isNumber()) + return v1.uncheckedGetNumber() == v2.uncheckedGetNumber(); + + bool s1 = v1.isString(); + bool s2 = v2.isString(); + if (s1 && s2) + return asString(v1)->value() == asString(v2)->value(); + + if (v1.isUndefinedOrNull()) { + if (v2.isUndefinedOrNull()) + return true; + if (JSImmediate::isImmediate(v2)) + return false; + return v2.asCell()->structure()->typeInfo().masqueradesAsUndefined(); + } + + if (v2.isUndefinedOrNull()) { + if (JSImmediate::isImmediate(v1)) + return false; + return v1.asCell()->structure()->typeInfo().masqueradesAsUndefined(); + } + + if (v1.isObject()) { + if (v2.isObject()) + return v1 == v2; + JSValue p1 = v1.toPrimitive(exec); + if (exec->hadException()) + return false; + v1 = p1; + if (JSImmediate::areBothImmediateIntegerNumbers(v1, v2)) + return v1 == v2; + continue; + } + + if (v2.isObject()) { + JSValue p2 = v2.toPrimitive(exec); + if (exec->hadException()) + return false; + v2 = p2; + if (JSImmediate::areBothImmediateIntegerNumbers(v1, v2)) + return v1 == v2; + continue; + } + + if (s1 || s2) { + double d1 = v1.toNumber(exec); + double d2 = v2.toNumber(exec); + return d1 == d2; + } + + if (v1.isBoolean()) { + if (v2.isNumber()) + return static_cast<double>(v1.getBoolean()) == v2.uncheckedGetNumber(); + } else if (v2.isBoolean()) { + if (v1.isNumber()) + return v1.uncheckedGetNumber() == static_cast<double>(v2.getBoolean()); + } + + return v1 == v2; + } while (true); + } + + // ECMA 11.9.3 + ALWAYS_INLINE bool JSValue::strictEqualSlowCaseInline(JSValue v1, JSValue v2) + { + ASSERT(!JSImmediate::isEitherImmediate(v1, v2)); + + if (v1.asCell()->isString() && v2.asCell()->isString()) + return asString(v1)->value() == asString(v2)->value(); + + return v1 == v2; + } + + inline bool JSValue::strictEqual(JSValue v1, JSValue v2) + { + if (JSImmediate::areBothImmediateIntegerNumbers(v1, v2)) + return v1 == v2; + + if (v1.isNumber() && v2.isNumber()) + return v1.uncheckedGetNumber() == v2.uncheckedGetNumber(); + + if (JSImmediate::isEitherImmediate(v1, v2)) + return v1 == v2; + + return strictEqualSlowCaseInline(v1, v2); + } + + inline bool jsLess(CallFrame* callFrame, JSValue v1, JSValue v2) + { + if (JSValue::areBothInt32Fast(v1, v2)) + return v1.getInt32Fast() < v2.getInt32Fast(); + + double n1; + double n2; + if (v1.getNumber(n1) && v2.getNumber(n2)) + return n1 < n2; + + JSGlobalData* globalData = &callFrame->globalData(); + if (isJSString(globalData, v1) && isJSString(globalData, v2)) + return asString(v1)->value() < asString(v2)->value(); + + JSValue p1; + JSValue p2; + bool wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1); + bool wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2); + + if (wasNotString1 | wasNotString2) + return n1 < n2; + + return asString(p1)->value() < asString(p2)->value(); + } + + inline bool jsLessEq(CallFrame* callFrame, JSValue v1, JSValue v2) + { + if (JSValue::areBothInt32Fast(v1, v2)) + return v1.getInt32Fast() <= v2.getInt32Fast(); + + double n1; + double n2; + if (v1.getNumber(n1) && v2.getNumber(n2)) + return n1 <= n2; + + JSGlobalData* globalData = &callFrame->globalData(); + if (isJSString(globalData, v1) && isJSString(globalData, v2)) + return !(asString(v2)->value() < asString(v1)->value()); + + JSValue p1; + JSValue p2; + bool wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1); + bool wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2); + + if (wasNotString1 | wasNotString2) + return n1 <= n2; + + return !(asString(p2)->value() < asString(p1)->value()); + } + + // Fast-path choices here are based on frequency data from SunSpider: + // <times> Add case: <t1> <t2> + // --------------------------- + // 5626160 Add case: 3 3 (of these, 3637690 are for immediate values) + // 247412 Add case: 5 5 + // 20900 Add case: 5 6 + // 13962 Add case: 5 3 + // 4000 Add case: 3 5 + + ALWAYS_INLINE JSValue jsAdd(CallFrame* callFrame, JSValue v1, JSValue v2) + { + double left; + double right = 0.0; + + bool rightIsNumber = v2.getNumber(right); + if (rightIsNumber && v1.getNumber(left)) + return jsNumber(callFrame, left + right); + + bool leftIsString = v1.isString(); + if (leftIsString && v2.isString()) { + RefPtr<UString::Rep> value = concatenate(asString(v1)->value().rep(), asString(v2)->value().rep()); + if (!value) + return throwOutOfMemoryError(callFrame); + return jsString(callFrame, value.release()); + } + + if (rightIsNumber & leftIsString) { + RefPtr<UString::Rep> value = v2.isInt32Fast() ? + concatenate(asString(v1)->value().rep(), v2.getInt32Fast()) : + concatenate(asString(v1)->value().rep(), right); + + if (!value) + return throwOutOfMemoryError(callFrame); + return jsString(callFrame, value.release()); + } + + // All other cases are pretty uncommon + return jsAddSlowCase(callFrame, v1, v2); + } + + inline size_t countPrototypeChainEntriesAndCheckForProxies(CallFrame* callFrame, JSValue baseValue, const PropertySlot& slot) + { + JSCell* cell = asCell(baseValue); + size_t count = 0; + + while (slot.slotBase() != cell) { + JSValue v = cell->structure()->prototypeForLookup(callFrame); + + // If we didn't find slotBase in baseValue's prototype chain, then baseValue + // must be a proxy for another object. + + if (v.isNull()) + return 0; + + cell = asCell(v); + + // 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)->setStructure(Structure::fromDictionaryTransition(cell->structure())); + + ++count; + } + + ASSERT(count); + return count; + } + + ALWAYS_INLINE JSValue resolveBase(CallFrame* callFrame, Identifier& property, ScopeChainNode* scopeChain) + { + ScopeChainIterator iter = scopeChain->begin(); + ScopeChainIterator next = iter; + ++next; + ScopeChainIterator end = scopeChain->end(); + ASSERT(iter != end); + + PropertySlot slot; + JSObject* base; + while (true) { + base = *iter; + if (next == end || base->getPropertySlot(callFrame, property, slot)) + return base; + + iter = next; + ++next; + } + + ASSERT_NOT_REACHED(); + return JSValue(); + } + + ALWAYS_INLINE JSValue concatenateStrings(CallFrame* callFrame, Register* strings, unsigned count) + { + ASSERT(count >= 3); + + // Estimate the amount of space required to hold the entire string. If all + // arguments are strings, we can easily calculate the exact amount of space + // required. For any other arguments, for now let's assume they may require + // 11 UChars of storage. This is enouch to hold any int, and likely is also + // reasonable for the other immediates. We may want to come back and tune + // this value at some point. + unsigned bufferSize = 0; + for (unsigned i = 0; i < count; ++i) { + JSValue v = strings[i].jsValue(); + if (LIKELY(v.isString())) + bufferSize += asString(v)->value().size(); + else + bufferSize += 11; + } + + // Allocate an output string to store the result. + // If the first argument is a String, and if it has the capacity (or can grow + // its capacity) to hold the entire result then use this as a base to concatenate + // onto. Otherwise, allocate a new empty output buffer. + JSValue firstValue = strings[0].jsValue(); + RefPtr<UString::Rep> resultRep; + if (firstValue.isString() && (resultRep = asString(firstValue)->value().rep())->reserveCapacity(bufferSize)) { + // We're going to concatenate onto the first string - remove it from the list of items to be appended. + ++strings; + --count; + } else + resultRep = UString::Rep::createEmptyBuffer(bufferSize); + UString result(resultRep); + + // Loop over the openards, writing them into the output buffer. + for (unsigned i = 0; i < count; ++i) { + JSValue v = strings[i].jsValue(); + if (LIKELY(v.isString())) + result.append(asString(v)->value()); + else if (v.isInt32Fast()) + result.appendNumeric(v.getInt32Fast()); + else { + double d; + if (v.getNumber(d)) + result.appendNumeric(d); + else + result.append(v.toString(callFrame)); + } + } + + return jsString(callFrame, result); + } + +} // namespace JSC + +#endif // Operations_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyMapHashTable.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyMapHashTable.h new file mode 100644 index 0000000..44dc2b8 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyMapHashTable.h @@ -0,0 +1,90 @@ +/* + * 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 + * 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 PropertyMapHashTable_h +#define PropertyMapHashTable_h + +#include "UString.h" +#include <wtf/Vector.h> + +namespace JSC { + + struct PropertyMapEntry { + UString::Rep* key; + unsigned offset; + unsigned attributes; + JSCell* specificValue; + unsigned index; + + PropertyMapEntry(UString::Rep* key, unsigned attributes, JSCell* specificValue) + : key(key) + , offset(0) + , attributes(attributes) + , specificValue(specificValue) + , index(0) + { + } + + PropertyMapEntry(UString::Rep* key, unsigned offset, unsigned attributes, JSCell* specificValue, unsigned index) + : key(key) + , offset(offset) + , attributes(attributes) + , specificValue(specificValue) + , index(index) + { + } + }; + + // lastIndexUsed is an ever-increasing index used to identify the order items + // were inserted into the property map. It's required that getEnumerablePropertyNames + // return the properties in the order they were added for compatibility with other + // browsers' JavaScript implementations. + struct PropertyMapHashTable { + unsigned sizeMask; + unsigned size; + unsigned keyCount; + unsigned deletedSentinelCount; + unsigned lastIndexUsed; + Vector<unsigned>* deletedOffsets; + unsigned entryIndices[1]; + + PropertyMapEntry* entries() + { + // The entries vector comes after the indices vector. + // The 0th item in the entries vector is not really used; it has to + // have a 0 in its key to allow the hash table lookup to handle deleted + // sentinels without any special-case code, but the other fields are unused. + return reinterpret_cast<PropertyMapEntry*>(&entryIndices[size]); + } + + static size_t allocationSize(unsigned size) + { + // We never let a hash table get more than half full, + // So the number of indices we need is the size of the hash table. + // But the number of entries is half that (plus one for the deleted sentinel). + return sizeof(PropertyMapHashTable) + + (size - 1) * sizeof(unsigned) + + (1 + size / 2) * sizeof(PropertyMapEntry); + } + }; + +} // namespace JSC + +#endif // PropertyMapHashTable_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyNameArray.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyNameArray.cpp new file mode 100644 index 0000000..0878e73 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyNameArray.cpp @@ -0,0 +1,50 @@ +/* + * 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" + +namespace JSC { + +static const size_t setThreshold = 20; + +void PropertyNameArray::add(UString::Rep* identifier) +{ + ASSERT(identifier == &UString::Rep::null() || identifier == &UString::Rep::empty() || identifier->identifierTable()); + + size_t size = m_data->propertyNameVector().size(); + if (size < setThreshold) { + for (size_t i = 0; i < size; ++i) { + if (identifier == m_data->propertyNameVector()[i].ustring().rep()) + return; + } + } else { + if (m_set.isEmpty()) { + for (size_t i = 0; i < size; ++i) + m_set.add(m_data->propertyNameVector()[i].ustring().rep()); + } + if (!m_set.add(identifier).second) + return; + } + + m_data->propertyNameVector().append(Identifier(m_globalData, identifier)); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyNameArray.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyNameArray.h new file mode 100644 index 0000000..67ee9c8 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyNameArray.h @@ -0,0 +1,113 @@ +/* + * 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. + * + */ + +#ifndef PropertyNameArray_h +#define PropertyNameArray_h + +#include "CallFrame.h" +#include "Identifier.h" +#include "Structure.h" +#include "StructureChain.h" +#include <wtf/HashSet.h> +#include <wtf/Vector.h> + +namespace JSC { + + class PropertyNameArrayData : public RefCounted<PropertyNameArrayData> { + public: + typedef Vector<Identifier, 20> PropertyNameVector; + typedef PropertyNameVector::const_iterator const_iterator; + + static PassRefPtr<PropertyNameArrayData> create() { return adoptRef(new PropertyNameArrayData); } + + const_iterator begin() const { return m_propertyNameVector.begin(); } + const_iterator end() const { return m_propertyNameVector.end(); } + + PropertyNameVector& propertyNameVector() { return m_propertyNameVector; } + + void setCachedStructure(Structure* structure) { m_cachedStructure = structure; } + Structure* cachedStructure() const { return m_cachedStructure; } + + void setCachedPrototypeChain(PassRefPtr<StructureChain> cachedPrototypeChain) { m_cachedPrototypeChain = cachedPrototypeChain; } + StructureChain* cachedPrototypeChain() { return m_cachedPrototypeChain.get(); } + + private: + PropertyNameArrayData() + : m_cachedStructure(0) + { + } + + PropertyNameVector m_propertyNameVector; + Structure* m_cachedStructure; + RefPtr<StructureChain> m_cachedPrototypeChain; + }; + + class PropertyNameArray { + public: + typedef PropertyNameArrayData::const_iterator const_iterator; + + PropertyNameArray(JSGlobalData* globalData) + : m_data(PropertyNameArrayData::create()) + , m_globalData(globalData) + , m_shouldCache(true) + { + } + + PropertyNameArray(ExecState* exec) + : m_data(PropertyNameArrayData::create()) + , m_globalData(&exec->globalData()) + , m_shouldCache(true) + { + } + + JSGlobalData* globalData() { return m_globalData; } + + void add(const Identifier& identifier) { add(identifier.ustring().rep()); } + void add(UString::Rep*); + void addKnownUnique(UString::Rep* identifier) { m_data->propertyNameVector().append(Identifier(m_globalData, identifier)); } + + size_t size() const { return m_data->propertyNameVector().size(); } + + Identifier& operator[](unsigned i) { return m_data->propertyNameVector()[i]; } + const Identifier& operator[](unsigned i) const { return m_data->propertyNameVector()[i]; } + + const_iterator begin() const { return m_data->begin(); } + const_iterator end() const { return m_data->end(); } + + void setData(PassRefPtr<PropertyNameArrayData> data) { m_data = data; } + PropertyNameArrayData* data() { return m_data.get(); } + + PassRefPtr<PropertyNameArrayData> releaseData() { return m_data.release(); } + + void setShouldCache(bool shouldCache) { m_shouldCache = shouldCache; } + bool shouldCache() const { return m_shouldCache; } + + private: + typedef HashSet<UString::Rep*, PtrHash<UString::Rep*> > IdentifierSet; + + RefPtr<PropertyNameArrayData> m_data; + IdentifierSet m_set; + JSGlobalData* m_globalData; + bool m_shouldCache; + }; + +} // namespace JSC + +#endif // PropertyNameArray_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertySlot.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertySlot.cpp new file mode 100644 index 0000000..36fa5d8 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertySlot.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2005, 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 "PropertySlot.h" + +#include "JSFunction.h" +#include "JSGlobalObject.h" +#include "JSObject.h" + +namespace JSC { + +JSValue PropertySlot::functionGetter(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + // Prevent getter functions from observing execution if an exception is pending. + if (exec->hadException()) + return exec->exception(); + + CallData callData; + CallType callType = slot.m_data.getterFunc->getCallData(callData); + if (callType == CallTypeHost) + return callData.native.function(exec, slot.m_data.getterFunc, slot.slotBase(), exec->emptyList()); + ASSERT(callType == CallTypeJS); + // FIXME: Can this be done more efficiently using the callData? + return static_cast<JSFunction*>(slot.m_data.getterFunc)->call(exec, slot.slotBase(), exec->emptyList()); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertySlot.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertySlot.h new file mode 100644 index 0000000..da0d152 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertySlot.h @@ -0,0 +1,203 @@ +/* + * 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 + * 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 PropertySlot_h +#define PropertySlot_h + +#include "Identifier.h" +#include "JSValue.h" +#include "JSImmediate.h" +#include "Register.h" +#include <wtf/Assertions.h> +#include <wtf/NotFound.h> + +namespace JSC { + + class ExecState; + class JSObject; + +#define JSC_VALUE_SLOT_MARKER 0 +#define JSC_REGISTER_SLOT_MARKER reinterpret_cast<GetValueFunc>(1) + + class PropertySlot { + public: + PropertySlot() + : m_offset(WTF::notFound) + { + clearBase(); + clearValue(); + } + + explicit PropertySlot(const JSValue base) + : m_slotBase(base) + , m_offset(WTF::notFound) + { + clearValue(); + } + + typedef JSValue (*GetValueFunc)(ExecState*, const Identifier&, const PropertySlot&); + + JSValue getValue(ExecState* exec, const Identifier& propertyName) const + { + if (m_getValue == JSC_VALUE_SLOT_MARKER) + return *m_data.valueSlot; + if (m_getValue == JSC_REGISTER_SLOT_MARKER) + return (*m_data.registerSlot).jsValue(); + return m_getValue(exec, propertyName, *this); + } + + JSValue getValue(ExecState* exec, unsigned propertyName) const + { + if (m_getValue == JSC_VALUE_SLOT_MARKER) + return *m_data.valueSlot; + if (m_getValue == JSC_REGISTER_SLOT_MARKER) + return (*m_data.registerSlot).jsValue(); + return m_getValue(exec, Identifier::from(exec, propertyName), *this); + } + + bool isCacheable() const { return m_offset != WTF::notFound; } + size_t cachedOffset() const + { + ASSERT(isCacheable()); + return m_offset; + } + + void setValueSlot(JSValue* valueSlot) + { + ASSERT(valueSlot); + m_getValue = JSC_VALUE_SLOT_MARKER; + clearBase(); + m_data.valueSlot = valueSlot; + } + + void setValueSlot(JSValue slotBase, JSValue* valueSlot) + { + ASSERT(valueSlot); + m_getValue = JSC_VALUE_SLOT_MARKER; + m_slotBase = slotBase; + m_data.valueSlot = valueSlot; + } + + void setValueSlot(JSValue slotBase, JSValue* valueSlot, size_t offset) + { + ASSERT(valueSlot); + m_getValue = JSC_VALUE_SLOT_MARKER; + m_slotBase = slotBase; + m_data.valueSlot = valueSlot; + m_offset = offset; + } + + void setValue(JSValue value) + { + ASSERT(value); + m_getValue = JSC_VALUE_SLOT_MARKER; + clearBase(); + m_value = value; + m_data.valueSlot = &m_value; + } + + void setRegisterSlot(Register* registerSlot) + { + ASSERT(registerSlot); + m_getValue = JSC_REGISTER_SLOT_MARKER; + clearBase(); + m_data.registerSlot = registerSlot; + } + + void setCustom(JSValue slotBase, GetValueFunc getValue) + { + ASSERT(slotBase); + ASSERT(getValue); + m_getValue = getValue; + m_slotBase = slotBase; + } + + void setCustomIndex(JSValue slotBase, unsigned index, GetValueFunc getValue) + { + ASSERT(slotBase); + ASSERT(getValue); + m_getValue = getValue; + m_slotBase = slotBase; + m_data.index = index; + } + + void setGetterSlot(JSObject* getterFunc) + { + ASSERT(getterFunc); + m_getValue = functionGetter; + m_data.getterFunc = getterFunc; + } + + void setUndefined() + { + clearBase(); + setValue(jsUndefined()); + } + + JSValue slotBase() const + { + ASSERT(m_slotBase); + return m_slotBase; + } + + void setBase(JSValue base) + { + ASSERT(m_slotBase); + ASSERT(base); + m_slotBase = base; + } + + void clearBase() + { +#ifndef NDEBUG + m_slotBase = JSValue(); +#endif + } + + void clearValue() + { +#ifndef NDEBUG + m_value = JSValue(); +#endif + } + + unsigned index() const { return m_data.index; } + + private: + static JSValue functionGetter(ExecState*, const Identifier&, const PropertySlot&); + + GetValueFunc m_getValue; + + JSValue m_slotBase; + union { + JSObject* getterFunc; + JSValue* valueSlot; + Register* registerSlot; + unsigned index; + } m_data; + + JSValue m_value; + + size_t m_offset; + }; + +} // namespace JSC + +#endif // PropertySlot_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Protect.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Protect.h new file mode 100644 index 0000000..6e7984c --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Protect.h @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2004, 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 + * 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 Protect_h +#define Protect_h + +#include "JSCell.h" +#include "Collector.h" + +namespace JSC { + + inline void gcProtect(JSCell* val) + { + Heap::heap(val)->protect(val); + } + + inline void gcUnprotect(JSCell* val) + { + Heap::heap(val)->unprotect(val); + } + + inline void gcProtectNullTolerant(JSCell* val) + { + if (val) + gcProtect(val); + } + + inline void gcUnprotectNullTolerant(JSCell* val) + { + if (val) + gcUnprotect(val); + } + + inline void gcProtect(JSValue value) + { + if (value && value.isCell()) + gcProtect(asCell(value)); + } + + inline void gcUnprotect(JSValue value) + { + if (value && value.isCell()) + gcUnprotect(asCell(value)); + } + + // FIXME: Share more code with RefPtr template? The only differences are the ref/deref operation + // and the implicit conversion to raw pointer + template <class T> class ProtectedPtr { + public: + ProtectedPtr() : m_ptr(0) {} + ProtectedPtr(T* ptr); + ProtectedPtr(const ProtectedPtr&); + ~ProtectedPtr(); + + template <class U> ProtectedPtr(const ProtectedPtr<U>&); + + T* get() const { return m_ptr; } + operator T*() const { return m_ptr; } + operator JSValue() const { return JSValue(m_ptr); } + T* operator->() const { return m_ptr; } + + operator bool() const { return m_ptr; } + bool operator!() const { return !m_ptr; } + + ProtectedPtr& operator=(const ProtectedPtr&); + ProtectedPtr& operator=(T*); + + private: + T* m_ptr; + }; + + class ProtectedJSValue { + public: + ProtectedJSValue() {} + ProtectedJSValue(JSValue value); + ProtectedJSValue(const ProtectedJSValue&); + ~ProtectedJSValue(); + + template <class U> ProtectedJSValue(const ProtectedPtr<U>&); + + JSValue get() const { return m_value; } + operator JSValue() const { return m_value; } + //JSValue operator->() const { return m_value; } + + operator bool() const { return m_value; } + bool operator!() const { return !m_value; } + + ProtectedJSValue& operator=(const ProtectedJSValue&); + ProtectedJSValue& operator=(JSValue); + + private: + JSValue m_value; + }; + + template <class T> inline ProtectedPtr<T>::ProtectedPtr(T* ptr) + : m_ptr(ptr) + { + gcProtectNullTolerant(m_ptr); + } + + template <class T> inline ProtectedPtr<T>::ProtectedPtr(const ProtectedPtr& o) + : m_ptr(o.get()) + { + gcProtectNullTolerant(m_ptr); + } + + template <class T> inline ProtectedPtr<T>::~ProtectedPtr() + { + gcUnprotectNullTolerant(m_ptr); + } + + template <class T> template <class U> inline ProtectedPtr<T>::ProtectedPtr(const ProtectedPtr<U>& o) + : m_ptr(o.get()) + { + gcProtectNullTolerant(m_ptr); + } + + template <class T> inline ProtectedPtr<T>& ProtectedPtr<T>::operator=(const ProtectedPtr<T>& o) + { + T* optr = o.m_ptr; + gcProtectNullTolerant(optr); + gcUnprotectNullTolerant(m_ptr); + m_ptr = optr; + return *this; + } + + template <class T> inline ProtectedPtr<T>& ProtectedPtr<T>::operator=(T* optr) + { + gcProtectNullTolerant(optr); + gcUnprotectNullTolerant(m_ptr); + m_ptr = optr; + return *this; + } + + inline ProtectedJSValue::ProtectedJSValue(JSValue value) + : m_value(value) + { + gcProtect(m_value); + } + + inline ProtectedJSValue::ProtectedJSValue(const ProtectedJSValue& o) + : m_value(o.get()) + { + gcProtect(m_value); + } + + inline ProtectedJSValue::~ProtectedJSValue() + { + gcUnprotect(m_value); + } + + template <class U> ProtectedJSValue::ProtectedJSValue(const ProtectedPtr<U>& o) + : m_value(o.get()) + { + gcProtect(m_value); + } + + inline ProtectedJSValue& ProtectedJSValue::operator=(const ProtectedJSValue& o) + { + JSValue ovalue = o.m_value; + gcProtect(ovalue); + gcUnprotect(m_value); + m_value = ovalue; + return *this; + } + + inline ProtectedJSValue& ProtectedJSValue::operator=(JSValue ovalue) + { + gcProtect(ovalue); + gcUnprotect(m_value); + m_value = ovalue; + return *this; + } + + template <class T> inline bool operator==(const ProtectedPtr<T>& a, const ProtectedPtr<T>& b) { return a.get() == b.get(); } + template <class T> inline bool operator==(const ProtectedPtr<T>& a, const T* b) { return a.get() == b; } + template <class T> inline bool operator==(const T* a, const ProtectedPtr<T>& b) { return a == b.get(); } + + template <class T> inline bool operator!=(const ProtectedPtr<T>& a, const ProtectedPtr<T>& b) { return a.get() != b.get(); } + template <class T> inline bool operator!=(const ProtectedPtr<T>& a, const T* b) { return a.get() != b; } + template <class T> inline bool operator!=(const T* a, const ProtectedPtr<T>& b) { return a != b.get(); } + + inline bool operator==(const ProtectedJSValue& a, const ProtectedJSValue& b) { return a.get() == b.get(); } + inline bool operator==(const ProtectedJSValue& a, const JSValue b) { return a.get() == b; } + template <class T> inline bool operator==(const ProtectedJSValue& a, const ProtectedPtr<T>& b) { return a.get() == JSValue(b.get()); } + inline bool operator==(const JSValue a, const ProtectedJSValue& b) { return a == b.get(); } + template <class T> inline bool operator==(const ProtectedPtr<T>& a, const ProtectedJSValue& b) { return JSValue(a.get()) == b.get(); } + + inline bool operator!=(const ProtectedJSValue& a, const ProtectedJSValue& b) { return a.get() != b.get(); } + inline bool operator!=(const ProtectedJSValue& a, const JSValue b) { return a.get() != b; } + template <class T> inline bool operator!=(const ProtectedJSValue& a, const ProtectedPtr<T>& b) { return a.get() != JSValue(b.get()); } + inline bool operator!=(const JSValue a, const ProtectedJSValue& b) { return a != b.get(); } + template <class T> inline bool operator!=(const ProtectedPtr<T>& a, const ProtectedJSValue& b) { return JSValue(a.get()) != b.get(); } + +} // namespace JSC + +#endif // Protect_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PrototypeFunction.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PrototypeFunction.cpp new file mode 100644 index 0000000..8e3d107 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PrototypeFunction.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) + * Copyright (C) 2007 Maks Orlovich + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "PrototypeFunction.h" + +#include "JSGlobalObject.h" +#include <wtf/Assertions.h> + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(PrototypeFunction); + +PrototypeFunction::PrototypeFunction(ExecState* exec, int length, const Identifier& name, NativeFunction function) + : InternalFunction(&exec->globalData(), exec->lexicalGlobalObject()->prototypeFunctionStructure(), name) + , m_function(function) +{ + ASSERT_ARG(function, function); + putDirect(exec->propertyNames().length, jsNumber(exec, length), DontDelete | ReadOnly | DontEnum); +} + +PrototypeFunction::PrototypeFunction(ExecState* exec, PassRefPtr<Structure> prototypeFunctionStructure, int length, const Identifier& name, NativeFunction function) + : InternalFunction(&exec->globalData(), prototypeFunctionStructure, name) + , m_function(function) +{ + ASSERT_ARG(function, function); + putDirect(exec->propertyNames().length, jsNumber(exec, length), DontDelete | ReadOnly | DontEnum); +} + +CallType PrototypeFunction::getCallData(CallData& callData) +{ + callData.native.function = m_function; + return CallTypeHost; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PrototypeFunction.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PrototypeFunction.h new file mode 100644 index 0000000..99ab327 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PrototypeFunction.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) + * Copyright (C) 2007 Maks Orlovich + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef PrototypeFunction_h +#define PrototypeFunction_h + +#include "InternalFunction.h" +#include "CallData.h" + +namespace JSC { + + class PrototypeFunction : public InternalFunction { + public: + PrototypeFunction(ExecState*, int length, const Identifier&, NativeFunction); + PrototypeFunction(ExecState*, PassRefPtr<Structure>, int length, const Identifier&, NativeFunction); + + private: + virtual CallType getCallData(CallData&); + + const NativeFunction m_function; + }; + +} // namespace JSC + +#endif // PrototypeFunction_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PutPropertySlot.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PutPropertySlot.h new file mode 100644 index 0000000..eb8ea8a --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PutPropertySlot.h @@ -0,0 +1,77 @@ +// -*- mode: c++; c-basic-offset: 4 -*- +/* + * 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 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 PutPropertySlot_h +#define PutPropertySlot_h + +#include <wtf/Assertions.h> + +namespace JSC { + + class JSObject; + class JSFunction; + + class PutPropertySlot { + public: + enum Type { Uncachable, ExistingProperty, NewProperty }; + + PutPropertySlot() + : m_type(Uncachable) + , m_base(0) + { + } + + void setExistingProperty(JSObject* base, size_t offset) + { + m_type = ExistingProperty; + m_base = base; + m_offset = offset; + } + + void setNewProperty(JSObject* base, size_t offset) + { + m_type = NewProperty; + m_base = base; + m_offset = offset; + } + + Type type() const { return m_type; } + JSObject* base() const { return m_base; } + + bool isCacheable() const { return m_type != Uncachable; } + size_t cachedOffset() const { + ASSERT(isCacheable()); + return m_offset; + } + private: + Type m_type; + JSObject* m_base; + size_t m_offset; + }; + +} // namespace JSC + +#endif // PutPropertySlot_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExp.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExp.cpp new file mode 100644 index 0000000..b366b58 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExp.cpp @@ -0,0 +1,283 @@ +/* + * Copyright (C) 1999-2001, 2004 Harri Porten (porten@kde.org) + * Copyright (c) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Torch Mobile, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "RegExp.h" +#include "Lexer.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wtf/Assertions.h> +#include <wtf/OwnArrayPtr.h> + + +#if ENABLE(YARR) + +#include "yarr/RegexCompiler.h" +#if ENABLE(YARR_JIT) +#include "yarr/RegexJIT.h" +#else +#include "yarr/RegexInterpreter.h" +#endif + +#else + +#if ENABLE(WREC) +#include "JIT.h" +#include "WRECGenerator.h" +#endif +#include <pcre/pcre.h> + +#endif + +namespace JSC { + +#if ENABLE(WREC) +using namespace WREC; +#endif + +inline RegExp::RegExp(JSGlobalData* globalData, const UString& pattern) + : m_pattern(pattern) + , m_flagBits(0) + , m_constructionError(0) + , m_numSubpatterns(0) +{ + compile(globalData); +} + +inline RegExp::RegExp(JSGlobalData* globalData, const UString& pattern, const UString& flags) + : m_pattern(pattern) + , m_flags(flags) + , m_flagBits(0) + , m_constructionError(0) + , m_numSubpatterns(0) +{ + // NOTE: The global flag is handled on a case-by-case basis by functions like + // String::match and RegExpObject::match. +#ifndef QT_BUILD_SCRIPT_LIB + if (flags.find('g') != -1) + m_flagBits |= Global; + if (flags.find('i') != -1) + m_flagBits |= IgnoreCase; + if (flags.find('m') != -1) + m_flagBits |= Multiline; +#else //Invalid flags should throw a SyntaxError (ECMA Script 15.10.4.1) + static const char flagError[] = "invalid regular expression flag"; + for (int i = 0; i < flags.size(); i++) { + switch (flags.data()[i]) { + case 'g': + m_flagBits |= Global; + break; + case 'i': + m_flagBits |= IgnoreCase; + break; + case 'm': + m_flagBits |= Multiline; + break; + default: + m_constructionError = flagError; +#if !ENABLE(YARR) + m_regExp = 0; +#endif + return; + } + } +#endif + + compile(globalData); +} + +#if !ENABLE(YARR) +RegExp::~RegExp() +{ + jsRegExpFree(m_regExp); +} +#endif + +PassRefPtr<RegExp> RegExp::create(JSGlobalData* globalData, const UString& pattern) +{ + return adoptRef(new RegExp(globalData, pattern)); +} + +PassRefPtr<RegExp> RegExp::create(JSGlobalData* globalData, const UString& pattern, const UString& flags) +{ + return adoptRef(new RegExp(globalData, pattern, flags)); +} + +#if ENABLE(YARR) + +void RegExp::compile(JSGlobalData* globalData) +{ +#if ENABLE(YARR_JIT) + Yarr::jitCompileRegex(globalData, m_regExpJITCode, m_pattern, m_numSubpatterns, m_constructionError, ignoreCase(), multiline()); +#else + UNUSED_PARAM(globalData); + m_regExpBytecode.set(Yarr::byteCompileRegex(m_pattern, m_numSubpatterns, m_constructionError, ignoreCase(), multiline())); +#endif +} + +int RegExp::match(const UString& s, int startOffset, Vector<int, 32>* ovector) +{ + if (startOffset < 0) + startOffset = 0; + if (ovector) + ovector->clear(); + + if (startOffset > s.size() || s.isNull()) + return -1; + +#if ENABLE(YARR_JIT) + if (!!m_regExpJITCode) { +#else + if (m_regExpBytecode) { +#endif + int offsetVectorSize = (m_numSubpatterns + 1) * 3; // FIXME: should be 2 - but adding temporary fallback to pcre. + int* offsetVector; + Vector<int, 32> nonReturnedOvector; + if (ovector) { + ovector->resize(offsetVectorSize); + offsetVector = ovector->data(); + } else { + nonReturnedOvector.resize(offsetVectorSize); + offsetVector = nonReturnedOvector.data(); + } + + ASSERT(offsetVector); + for (int j = 0; j < offsetVectorSize; ++j) + offsetVector[j] = -1; + + +#if ENABLE(YARR_JIT) + int result = Yarr::executeRegex(m_regExpJITCode, s.data(), startOffset, s.size(), offsetVector, offsetVectorSize); +#else + int result = Yarr::interpretRegex(m_regExpBytecode.get(), s.data(), startOffset, s.size(), offsetVector); +#endif + + if (result < 0) { +#ifndef NDEBUG + // TODO: define up a symbol, rather than magic -1 + if (result != -1) + fprintf(stderr, "jsRegExpExecute failed with result %d\n", result); +#endif + if (ovector) + ovector->clear(); + } + return result; + } + + return -1; +} + +#else + +void RegExp::compile(JSGlobalData* globalData) +{ + m_regExp = 0; +#if ENABLE(WREC) + m_wrecFunction = Generator::compileRegExp(globalData, m_pattern, &m_numSubpatterns, &m_constructionError, m_executablePool, ignoreCase(), multiline()); + if (m_wrecFunction || m_constructionError) + return; + // Fall through to non-WREC case. +#else + UNUSED_PARAM(globalData); +#endif + + JSRegExpIgnoreCaseOption ignoreCaseOption = ignoreCase() ? JSRegExpIgnoreCase : JSRegExpDoNotIgnoreCase; + JSRegExpMultilineOption multilineOption = multiline() ? JSRegExpMultiline : JSRegExpSingleLine; + m_regExp = jsRegExpCompile(reinterpret_cast<const UChar*>(m_pattern.data()), m_pattern.size(), ignoreCaseOption, multilineOption, &m_numSubpatterns, &m_constructionError); +} + +int RegExp::match(const UString& s, int startOffset, Vector<int, 32>* ovector) +{ + if (startOffset < 0) + startOffset = 0; + if (ovector) + ovector->clear(); + + if (startOffset > s.size() || s.isNull()) + return -1; + +#if ENABLE(WREC) + if (m_wrecFunction) { + int offsetVectorSize = (m_numSubpatterns + 1) * 2; + int* offsetVector; + Vector<int, 32> nonReturnedOvector; + if (ovector) { + ovector->resize(offsetVectorSize); + offsetVector = ovector->data(); + } else { + nonReturnedOvector.resize(offsetVectorSize); + offsetVector = nonReturnedOvector.data(); + } + ASSERT(offsetVector); + for (int j = 0; j < offsetVectorSize; ++j) + offsetVector[j] = -1; + + int result = m_wrecFunction(s.data(), startOffset, s.size(), offsetVector); + + if (result < 0) { +#ifndef NDEBUG + // TODO: define up a symbol, rather than magic -1 + if (result != -1) + fprintf(stderr, "jsRegExpExecute failed with result %d\n", result); +#endif + if (ovector) + ovector->clear(); + } + return result; + } else +#endif + if (m_regExp) { + // Set up the offset vector for the result. + // First 2/3 used for result, the last third used by PCRE. + int* offsetVector; + int offsetVectorSize; + int fixedSizeOffsetVector[3]; + if (!ovector) { + offsetVectorSize = 3; + offsetVector = fixedSizeOffsetVector; + } else { + offsetVectorSize = (m_numSubpatterns + 1) * 3; + ovector->resize(offsetVectorSize); + offsetVector = ovector->data(); + } + + int numMatches = jsRegExpExecute(m_regExp, reinterpret_cast<const UChar*>(s.data()), s.size(), startOffset, offsetVector, offsetVectorSize); + + if (numMatches < 0) { +#ifndef NDEBUG + if (numMatches != JSRegExpErrorNoMatch) + fprintf(stderr, "jsRegExpExecute failed with result %d\n", numMatches); +#endif + if (ovector) + ovector->clear(); + return -1; + } + + return offsetVector[0]; + } + + return -1; +} + +#endif + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExp.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExp.h new file mode 100644 index 0000000..24d4199 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExp.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Torch Mobile, Inc. + * + * 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 RegExp_h +#define RegExp_h + +#include "UString.h" +#include "WREC.h" +#include "ExecutableAllocator.h" +#include <wtf/Forward.h> +#include <wtf/RefCounted.h> +#include "yarr/RegexJIT.h" +#include "yarr/RegexInterpreter.h" + +struct JSRegExp; + +namespace JSC { + + class JSGlobalData; + + class RegExp : public RefCounted<RegExp> { + public: + static PassRefPtr<RegExp> create(JSGlobalData* globalData, const UString& pattern); + static PassRefPtr<RegExp> create(JSGlobalData* globalData, const UString& pattern, const UString& flags); +#if !ENABLE(YARR) + ~RegExp(); +#endif + + bool global() const { return m_flagBits & Global; } + bool ignoreCase() const { return m_flagBits & IgnoreCase; } + bool multiline() const { return m_flagBits & Multiline; } + + const UString& pattern() const { return m_pattern; } + const UString& flags() const { return m_flags; } + + bool isValid() const { return !m_constructionError; } + const char* errorMessage() const { return m_constructionError; } + + int match(const UString&, int startOffset, Vector<int, 32>* ovector = 0); + unsigned numSubpatterns() const { return m_numSubpatterns; } + + private: + RegExp(JSGlobalData* globalData, const UString& pattern); + RegExp(JSGlobalData* globalData, const UString& pattern, const UString& flags); + + void compile(JSGlobalData*); + + enum FlagBits { Global = 1, IgnoreCase = 2, Multiline = 4 }; + + UString m_pattern; // FIXME: Just decompile m_regExp instead of storing this. + UString m_flags; // FIXME: Just decompile m_regExp instead of storing this. + int m_flagBits; + const char* m_constructionError; + unsigned m_numSubpatterns; + +#if ENABLE(YARR_JIT) + Yarr::RegexCodeBlock m_regExpJITCode; +#elif ENABLE(YARR) + OwnPtr<Yarr::BytecodePattern> m_regExpBytecode; +#else +#if ENABLE(WREC) + WREC::CompiledRegExp m_wrecFunction; + RefPtr<ExecutablePool> m_executablePool; +#endif + JSRegExp* m_regExp; +#endif + }; + +} // namespace JSC + +#endif // RegExp_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpConstructor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpConstructor.cpp new file mode 100644 index 0000000..e468521 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpConstructor.cpp @@ -0,0 +1,392 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 2007, 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2009 Torch Mobile, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "RegExpConstructor.h" + +#include "ArrayPrototype.h" +#include "JSArray.h" +#include "JSFunction.h" +#include "JSString.h" +#include "ObjectPrototype.h" +#include "RegExpMatchesArray.h" +#include "RegExpObject.h" +#include "RegExpPrototype.h" +#include "RegExp.h" + +namespace JSC { + +static JSValue regExpConstructorInput(ExecState*, const Identifier&, const PropertySlot&); +static JSValue regExpConstructorMultiline(ExecState*, const Identifier&, const PropertySlot&); +static JSValue regExpConstructorLastMatch(ExecState*, const Identifier&, const PropertySlot&); +static JSValue regExpConstructorLastParen(ExecState*, const Identifier&, const PropertySlot&); +static JSValue regExpConstructorLeftContext(ExecState*, const Identifier&, const PropertySlot&); +static JSValue regExpConstructorRightContext(ExecState*, const Identifier&, const PropertySlot&); +static JSValue regExpConstructorDollar1(ExecState*, const Identifier&, const PropertySlot&); +static JSValue regExpConstructorDollar2(ExecState*, const Identifier&, const PropertySlot&); +static JSValue regExpConstructorDollar3(ExecState*, const Identifier&, const PropertySlot&); +static JSValue regExpConstructorDollar4(ExecState*, const Identifier&, const PropertySlot&); +static JSValue regExpConstructorDollar5(ExecState*, const Identifier&, const PropertySlot&); +static JSValue regExpConstructorDollar6(ExecState*, const Identifier&, const PropertySlot&); +static JSValue regExpConstructorDollar7(ExecState*, const Identifier&, const PropertySlot&); +static JSValue regExpConstructorDollar8(ExecState*, const Identifier&, const PropertySlot&); +static JSValue regExpConstructorDollar9(ExecState*, const Identifier&, const PropertySlot&); + +static void setRegExpConstructorInput(ExecState*, JSObject*, JSValue); +static void setRegExpConstructorMultiline(ExecState*, JSObject*, JSValue); + +} // namespace JSC + +#include "RegExpConstructor.lut.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(RegExpConstructor); + +const ClassInfo RegExpConstructor::info = { "Function", &InternalFunction::info, 0, ExecState::regExpConstructorTable }; + +/* Source for RegExpConstructor.lut.h +@begin regExpConstructorTable + input regExpConstructorInput None + $_ regExpConstructorInput DontEnum + multiline regExpConstructorMultiline None + $* regExpConstructorMultiline DontEnum + lastMatch regExpConstructorLastMatch DontDelete|ReadOnly + $& regExpConstructorLastMatch DontDelete|ReadOnly|DontEnum + lastParen regExpConstructorLastParen DontDelete|ReadOnly + $+ regExpConstructorLastParen DontDelete|ReadOnly|DontEnum + leftContext regExpConstructorLeftContext DontDelete|ReadOnly + $` regExpConstructorLeftContext DontDelete|ReadOnly|DontEnum + rightContext regExpConstructorRightContext DontDelete|ReadOnly + $' regExpConstructorRightContext DontDelete|ReadOnly|DontEnum + $1 regExpConstructorDollar1 DontDelete|ReadOnly + $2 regExpConstructorDollar2 DontDelete|ReadOnly + $3 regExpConstructorDollar3 DontDelete|ReadOnly + $4 regExpConstructorDollar4 DontDelete|ReadOnly + $5 regExpConstructorDollar5 DontDelete|ReadOnly + $6 regExpConstructorDollar6 DontDelete|ReadOnly + $7 regExpConstructorDollar7 DontDelete|ReadOnly + $8 regExpConstructorDollar8 DontDelete|ReadOnly + $9 regExpConstructorDollar9 DontDelete|ReadOnly +@end +*/ + +struct RegExpConstructorPrivate { + // Global search cache / settings + RegExpConstructorPrivate() + : lastNumSubPatterns(0) + , multiline(false) + , lastOvectorIndex(0) + { + } + + const Vector<int, 32>& lastOvector() const { return ovector[lastOvectorIndex]; } + Vector<int, 32>& lastOvector() { return ovector[lastOvectorIndex]; } + Vector<int, 32>& tempOvector() { return ovector[lastOvectorIndex ? 0 : 1]; } + void changeLastOvector() { lastOvectorIndex = lastOvectorIndex ? 0 : 1; } + + UString input; + UString lastInput; + Vector<int, 32> ovector[2]; + unsigned lastNumSubPatterns : 30; + bool multiline : 1; + unsigned lastOvectorIndex : 1; +}; + +RegExpConstructor::RegExpConstructor(ExecState* exec, PassRefPtr<Structure> structure, RegExpPrototype* regExpPrototype) + : InternalFunction(&exec->globalData(), structure, Identifier(exec, "RegExp")) + , d(new RegExpConstructorPrivate) +{ + // ECMA 15.10.5.1 RegExp.prototype + putDirectWithoutTransition(exec->propertyNames().prototype, regExpPrototype, DontEnum | DontDelete | ReadOnly); + + // no. of arguments for constructor + putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 2), ReadOnly | DontDelete | DontEnum); +} + +/* + 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. +*/ +void RegExpConstructor::performMatch(RegExp* r, const UString& s, int startOffset, int& position, int& length, int** ovector) +{ + position = r->match(s, startOffset, &d->tempOvector()); + + if (ovector) + *ovector = d->tempOvector().data(); + + if (position != -1) { + ASSERT(!d->tempOvector().isEmpty()); + + length = d->tempOvector()[1] - d->tempOvector()[0]; + + d->input = s; + d->lastInput = s; + d->changeLastOvector(); + d->lastNumSubPatterns = r->numSubpatterns(); + } +} + +RegExpMatchesArray::RegExpMatchesArray(ExecState* exec, RegExpConstructorPrivate* data) + : JSArray(exec->lexicalGlobalObject()->regExpMatchesArrayStructure(), data->lastNumSubPatterns + 1) +{ + RegExpConstructorPrivate* d = new RegExpConstructorPrivate; + d->input = data->lastInput; + d->lastInput = data->lastInput; + d->lastNumSubPatterns = data->lastNumSubPatterns; + unsigned offsetVectorSize = (data->lastNumSubPatterns + 1) * 2; // only copying the result part of the vector + d->lastOvector().resize(offsetVectorSize); + memcpy(d->lastOvector().data(), data->lastOvector().data(), offsetVectorSize * sizeof(int)); + // d->multiline is not needed, and remains uninitialized + + setLazyCreationData(d); +} + +RegExpMatchesArray::~RegExpMatchesArray() +{ + delete static_cast<RegExpConstructorPrivate*>(lazyCreationData()); +} + +void RegExpMatchesArray::fillArrayInstance(ExecState* exec) +{ + RegExpConstructorPrivate* d = static_cast<RegExpConstructorPrivate*>(lazyCreationData()); + ASSERT(d); + + unsigned lastNumSubpatterns = d->lastNumSubPatterns; + + for (unsigned i = 0; i <= lastNumSubpatterns; ++i) { + int start = d->lastOvector()[2 * i]; + if (start >= 0) + JSArray::put(exec, i, jsSubstring(exec, d->lastInput, start, d->lastOvector()[2 * i + 1] - start)); + } + + PutPropertySlot slot; + JSArray::put(exec, exec->propertyNames().index, jsNumber(exec, d->lastOvector()[0]), slot); + JSArray::put(exec, exec->propertyNames().input, jsString(exec, d->input), slot); + + delete d; + setLazyCreationData(0); +} + +JSObject* RegExpConstructor::arrayOfMatches(ExecState* exec) const +{ + return new (exec) RegExpMatchesArray(exec, d.get()); +} + +JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i) const +{ + if (!d->lastOvector().isEmpty() && i <= d->lastNumSubPatterns) { + int start = d->lastOvector()[2 * i]; + if (start >= 0) + return jsSubstring(exec, d->lastInput, start, d->lastOvector()[2 * i + 1] - start); + } + return jsEmptyString(exec); +} + +JSValue RegExpConstructor::getLastParen(ExecState* exec) const +{ + unsigned i = d->lastNumSubPatterns; + if (i > 0) { + ASSERT(!d->lastOvector().isEmpty()); + int start = d->lastOvector()[2 * i]; + if (start >= 0) + return jsSubstring(exec, d->lastInput, start, d->lastOvector()[2 * i + 1] - start); + } + return jsEmptyString(exec); +} + +JSValue RegExpConstructor::getLeftContext(ExecState* exec) const +{ + if (!d->lastOvector().isEmpty()) + return jsSubstring(exec, d->lastInput, 0, d->lastOvector()[0]); + return jsEmptyString(exec); +} + +JSValue RegExpConstructor::getRightContext(ExecState* exec) const +{ + if (!d->lastOvector().isEmpty()) + return jsSubstring(exec, d->lastInput, d->lastOvector()[1], d->lastInput.size() - d->lastOvector()[1]); + return jsEmptyString(exec); +} + +bool RegExpConstructor::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +{ + return getStaticValueSlot<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec), this, propertyName, slot); +} + +JSValue regExpConstructorDollar1(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + return asRegExpConstructor(slot.slotBase())->getBackref(exec, 1); +} + +JSValue regExpConstructorDollar2(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + return asRegExpConstructor(slot.slotBase())->getBackref(exec, 2); +} + +JSValue regExpConstructorDollar3(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + return asRegExpConstructor(slot.slotBase())->getBackref(exec, 3); +} + +JSValue regExpConstructorDollar4(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + return asRegExpConstructor(slot.slotBase())->getBackref(exec, 4); +} + +JSValue regExpConstructorDollar5(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + return asRegExpConstructor(slot.slotBase())->getBackref(exec, 5); +} + +JSValue regExpConstructorDollar6(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + return asRegExpConstructor(slot.slotBase())->getBackref(exec, 6); +} + +JSValue regExpConstructorDollar7(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + return asRegExpConstructor(slot.slotBase())->getBackref(exec, 7); +} + +JSValue regExpConstructorDollar8(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + return asRegExpConstructor(slot.slotBase())->getBackref(exec, 8); +} + +JSValue regExpConstructorDollar9(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + return asRegExpConstructor(slot.slotBase())->getBackref(exec, 9); +} + +JSValue regExpConstructorInput(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + return jsString(exec, asRegExpConstructor(slot.slotBase())->input()); +} + +JSValue regExpConstructorMultiline(ExecState*, const Identifier&, const PropertySlot& slot) +{ + return jsBoolean(asRegExpConstructor(slot.slotBase())->multiline()); +} + +JSValue regExpConstructorLastMatch(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + return asRegExpConstructor(slot.slotBase())->getBackref(exec, 0); +} + +JSValue regExpConstructorLastParen(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + return asRegExpConstructor(slot.slotBase())->getLastParen(exec); +} + +JSValue regExpConstructorLeftContext(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + return asRegExpConstructor(slot.slotBase())->getLeftContext(exec); +} + +JSValue regExpConstructorRightContext(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + return asRegExpConstructor(slot.slotBase())->getRightContext(exec); +} + +void RegExpConstructor::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) +{ + lookupPut<RegExpConstructor, InternalFunction>(exec, propertyName, value, ExecState::regExpConstructorTable(exec), this, slot); +} + +void setRegExpConstructorInput(ExecState* exec, JSObject* baseObject, JSValue value) +{ + asRegExpConstructor(baseObject)->setInput(value.toString(exec)); +} + +void setRegExpConstructorMultiline(ExecState* exec, JSObject* baseObject, JSValue value) +{ + asRegExpConstructor(baseObject)->setMultiline(value.toBoolean(exec)); +} + +// ECMA 15.10.4 +JSObject* constructRegExp(ExecState* exec, const ArgList& args) +{ + JSValue arg0 = args.at(0); + JSValue arg1 = args.at(1); + + if (arg0.isObject(&RegExpObject::info)) { + if (!arg1.isUndefined()) + return throwError(exec, TypeError, "Cannot supply flags when constructing one RegExp from another."); + return asObject(arg0); + } + + UString pattern = arg0.isUndefined() ? UString("") : arg0.toString(exec); + UString flags = arg1.isUndefined() ? UString("") : arg1.toString(exec); + + RefPtr<RegExp> regExp = RegExp::create(&exec->globalData(), pattern, flags); + if (!regExp->isValid()) + return throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(regExp->errorMessage())); + return new (exec) RegExpObject(exec->lexicalGlobalObject()->regExpStructure(), regExp.release()); +} + +static JSObject* constructWithRegExpConstructor(ExecState* exec, JSObject*, const ArgList& args) +{ + return constructRegExp(exec, args); +} + +ConstructType RegExpConstructor::getConstructData(ConstructData& constructData) +{ + constructData.native.function = constructWithRegExpConstructor; + return ConstructTypeHost; +} + +// ECMA 15.10.3 +static JSValue JSC_HOST_CALL callRegExpConstructor(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + return constructRegExp(exec, args); +} + +CallType RegExpConstructor::getCallData(CallData& callData) +{ + callData.native.function = callRegExpConstructor; + return CallTypeHost; +} + +void RegExpConstructor::setInput(const UString& input) +{ + d->input = input; +} + +const UString& RegExpConstructor::input() const +{ + // Can detect a distinct initial state that is invisible to JavaScript, by checking for null + // state (since jsString turns null strings to empty strings). + return d->input; +} + +void RegExpConstructor::setMultiline(bool multiline) +{ + d->multiline = multiline; +} + +bool RegExpConstructor::multiline() const +{ + return d->multiline; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpConstructor.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpConstructor.h new file mode 100644 index 0000000..6823f3f --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpConstructor.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 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 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 RegExpConstructor_h +#define RegExpConstructor_h + +#include "InternalFunction.h" +#include <wtf/OwnPtr.h> + +namespace JSC { + + class RegExp; + class RegExpPrototype; + struct RegExpConstructorPrivate; + + class RegExpConstructor : public InternalFunction { + public: + RegExpConstructor(ExecState*, PassRefPtr<Structure>, RegExpPrototype*); + + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType, ImplementsHasInstance)); + } + + virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); + virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); + + static const ClassInfo info; + + void performMatch(RegExp*, const UString&, int startOffset, int& position, int& length, int** ovector = 0); + JSObject* arrayOfMatches(ExecState*) const; + + void setInput(const UString&); + const UString& input() const; + + void setMultiline(bool); + bool multiline() const; + + JSValue getBackref(ExecState*, unsigned) const; + JSValue getLastParen(ExecState*) const; + JSValue getLeftContext(ExecState*) const; + JSValue getRightContext(ExecState*) const; + + private: + virtual ConstructType getConstructData(ConstructData&); + virtual CallType getCallData(CallData&); + + virtual const ClassInfo* classInfo() const { return &info; } + + OwnPtr<RegExpConstructorPrivate> d; + }; + + RegExpConstructor* asRegExpConstructor(JSValue); + + JSObject* constructRegExp(ExecState*, const ArgList&); + + inline RegExpConstructor* asRegExpConstructor(JSValue value) + { + ASSERT(asObject(value)->inherits(&RegExpConstructor::info)); + return static_cast<RegExpConstructor*>(asObject(value)); + } + +} // namespace JSC + +#endif // RegExpConstructor_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpMatchesArray.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpMatchesArray.h new file mode 100644 index 0000000..cbba85a --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpMatchesArray.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 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 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 RegExpMatchesArray_h +#define RegExpMatchesArray_h + +#include "JSArray.h" + +namespace JSC { + + class RegExpMatchesArray : public JSArray { + public: + RegExpMatchesArray(ExecState*, RegExpConstructorPrivate*); + virtual ~RegExpMatchesArray(); + + private: + virtual bool getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) + { + if (lazyCreationData()) + fillArrayInstance(exec); + return JSArray::getOwnPropertySlot(exec, propertyName, slot); + } + + virtual bool getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) + { + if (lazyCreationData()) + fillArrayInstance(exec); + return JSArray::getOwnPropertySlot(exec, propertyName, slot); + } + + virtual void put(ExecState* exec, const Identifier& propertyName, JSValue v, PutPropertySlot& slot) + { + if (lazyCreationData()) + fillArrayInstance(exec); + JSArray::put(exec, propertyName, v, slot); + } + + virtual void put(ExecState* exec, unsigned propertyName, JSValue v) + { + if (lazyCreationData()) + fillArrayInstance(exec); + JSArray::put(exec, propertyName, v); + } + + virtual bool deleteProperty(ExecState* exec, const Identifier& propertyName, bool checkDontDelete = true) + { + if (lazyCreationData()) + fillArrayInstance(exec); + return JSArray::deleteProperty(exec, propertyName, checkDontDelete); + } + + virtual bool deleteProperty(ExecState* exec, unsigned propertyName, bool checkDontDelete = true) + { + if (lazyCreationData()) + fillArrayInstance(exec); + return JSArray::deleteProperty(exec, propertyName, checkDontDelete); + } + + virtual void getPropertyNames(ExecState* exec, PropertyNameArray& arr, unsigned listedAttributes) + { + if (lazyCreationData()) + fillArrayInstance(exec); + JSArray::getPropertyNames(exec, arr, listedAttributes); + } + + void fillArrayInstance(ExecState*); +}; + +} + +#endif // RegExpMatchesArray_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpObject.cpp new file mode 100644 index 0000000..687844e --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpObject.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "RegExpObject.h" + +#include "Error.h" +#include "JSArray.h" +#include "JSGlobalObject.h" +#include "JSString.h" +#include "RegExpConstructor.h" +#include "RegExpPrototype.h" + +namespace JSC { + +static JSValue regExpObjectGlobal(ExecState*, const Identifier&, const PropertySlot&); +static JSValue regExpObjectIgnoreCase(ExecState*, const Identifier&, const PropertySlot&); +static JSValue regExpObjectMultiline(ExecState*, const Identifier&, const PropertySlot&); +static JSValue regExpObjectSource(ExecState*, const Identifier&, const PropertySlot&); +static JSValue regExpObjectLastIndex(ExecState*, const Identifier&, const PropertySlot&); +static void setRegExpObjectLastIndex(ExecState*, JSObject*, JSValue); + +} // namespace JSC + +#include "RegExpObject.lut.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(RegExpObject); + +const ClassInfo RegExpObject::info = { "RegExp", 0, 0, ExecState::regExpTable }; + +/* 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 + lastIndex regExpObjectLastIndex DontDelete|DontEnum +@end +*/ + +RegExpObject::RegExpObject(PassRefPtr<Structure> structure, PassRefPtr<RegExp> regExp) + : JSObject(structure) + , d(new RegExpObjectData(regExp, 0)) +{ +} + +RegExpObject::~RegExpObject() +{ +} + +bool RegExpObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +{ + return getStaticValueSlot<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), this, propertyName, slot); +} + +JSValue regExpObjectGlobal(ExecState*, const Identifier&, const PropertySlot& slot) +{ + return jsBoolean(asRegExpObject(slot.slotBase())->regExp()->global()); +} + +JSValue regExpObjectIgnoreCase(ExecState*, const Identifier&, const PropertySlot& slot) +{ + return jsBoolean(asRegExpObject(slot.slotBase())->regExp()->ignoreCase()); +} + +JSValue regExpObjectMultiline(ExecState*, const Identifier&, const PropertySlot& slot) +{ + return jsBoolean(asRegExpObject(slot.slotBase())->regExp()->multiline()); +} + +JSValue regExpObjectSource(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + return jsString(exec, asRegExpObject(slot.slotBase())->regExp()->pattern()); +} + +JSValue regExpObjectLastIndex(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + return jsNumber(exec, asRegExpObject(slot.slotBase())->lastIndex()); +} + +void RegExpObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) +{ + lookupPut<RegExpObject, JSObject>(exec, propertyName, value, ExecState::regExpTable(exec), this, slot); +} + +void setRegExpObjectLastIndex(ExecState* exec, JSObject* baseObject, JSValue value) +{ + asRegExpObject(baseObject)->setLastIndex(value.toInteger(exec)); +} + +JSValue RegExpObject::test(ExecState* exec, const ArgList& args) +{ + return jsBoolean(match(exec, args)); +} + +JSValue RegExpObject::exec(ExecState* exec, const ArgList& args) +{ + if (match(exec, args)) + return exec->lexicalGlobalObject()->regExpConstructor()->arrayOfMatches(exec); + return jsNull(); +} + +static JSValue JSC_HOST_CALL callRegExpObject(ExecState* exec, JSObject* function, JSValue, const ArgList& args) +{ + return asRegExpObject(function)->exec(exec, args); +} + +CallType RegExpObject::getCallData(CallData& callData) +{ + callData.native.function = callRegExpObject; + return CallTypeHost; +} + +// Shared implementation used by test and exec. +bool RegExpObject::match(ExecState* exec, const ArgList& args) +{ + RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); + + UString input = args.isEmpty() ? regExpConstructor->input() : args.at(0).toString(exec); + if (input.isNull()) { + throwError(exec, GeneralError, "No input to " + toString(exec) + "."); + return false; + } + + if (!regExp()->global()) { + int position; + int length; + regExpConstructor->performMatch(d->regExp.get(), input, 0, position, length); + return position >= 0; + } + + if (d->lastIndex < 0 || d->lastIndex > input.size()) { + d->lastIndex = 0; + return false; + } + + int position; + int length; + regExpConstructor->performMatch(d->regExp.get(), input, static_cast<int>(d->lastIndex), position, length); + if (position < 0) { + d->lastIndex = 0; + return false; + } + + d->lastIndex = position + length; + return true; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpObject.h new file mode 100644 index 0000000..fac9978 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpObject.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 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 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 RegExpObject_h +#define RegExpObject_h + +#include "JSObject.h" +#include "RegExp.h" + +namespace JSC { + + class RegExpObject : public JSObject { + public: + RegExpObject(PassRefPtr<Structure>, PassRefPtr<RegExp>); + virtual ~RegExpObject(); + + void setRegExp(PassRefPtr<RegExp> r) { d->regExp = r; } + RegExp* regExp() const { return d->regExp.get(); } + + void setLastIndex(double lastIndex) { d->lastIndex = lastIndex; } + double lastIndex() const { return d->lastIndex; } + + JSValue test(ExecState*, const ArgList&); + JSValue exec(ExecState*, const ArgList&); + + virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); + virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); + + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType)); + } + + private: + bool match(ExecState*, const ArgList&); + + virtual CallType getCallData(CallData&); + + struct RegExpObjectData { + RegExpObjectData(PassRefPtr<RegExp> regExp, double lastIndex) + : regExp(regExp) + , lastIndex(lastIndex) + { + } + + RefPtr<RegExp> regExp; + double lastIndex; + }; + + OwnPtr<RegExpObjectData> d; + }; + + 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/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpPrototype.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpPrototype.cpp new file mode 100644 index 0000000..e507016 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpPrototype.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "RegExpPrototype.h" + +#include "ArrayPrototype.h" +#include "JSArray.h" +#include "JSFunction.h" +#include "JSObject.h" +#include "JSString.h" +#include "JSValue.h" +#include "ObjectPrototype.h" +#include "PrototypeFunction.h" +#include "RegExpObject.h" +#include "RegExp.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(RegExpPrototype); + +static JSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&); + +// ECMA 15.10.5 + +const ClassInfo RegExpPrototype::info = { "RegExpPrototype", 0, 0, 0 }; + +RegExpPrototype::RegExpPrototype(ExecState* exec, PassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) + : JSObject(structure) +{ + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().compile, regExpProtoFuncCompile), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().exec, regExpProtoFuncExec), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().test, regExpProtoFuncTest), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().toString, regExpProtoFuncToString), DontEnum); +} + +// ------------------------------ Functions --------------------------- + +JSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + if (!thisValue.isObject(&RegExpObject::info)) + return throwError(exec, TypeError); + return asRegExpObject(thisValue)->test(exec, args); +} + +JSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + if (!thisValue.isObject(&RegExpObject::info)) + return throwError(exec, TypeError); + return asRegExpObject(thisValue)->exec(exec, args); +} + +JSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + if (!thisValue.isObject(&RegExpObject::info)) + return throwError(exec, TypeError); + + RefPtr<RegExp> regExp; + JSValue arg0 = args.at(0); + JSValue arg1 = args.at(1); + + if (arg0.isObject(&RegExpObject::info)) { + if (!arg1.isUndefined()) + return throwError(exec, TypeError, "Cannot supply flags when constructing one RegExp from another."); + regExp = asRegExpObject(arg0)->regExp(); + } else { + UString pattern = args.isEmpty() ? UString("") : arg0.toString(exec); + UString flags = arg1.isUndefined() ? UString("") : arg1.toString(exec); + regExp = RegExp::create(&exec->globalData(), pattern, flags); + } + + if (!regExp->isValid()) + return throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(regExp->errorMessage())); + + asRegExpObject(thisValue)->setRegExp(regExp.release()); + asRegExpObject(thisValue)->setLastIndex(0); + return jsUndefined(); +} + +JSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&RegExpObject::info)) { + if (thisValue.isObject(&RegExpPrototype::info)) + return jsNontrivialString(exec, "//"); + return throwError(exec, TypeError); + } + + UString result = "/" + asRegExpObject(thisValue)->get(exec, exec->propertyNames().source).toString(exec); +#ifdef QT_BUILD_SCRIPT_LIB + if (result.size() == 1) + result.append("(?:)"); +#endif + result.append('/'); + if (asRegExpObject(thisValue)->get(exec, exec->propertyNames().global).toBoolean(exec)) + result.append('g'); + if (asRegExpObject(thisValue)->get(exec, exec->propertyNames().ignoreCase).toBoolean(exec)) + result.append('i'); + if (asRegExpObject(thisValue)->get(exec, exec->propertyNames().multiline).toBoolean(exec)) + result.append('m'); + return jsNontrivialString(exec, result); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpPrototype.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpPrototype.h new file mode 100644 index 0000000..f5db720 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpPrototype.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 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 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 RegExpPrototype_h +#define RegExpPrototype_h + +#include "JSObject.h" + +namespace JSC { + + class RegExpPrototype : public JSObject { + public: + RegExpPrototype(ExecState*, PassRefPtr<Structure>, Structure* prototypeFunctionStructure); + + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + }; + +} // namespace JSC + +#endif // RegExpPrototype_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ScopeChain.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ScopeChain.cpp new file mode 100644 index 0000000..5c2edab --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ScopeChain.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2003, 2006, 2008 Apple Inc. + * + * 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 "ScopeChain.h" + +#include "JSActivation.h" +#include "JSGlobalObject.h" +#include "JSObject.h" +#include "PropertyNameArray.h" +#include <stdio.h> + +namespace JSC { + +#ifndef NDEBUG + +void ScopeChainNode::print() const +{ + ScopeChainIterator scopeEnd = end(); + for (ScopeChainIterator scopeIter = begin(); scopeIter != scopeEnd; ++scopeIter) { + JSObject* o = *scopeIter; + PropertyNameArray propertyNames(globalObject()->globalExec()); + o->getPropertyNames(globalObject()->globalExec(), propertyNames); + PropertyNameArray::const_iterator propEnd = propertyNames.end(); + + fprintf(stderr, "----- [scope %p] -----\n", o); + for (PropertyNameArray::const_iterator propIter = propertyNames.begin(); propIter != propEnd; propIter++) { + Identifier name = *propIter; + fprintf(stderr, "%s, ", name.ascii()); + } + fprintf(stderr, "\n"); + } +} + +#endif + +int ScopeChain::localDepth() const +{ + int scopeDepth = 0; + ScopeChainIterator iter = this->begin(); + ScopeChainIterator end = this->end(); + while (!(*iter)->isObject(&JSActivation::info)) { + ++iter; + if (iter == end) + break; + ++scopeDepth; + } + return scopeDepth; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ScopeChain.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ScopeChain.h new file mode 100644 index 0000000..17aff24 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ScopeChain.h @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2003, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef ScopeChain_h +#define ScopeChain_h + +#include "FastAllocBase.h" + +namespace JSC { + + class JSGlobalData; + class JSGlobalObject; + class JSObject; + class ScopeChainIterator; + + class ScopeChainNode : public FastAllocBase { + public: + ScopeChainNode(ScopeChainNode* next, JSObject* object, JSGlobalData* globalData, JSObject* globalThis) + : next(next) + , object(object) + , globalData(globalData) + , globalThis(globalThis) + , refCount(1) + { + ASSERT(globalData); + } +#ifndef NDEBUG + // Due to the number of subtle and timing dependent bugs that have occurred due + // to deleted but still "valid" ScopeChainNodes we now deliberately clobber the + // contents in debug builds. + ~ScopeChainNode() + { + next = 0; + object = 0; + globalData = 0; + globalThis = 0; + } +#endif + + ScopeChainNode* next; + JSObject* object; + JSGlobalData* globalData; + JSObject* globalThis; + int refCount; + + void deref() { ASSERT(refCount); if (--refCount == 0) { release();} } + void ref() { ASSERT(refCount); ++refCount; } + void release(); + + // Before calling "push" on a bare ScopeChainNode, a client should + // logically "copy" the node. Later, the client can "deref" the head + // of its chain of ScopeChainNodes to reclaim all the nodes it added + // after the logical copy, leaving nodes added before the logical copy + // (nodes shared with other clients) untouched. + ScopeChainNode* copy() + { + ref(); + return this; + } + + ScopeChainNode* push(JSObject*); + ScopeChainNode* pop(); + + ScopeChainIterator begin() const; + ScopeChainIterator end() const; + + JSGlobalObject* globalObject() const; // defined in JSGlobalObject.h + JSObject* globalThisObject() const { return globalThis; } + +#ifndef NDEBUG + void print() const; +#endif + }; + + inline ScopeChainNode* ScopeChainNode::push(JSObject* o) + { + ASSERT(o); + return new ScopeChainNode(this, o, globalData, globalThis); + } + + inline ScopeChainNode* ScopeChainNode::pop() + { + ASSERT(next); + ScopeChainNode* result = next; + + if (--refCount != 0) + ++result->refCount; + else + delete this; + + return result; + } + + inline void ScopeChainNode::release() + { + // This function is only called by deref(), + // Deref ensures these conditions are true. + ASSERT(refCount == 0); + ScopeChainNode* n = this; + do { + ScopeChainNode* next = n->next; + delete n; + n = next; + } while (n && --n->refCount == 0); + } + + class ScopeChainIterator { + public: + ScopeChainIterator(const ScopeChainNode* node) + : m_node(node) + { + } + + JSObject* const & operator*() const { return m_node->object; } + JSObject* const * operator->() const { return &(operator*()); } + + ScopeChainIterator& operator++() { m_node = m_node->next; return *this; } + + // postfix ++ intentionally omitted + + bool operator==(const ScopeChainIterator& other) const { return m_node == other.m_node; } + bool operator!=(const ScopeChainIterator& other) const { return m_node != other.m_node; } + + private: + const ScopeChainNode* m_node; + }; + + inline ScopeChainIterator ScopeChainNode::begin() const + { + return ScopeChainIterator(this); + } + + inline ScopeChainIterator ScopeChainNode::end() const + { + return ScopeChainIterator(0); + } + + class NoScopeChain {}; + + class ScopeChain { + friend class JIT; + public: + ScopeChain(NoScopeChain) + : m_node(0) + { + } + + ScopeChain(JSObject* o, JSGlobalData* globalData, JSObject* globalThis) + : m_node(new ScopeChainNode(0, o, globalData, globalThis)) + { + } + + ScopeChain(const ScopeChain& c) + : m_node(c.m_node->copy()) + { + } + + ScopeChain& operator=(const ScopeChain& c); + + explicit ScopeChain(ScopeChainNode* node) + : m_node(node->copy()) + { + } + + ~ScopeChain() + { + if (m_node) + m_node->deref(); +#ifndef NDEBUG + m_node = 0; +#endif + } + + void swap(ScopeChain&); + + ScopeChainNode* node() const { return m_node; } + + JSObject* top() const { return m_node->object; } + + ScopeChainIterator begin() const { return m_node->begin(); } + ScopeChainIterator end() const { return m_node->end(); } + + void push(JSObject* o) { m_node = m_node->push(o); } + + void pop() { m_node = m_node->pop(); } + void clear() { m_node->deref(); m_node = 0; } + + JSGlobalObject* globalObject() const { return m_node->globalObject(); } + + void mark() const; + + // Caution: this should only be used if the codeblock this is being used + // with needs a full scope chain, otherwise this returns the depth of + // the preceeding call frame + // + // Returns the depth of the current call frame's scope chain + int localDepth() const; + +#ifndef NDEBUG + void print() const { m_node->print(); } +#endif + + private: + ScopeChainNode* m_node; + }; + + inline void ScopeChain::swap(ScopeChain& o) + { + ScopeChainNode* tmp = m_node; + m_node = o.m_node; + o.m_node = tmp; + } + + inline ScopeChain& ScopeChain::operator=(const ScopeChain& c) + { + ScopeChain tmp(c); + swap(tmp); + return *this; + } + +} // namespace JSC + +#endif // ScopeChain_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ScopeChainMark.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ScopeChainMark.h new file mode 100644 index 0000000..b80b8ef --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ScopeChainMark.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef ScopeChainMark_h +#define ScopeChainMark_h + +#include "ScopeChain.h" + +namespace JSC { + + inline void ScopeChain::mark() const + { + for (ScopeChainNode* n = m_node; n; n = n->next) { + JSObject* o = n->object; + if (!o->marked()) + o->mark(); + } + } + +} // namespace JSC + +#endif // ScopeChainMark_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/SmallStrings.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/SmallStrings.cpp new file mode 100644 index 0000000..9d1f01a --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/SmallStrings.cpp @@ -0,0 +1,128 @@ +/* + * 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. + */ + +#include "config.h" +#include "SmallStrings.h" + +#include "JSGlobalObject.h" +#include "JSString.h" + +#include <wtf/Noncopyable.h> + +namespace JSC { +static const unsigned numCharactersToStore = 0x100; + +class SmallStringsStorage : public Noncopyable { +public: + SmallStringsStorage(); + + UString::Rep* rep(unsigned char character) { return &m_reps[character]; } + +private: + UChar m_characters[numCharactersToStore]; + UString::BaseString m_base; + UString::Rep m_reps[numCharactersToStore]; +}; + +SmallStringsStorage::SmallStringsStorage() + : m_base(m_characters, numCharactersToStore) +{ + m_base.rc = numCharactersToStore + 1; + // make sure UString doesn't try to reuse the buffer by pretending we have one more character in it + m_base.usedCapacity = numCharactersToStore + 1; + m_base.capacity = numCharactersToStore + 1; + m_base.checkConsistency(); + + for (unsigned i = 0; i < numCharactersToStore; ++i) + m_characters[i] = i; + + memset(&m_reps, 0, sizeof(m_reps)); + for (unsigned i = 0; i < numCharactersToStore; ++i) { + m_reps[i].offset = i; + m_reps[i].len = 1; + m_reps[i].rc = 1; + m_reps[i].setBaseString(&m_base); + m_reps[i].checkConsistency(); + } +} + +SmallStrings::SmallStrings() + : m_emptyString(0) + , m_storage(0) +{ + COMPILE_ASSERT(numCharactersToStore == sizeof(m_singleCharacterStrings) / sizeof(m_singleCharacterStrings[0]), IsNumCharactersConstInSyncWithClassUsage); + + for (unsigned i = 0; i < numCharactersToStore; ++i) + m_singleCharacterStrings[i] = 0; +} + +SmallStrings::~SmallStrings() +{ +} + +void SmallStrings::mark() +{ + if (m_emptyString && !m_emptyString->marked()) + m_emptyString->mark(); + for (unsigned i = 0; i < numCharactersToStore; ++i) { + if (m_singleCharacterStrings[i] && !m_singleCharacterStrings[i]->marked()) + m_singleCharacterStrings[i]->mark(); + } +} + +unsigned SmallStrings::count() const +{ + unsigned count = 0; + if (m_emptyString) + ++count; + for (unsigned i = 0; i < numCharactersToStore; ++i) { + if (m_singleCharacterStrings[i]) + ++count; + } + return count; +} + +void SmallStrings::createEmptyString(JSGlobalData* globalData) +{ + ASSERT(!m_emptyString); + m_emptyString = new (globalData) JSString(globalData, "", JSString::HasOtherOwner); +} + +void SmallStrings::createSingleCharacterString(JSGlobalData* globalData, unsigned char character) +{ + if (!m_storage) + m_storage.set(new SmallStringsStorage); + ASSERT(!m_singleCharacterStrings[character]); + m_singleCharacterStrings[character] = new (globalData) JSString(globalData, m_storage->rep(character), JSString::HasOtherOwner); +} + +UString::Rep* SmallStrings::singleCharacterStringRep(unsigned char character) +{ + if (!m_storage) + m_storage.set(new SmallStringsStorage); + return m_storage->rep(character); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/SmallStrings.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/SmallStrings.h new file mode 100644 index 0000000..f0dd8df --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/SmallStrings.h @@ -0,0 +1,74 @@ +/* + * 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. + */ + +#ifndef SmallStrings_h +#define SmallStrings_h + +#include "UString.h" +#include <wtf/OwnPtr.h> + +namespace JSC { + + class JSGlobalData; + class JSString; + + class SmallStringsStorage; + + class SmallStrings : public Noncopyable { + public: + SmallStrings(); + ~SmallStrings(); + + JSString* emptyString(JSGlobalData* globalData) + { + if (!m_emptyString) + createEmptyString(globalData); + return m_emptyString; + } + JSString* singleCharacterString(JSGlobalData* globalData, unsigned char character) + { + if (!m_singleCharacterStrings[character]) + createSingleCharacterString(globalData, character); + return m_singleCharacterStrings[character]; + } + + UString::Rep* singleCharacterStringRep(unsigned char character); + + void mark(); + + unsigned count() const; + + private: + void createEmptyString(JSGlobalData*); + void createSingleCharacterString(JSGlobalData*, unsigned char); + + JSString* m_emptyString; + JSString* m_singleCharacterStrings[0x100]; + OwnPtr<SmallStringsStorage> m_storage; + }; + +} // namespace JSC + +#endif // SmallStrings_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringConstructor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringConstructor.cpp new file mode 100644 index 0000000..6380445 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringConstructor.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "StringConstructor.h" + +#include "JSFunction.h" +#include "JSGlobalObject.h" +#include "PrototypeFunction.h" +#include "StringPrototype.h" + +namespace JSC { + +static NEVER_INLINE JSValue stringFromCharCodeSlowCase(ExecState* exec, const ArgList& args) +{ + UChar* buf = static_cast<UChar*>(fastMalloc(args.size() * sizeof(UChar))); + UChar* p = buf; + ArgList::const_iterator end = args.end(); + for (ArgList::const_iterator it = args.begin(); it != end; ++it) + *p++ = static_cast<UChar>((*it).toUInt32(exec)); + return jsString(exec, UString(buf, p - buf, false)); +} + +static JSValue JSC_HOST_CALL stringFromCharCode(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + if (LIKELY(args.size() == 1)) + return jsSingleCharacterString(exec, args.at(0).toUInt32(exec)); + return stringFromCharCodeSlowCase(exec, args); +} + +ASSERT_CLASS_FITS_IN_CELL(StringConstructor); + +StringConstructor::StringConstructor(ExecState* exec, PassRefPtr<Structure> structure, Structure* prototypeFunctionStructure, StringPrototype* stringPrototype) + : InternalFunction(&exec->globalData(), structure, Identifier(exec, stringPrototype->classInfo()->className)) +{ + // ECMA 15.5.3.1 String.prototype + putDirectWithoutTransition(exec->propertyNames().prototype, stringPrototype, ReadOnly | DontEnum | DontDelete); + + // ECMA 15.5.3.2 fromCharCode() + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().fromCharCode, stringFromCharCode), DontEnum); + + // no. of arguments for constructor + putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 1), ReadOnly | DontEnum | DontDelete); +} + +// ECMA 15.5.2 +static JSObject* constructWithStringConstructor(ExecState* exec, JSObject*, const ArgList& args) +{ + if (args.isEmpty()) + return new (exec) StringObject(exec, exec->lexicalGlobalObject()->stringObjectStructure()); + return new (exec) StringObject(exec, exec->lexicalGlobalObject()->stringObjectStructure(), args.at(0).toString(exec)); +} + +ConstructType StringConstructor::getConstructData(ConstructData& constructData) +{ + constructData.native.function = constructWithStringConstructor; + return ConstructTypeHost; +} + +// ECMA 15.5.1 +static JSValue JSC_HOST_CALL callStringConstructor(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + if (args.isEmpty()) + return jsEmptyString(exec); + return jsString(exec, args.at(0).toString(exec)); +} + +CallType StringConstructor::getCallData(CallData& callData) +{ + callData.native.function = callStringConstructor; + return CallTypeHost; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringConstructor.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringConstructor.h new file mode 100644 index 0000000..7d52c69 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringConstructor.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 StringConstructor_h +#define StringConstructor_h + +#include "InternalFunction.h" + +namespace JSC { + + class StringPrototype; + + class StringConstructor : public InternalFunction { + public: + StringConstructor(ExecState*, PassRefPtr<Structure>, Structure* prototypeFunctionStructure, StringPrototype*); + + virtual ConstructType getConstructData(ConstructData&); + virtual CallType getCallData(CallData&); + }; + +} // namespace JSC + +#endif // StringConstructor_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringObject.cpp new file mode 100644 index 0000000..4745a98 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringObject.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "StringObject.h" + +#include "PropertyNameArray.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(StringObject); + +const ClassInfo StringObject::info = { "String", 0, 0, 0 }; + +StringObject::StringObject(ExecState* exec, PassRefPtr<Structure> structure) + : JSWrapperObject(structure) +{ + setInternalValue(jsEmptyString(exec)); +} + +StringObject::StringObject(PassRefPtr<Structure> structure, JSString* string) + : JSWrapperObject(structure) +{ + setInternalValue(string); +} + +StringObject::StringObject(ExecState* exec, PassRefPtr<Structure> structure, const UString& string) + : JSWrapperObject(structure) +{ + setInternalValue(jsString(exec, string)); +} + +bool StringObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +{ + if (internalValue()->getStringPropertySlot(exec, propertyName, slot)) + return true; + return JSObject::getOwnPropertySlot(exec, propertyName, slot); +} + +bool StringObject::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) +{ + if (internalValue()->getStringPropertySlot(exec, propertyName, slot)) + return true; + return JSObject::getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot); +} + +void StringObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) +{ + if (propertyName == exec->propertyNames().length) + return; + JSObject::put(exec, propertyName, value, slot); +} + +bool StringObject::deleteProperty(ExecState* exec, const Identifier& propertyName, bool checkDontDelete) +{ + if (propertyName == exec->propertyNames().length) + return false; + bool isStrictUInt32; + unsigned i = propertyName.toStrictUInt32(&isStrictUInt32); + if (isStrictUInt32 && internalValue()->canGetIndex(i)) + return false; + return JSObject::deleteProperty(exec, propertyName, checkDontDelete); +} + +void StringObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, unsigned listedAttributes) +{ + int size = internalValue()->value().size(); + for (int i = 0; i < size; ++i) + propertyNames.add(Identifier(exec, UString::from(i))); + return JSObject::getPropertyNames(exec, propertyNames, listedAttributes); +} + +bool StringObject::getPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const +{ + if (internalValue()->getStringPropertyAttributes(exec, propertyName, attributes)) + return true; + return JSObject::getPropertyAttributes(exec, propertyName, attributes); +} + +UString StringObject::toString(ExecState*) const +{ + return internalValue()->value(); +} + +UString StringObject::toThisString(ExecState*) const +{ + return internalValue()->value(); +} + +JSString* StringObject::toThisJSString(ExecState*) +{ + return internalValue(); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringObject.h new file mode 100644 index 0000000..fdeb2c1 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringObject.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 StringObject_h +#define StringObject_h + +#include "JSWrapperObject.h" +#include "JSString.h" + +namespace JSC { + + class StringObject : public JSWrapperObject { + public: + StringObject(ExecState*, PassRefPtr<Structure>); + StringObject(ExecState*, PassRefPtr<Structure>, const UString&); + + static StringObject* create(ExecState*, JSString*); + + virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); + virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); + + virtual void put(ExecState* exec, const Identifier& propertyName, JSValue, PutPropertySlot&); + virtual bool deleteProperty(ExecState*, const Identifier& propertyName, bool checkDontDelete = true); + virtual void getPropertyNames(ExecState*, PropertyNameArray&, unsigned listedAttributes = Structure::Prototype); + virtual bool getPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned& attributes) const; + + virtual const ClassInfo* classInfo() const { return &info; } + static const JS_EXPORTDATA ClassInfo info; + + JSString* internalValue() const { return asString(JSWrapperObject::internalValue());} + + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType)); + } + + protected: + StringObject(PassRefPtr<Structure>, JSString*); + + private: + virtual UString toString(ExecState*) const; + virtual UString toThisString(ExecState*) const; + virtual JSString* toThisJSString(ExecState*); + }; + + StringObject* asStringObject(JSValue); + + inline StringObject* asStringObject(JSValue value) + { + ASSERT(asObject(value)->inherits(&StringObject::info)); + return static_cast<StringObject*>(asObject(value)); + } + +} // namespace JSC + +#endif // StringObject_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h new file mode 100644 index 0000000..bc5c0a5 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 StringObjectThatMasqueradesAsUndefined_h +#define StringObjectThatMasqueradesAsUndefined_h + +#include "JSGlobalObject.h" +#include "StringObject.h" +#include "UString.h" + +namespace JSC { + + // WebCore uses this to make style.filter undetectable + class StringObjectThatMasqueradesAsUndefined : public StringObject { + public: + static StringObjectThatMasqueradesAsUndefined* create(ExecState* exec, const UString& string) + { + return new (exec) StringObjectThatMasqueradesAsUndefined(exec, + createStructure(exec->lexicalGlobalObject()->stringPrototype()), string); + } + + private: + StringObjectThatMasqueradesAsUndefined(ExecState* exec, PassRefPtr<Structure> structure, const UString& string) + : StringObject(exec, structure, string) + { + } + + static PassRefPtr<Structure> createStructure(JSValue proto) + { + return Structure::create(proto, TypeInfo(ObjectType, MasqueradesAsUndefined)); + } + + virtual bool toBoolean(ExecState*) const { return false; } + }; + +} // namespace JSC + +#endif // StringObjectThatMasqueradesAsUndefined_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringPrototype.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringPrototype.cpp new file mode 100644 index 0000000..ceb6b1e --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringPrototype.cpp @@ -0,0 +1,895 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Torch Mobile, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "StringPrototype.h" + +#include "CachedCall.h" +#include "JSArray.h" +#include "JSFunction.h" +#include "ObjectPrototype.h" +#include "PropertyNameArray.h" +#include "RegExpConstructor.h" +#include "RegExpObject.h" +#include <wtf/ASCIICType.h> +#include <wtf/MathExtras.h> +#include <wtf/unicode/Collator.h> + +using namespace WTF; + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(StringPrototype); + +static JSValue JSC_HOST_CALL stringProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState*, JSObject*, JSValue, const ArgList&); + +static JSValue JSC_HOST_CALL stringProtoFuncBig(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncBold(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncSub(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncSup(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncLink(ExecState*, JSObject*, JSValue, const ArgList&); + +} + +#include "StringPrototype.lut.h" + +namespace JSC { + +const ClassInfo StringPrototype::info = { "String", &StringObject::info, 0, ExecState::stringTable }; + +/* Source for StringPrototype.lut.h +@begin stringTable 26 + toString stringProtoFuncToString DontEnum|Function 0 + valueOf stringProtoFuncToString DontEnum|Function 0 + charAt stringProtoFuncCharAt DontEnum|Function 1 + charCodeAt stringProtoFuncCharCodeAt DontEnum|Function 1 + concat stringProtoFuncConcat DontEnum|Function 1 + indexOf stringProtoFuncIndexOf DontEnum|Function 1 + lastIndexOf stringProtoFuncLastIndexOf DontEnum|Function 1 + match stringProtoFuncMatch DontEnum|Function 1 + replace stringProtoFuncReplace DontEnum|Function 2 + search stringProtoFuncSearch DontEnum|Function 1 + slice stringProtoFuncSlice DontEnum|Function 2 + split stringProtoFuncSplit DontEnum|Function 2 + substr stringProtoFuncSubstr DontEnum|Function 2 + substring stringProtoFuncSubstring DontEnum|Function 2 + toLowerCase stringProtoFuncToLowerCase DontEnum|Function 0 + toUpperCase stringProtoFuncToUpperCase DontEnum|Function 0 + localeCompare stringProtoFuncLocaleCompare DontEnum|Function 1 + + # toLocaleLowerCase and toLocaleUpperCase are currently identical to toLowerCase and toUpperCase + toLocaleLowerCase stringProtoFuncToLowerCase DontEnum|Function 0 + toLocaleUpperCase stringProtoFuncToUpperCase DontEnum|Function 0 + + big stringProtoFuncBig DontEnum|Function 0 + small stringProtoFuncSmall DontEnum|Function 0 + blink stringProtoFuncBlink DontEnum|Function 0 + bold stringProtoFuncBold DontEnum|Function 0 + fixed stringProtoFuncFixed DontEnum|Function 0 + italics stringProtoFuncItalics DontEnum|Function 0 + strike stringProtoFuncStrike DontEnum|Function 0 + sub stringProtoFuncSub DontEnum|Function 0 + sup stringProtoFuncSup DontEnum|Function 0 + fontcolor stringProtoFuncFontcolor DontEnum|Function 1 + fontsize stringProtoFuncFontsize DontEnum|Function 1 + anchor stringProtoFuncAnchor DontEnum|Function 1 + link stringProtoFuncLink DontEnum|Function 1 +@end +*/ + +// ECMA 15.5.4 +StringPrototype::StringPrototype(ExecState* exec, PassRefPtr<Structure> structure) + : StringObject(exec, structure) +{ + // The constructor will be added later, after StringConstructor has been built + putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 0), DontDelete | ReadOnly | DontEnum); +} + +bool StringPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot &slot) +{ + return getStaticFunctionSlot<StringObject>(exec, ExecState::stringTable(exec), this, propertyName, slot); +} + +// ------------------------------ Functions -------------------------- + +static inline UString substituteBackreferences(const UString& replacement, const UString& source, const int* ovector, RegExp* reg) +{ + UString substitutedReplacement; + int offset = 0; + int i = -1; + while ((i = replacement.find('$', i + 1)) != -1) { + if (i + 1 == replacement.size()) + break; + + UChar ref = replacement[i + 1]; + if (ref == '$') { + // "$$" -> "$" + ++i; + substitutedReplacement.append(replacement.data() + offset, i - offset); + offset = i + 1; + continue; + } + + int backrefStart; + int backrefLength; + int advance = 0; + if (ref == '&') { + backrefStart = ovector[0]; + backrefLength = ovector[1] - backrefStart; + } else if (ref == '`') { + backrefStart = 0; + backrefLength = ovector[0]; + } else if (ref == '\'') { + backrefStart = ovector[1]; + backrefLength = source.size() - backrefStart; + } else if (reg && ref >= '0' && ref <= '9') { + // 1- and 2-digit back references are allowed + unsigned backrefIndex = ref - '0'; + if (backrefIndex > reg->numSubpatterns()) + continue; + if (replacement.size() > i + 2) { + ref = replacement[i + 2]; + if (ref >= '0' && ref <= '9') { + backrefIndex = 10 * backrefIndex + ref - '0'; + if (backrefIndex > reg->numSubpatterns()) + backrefIndex = backrefIndex / 10; // Fall back to the 1-digit reference + else + advance = 1; + } + } + if (!backrefIndex) + continue; + backrefStart = ovector[2 * backrefIndex]; + backrefLength = ovector[2 * backrefIndex + 1] - backrefStart; + } else + continue; + + if (i - offset) + substitutedReplacement.append(replacement.data() + offset, i - offset); + i += 1 + advance; + offset = i + 1; + substitutedReplacement.append(source.data() + backrefStart, backrefLength); + } + + if (!offset) + return replacement; + + if (replacement.size() - offset) + substitutedReplacement.append(replacement.data() + offset, replacement.size() - offset); + + return substitutedReplacement; +} + +static inline int localeCompare(const UString& a, const UString& b) +{ + return Collator::userDefault()->collate(reinterpret_cast<const ::UChar*>(a.data()), a.size(), reinterpret_cast<const ::UChar*>(b.data()), b.size()); +} + +JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + JSString* sourceVal = thisValue.toThisJSString(exec); + const UString& source = sourceVal->value(); + + JSValue pattern = args.at(0); + + JSValue replacement = args.at(1); + UString replacementString; + CallData callData; + CallType callType = replacement.getCallData(callData); + if (callType == CallTypeNone) + replacementString = replacement.toString(exec); + + if (pattern.isObject(&RegExpObject::info)) { + RegExp* reg = asRegExpObject(pattern)->regExp(); + bool global = reg->global(); + + RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); + + int lastIndex = 0; + int startPosition = 0; + + Vector<UString::Range, 16> sourceRanges; + Vector<UString, 16> replacements; + + // This is either a loop (if global is set) or a one-way (if not). + if (global && callType == CallTypeJS) { + // reg->numSubpatterns() + 1 for pattern args, + 2 for match start and sourceValue + int argCount = reg->numSubpatterns() + 1 + 2; + JSFunction* func = asFunction(replacement); + CachedCall cachedCall(exec, func, argCount, exec->exceptionSlot()); + if (exec->hadException()) + return jsNull(); + while (true) { + int matchIndex; + int matchLen; + int* ovector; + regExpConstructor->performMatch(reg, source, startPosition, matchIndex, matchLen, &ovector); + if (matchIndex < 0) + break; + + sourceRanges.append(UString::Range(lastIndex, matchIndex - lastIndex)); + + int completeMatchStart = ovector[0]; + unsigned i = 0; + for (; i < reg->numSubpatterns() + 1; ++i) { + int matchStart = ovector[i * 2]; + int matchLen = ovector[i * 2 + 1] - matchStart; + + if (matchStart < 0) + cachedCall.setArgument(i, jsUndefined()); + else + cachedCall.setArgument(i, jsSubstring(exec, source, matchStart, matchLen)); + } + + cachedCall.setArgument(i++, jsNumber(exec, completeMatchStart)); + cachedCall.setArgument(i++, sourceVal); + + cachedCall.setThis(exec->globalThisValue()); + replacements.append(cachedCall.call().toString(cachedCall.newCallFrame())); + if (exec->hadException()) + break; + + lastIndex = matchIndex + matchLen; + startPosition = lastIndex; + + // special case of empty match + if (matchLen == 0) { + startPosition++; + if (startPosition > source.size()) + break; + } + } + } else { + do { + int matchIndex; + int matchLen; + int* ovector; + regExpConstructor->performMatch(reg, source, startPosition, matchIndex, matchLen, &ovector); + if (matchIndex < 0) + break; + + sourceRanges.append(UString::Range(lastIndex, matchIndex - lastIndex)); + + if (callType != CallTypeNone) { + int completeMatchStart = ovector[0]; + MarkedArgumentBuffer args; + + for (unsigned i = 0; i < reg->numSubpatterns() + 1; ++i) { + int matchStart = ovector[i * 2]; + int matchLen = ovector[i * 2 + 1] - matchStart; + + if (matchStart < 0) + args.append(jsUndefined()); + else + args.append(jsSubstring(exec, source, matchStart, matchLen)); + } + + args.append(jsNumber(exec, completeMatchStart)); + args.append(sourceVal); + + replacements.append(call(exec, replacement, callType, callData, exec->globalThisValue(), args).toString(exec)); + if (exec->hadException()) + break; + } else + replacements.append(substituteBackreferences(replacementString, source, ovector, reg)); + + lastIndex = matchIndex + matchLen; + startPosition = lastIndex; + + // special case of empty match + if (matchLen == 0) { + startPosition++; + if (startPosition > source.size()) + break; + } + } while (global); + } + + if (!lastIndex && replacements.isEmpty()) + return sourceVal; + + if (lastIndex < source.size()) + sourceRanges.append(UString::Range(lastIndex, source.size() - lastIndex)); + + return jsString(exec, source.spliceSubstringsWithSeparators(sourceRanges.data(), sourceRanges.size(), + replacements.data(), replacements.size())); + } + + // Not a regular expression, so treat the pattern as a string. + + UString patternString = pattern.toString(exec); + int matchPos = source.find(patternString); + + if (matchPos == -1) + return sourceVal; + + int matchLen = patternString.size(); + if (callType != CallTypeNone) { + MarkedArgumentBuffer args; + args.append(jsSubstring(exec, source, matchPos, matchLen)); + args.append(jsNumber(exec, matchPos)); + args.append(sourceVal); + + replacementString = call(exec, replacement, callType, callData, exec->globalThisValue(), args).toString(exec); + } + + int ovector[2] = { matchPos, matchPos + matchLen }; + return jsString(exec, source.replaceRange(matchPos, matchLen, substituteBackreferences(replacementString, source, ovector, 0))); +} + +JSValue JSC_HOST_CALL stringProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + // Also used for valueOf. + + if (thisValue.isString()) + return thisValue; + + if (thisValue.isObject(&StringObject::info)) + return asStringObject(thisValue)->internalValue(); + + return throwError(exec, TypeError); +} + +JSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + UString s = thisValue.toThisString(exec); + unsigned len = s.size(); + JSValue a0 = args.at(0); + if (a0.isUInt32Fast()) { + uint32_t i = a0.getUInt32Fast(); + if (i < len) + return jsSingleCharacterSubstring(exec, s, i); + return jsEmptyString(exec); + } + double dpos = a0.toInteger(exec); + if (dpos >= 0 && dpos < len) + return jsSingleCharacterSubstring(exec, s, static_cast<unsigned>(dpos)); + return jsEmptyString(exec); +} + +JSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + UString s = thisValue.toThisString(exec); + unsigned len = s.size(); + JSValue a0 = args.at(0); + if (a0.isUInt32Fast()) { + uint32_t i = a0.getUInt32Fast(); + if (i < len) + return jsNumber(exec, s.data()[i]); + return jsNaN(exec); + } + double dpos = a0.toInteger(exec); + if (dpos >= 0 && dpos < len) + return jsNumber(exec, s[static_cast<int>(dpos)]); + return jsNaN(exec); +} + +JSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + UString s = thisValue.toThisString(exec); + + ArgList::const_iterator end = args.end(); + for (ArgList::const_iterator it = args.begin(); it != end; ++it) + s += (*it).toString(exec); + return jsString(exec, s); +} + +JSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + UString s = thisValue.toThisString(exec); + int len = s.size(); + + JSValue a0 = args.at(0); + JSValue a1 = args.at(1); + UString u2 = a0.toString(exec); + int pos; + if (a1.isUndefined()) + pos = 0; + else if (a1.isUInt32Fast()) + pos = min<uint32_t>(a1.getUInt32Fast(), len); + else { + double dpos = a1.toInteger(exec); + if (dpos < 0) + dpos = 0; + else if (dpos > len) + dpos = len; + pos = static_cast<int>(dpos); + } + + return jsNumber(exec, s.find(u2, pos)); +} + +JSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + UString s = thisValue.toThisString(exec); + int len = s.size(); + + JSValue a0 = args.at(0); + JSValue a1 = args.at(1); + + UString u2 = a0.toString(exec); + double dpos = a1.toIntegerPreserveNaN(exec); + if (dpos < 0) + dpos = 0; + else if (!(dpos <= len)) // true for NaN + dpos = len; + return jsNumber(exec, s.rfind(u2, static_cast<int>(dpos))); +} + +JSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + UString s = thisValue.toThisString(exec); + + JSValue a0 = args.at(0); + + UString u = s; + RefPtr<RegExp> reg; + RegExpObject* imp = 0; + if (a0.isObject(&RegExpObject::info)) + reg = asRegExpObject(a0)->regExp(); + else { + /* + * ECMA 15.5.4.12 String.prototype.search (regexp) + * If regexp is not an object whose [[Class]] property is "RegExp", it is + * replaced with the result of the expression new RegExp(regexp). + */ + reg = RegExp::create(&exec->globalData(), a0.toString(exec)); + } + RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); + int pos; + int matchLength; + regExpConstructor->performMatch(reg.get(), u, 0, pos, matchLength); + if (!(reg->global())) { + // case without 'g' flag is handled like RegExp.prototype.exec + if (pos < 0) + return jsNull(); + return regExpConstructor->arrayOfMatches(exec); + } + + // return array of matches + MarkedArgumentBuffer list; + int lastIndex = 0; + while (pos >= 0) { + list.append(jsSubstring(exec, u, pos, matchLength)); + lastIndex = pos; + pos += matchLength == 0 ? 1 : matchLength; + regExpConstructor->performMatch(reg.get(), u, pos, pos, matchLength); + } + if (imp) + imp->setLastIndex(lastIndex); + if (list.isEmpty()) { + // if there are no matches at all, it's important to return + // Null instead of an empty array, because this matches + // other browsers and because Null is a false value. + return jsNull(); + } + + return constructArray(exec, list); +} + +JSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + UString s = thisValue.toThisString(exec); + + JSValue a0 = args.at(0); + + UString u = s; + RefPtr<RegExp> reg; + if (a0.isObject(&RegExpObject::info)) + reg = asRegExpObject(a0)->regExp(); + else { + /* + * ECMA 15.5.4.12 String.prototype.search (regexp) + * If regexp is not an object whose [[Class]] property is "RegExp", it is + * replaced with the result of the expression new RegExp(regexp). + */ + reg = RegExp::create(&exec->globalData(), a0.toString(exec)); + } + RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); + int pos; + int matchLength; + regExpConstructor->performMatch(reg.get(), u, 0, pos, matchLength); + return jsNumber(exec, pos); +} + +JSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + UString s = thisValue.toThisString(exec); + int len = s.size(); + + JSValue a0 = args.at(0); + JSValue a1 = args.at(1); + + // The arg processing is very much like ArrayProtoFunc::Slice + double start = a0.toInteger(exec); + double end = a1.isUndefined() ? len : a1.toInteger(exec); + double from = start < 0 ? len + start : start; + double to = end < 0 ? len + end : end; + if (to > from && to > 0 && from < len) { + if (from < 0) + from = 0; + if (to > len) + to = len; + return jsSubstring(exec, s, static_cast<unsigned>(from), static_cast<unsigned>(to) - static_cast<unsigned>(from)); + } + + return jsEmptyString(exec); +} + +JSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + UString s = thisValue.toThisString(exec); + + JSValue a0 = args.at(0); + JSValue a1 = args.at(1); + + JSArray* result = constructEmptyArray(exec); + unsigned i = 0; + int p0 = 0; + unsigned limit = a1.isUndefined() ? 0xFFFFFFFFU : a1.toUInt32(exec); + if (a0.isObject(&RegExpObject::info)) { + RegExp* reg = asRegExpObject(a0)->regExp(); + if (s.isEmpty() && reg->match(s, 0) >= 0) { + // empty string matched by regexp -> empty array + return result; + } + int pos = 0; + while (i != limit && pos < s.size()) { + Vector<int, 32> ovector; + int mpos = reg->match(s, pos, &ovector); + if (mpos < 0) + break; + int mlen = ovector[1] - ovector[0]; + pos = mpos + (mlen == 0 ? 1 : mlen); + if (mpos != p0 || mlen) { + result->put(exec, i++, jsSubstring(exec, s, p0, mpos - p0)); + p0 = mpos + mlen; + } + for (unsigned si = 1; si <= reg->numSubpatterns(); ++si) { + int spos = ovector[si * 2]; + if (spos < 0) + result->put(exec, i++, jsUndefined()); + else + result->put(exec, i++, jsSubstring(exec, s, spos, ovector[si * 2 + 1] - spos)); + } + } + } else { + UString u2 = a0.toString(exec); + if (u2.isEmpty()) { + if (s.isEmpty()) { + // empty separator matches empty string -> empty array + return result; + } + while (i != limit && p0 < s.size() - 1) + result->put(exec, i++, jsSingleCharacterSubstring(exec, s, p0++)); + } else { + int pos; + while (i != limit && (pos = s.find(u2, p0)) >= 0) { + result->put(exec, i++, jsSubstring(exec, s, p0, pos - p0)); + p0 = pos + u2.size(); + } + } + } + + // add remaining string + if (i != limit) + result->put(exec, i++, jsSubstring(exec, s, p0, s.size() - p0)); + + return result; +} + +JSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + UString s = thisValue.toThisString(exec); + int len = s.size(); + + JSValue a0 = args.at(0); + JSValue a1 = args.at(1); + + double start = a0.toInteger(exec); + double length = a1.isUndefined() ? len : a1.toInteger(exec); + if (start >= len || length <= 0) + return jsEmptyString(exec); + if (start < 0) { + start += len; + if (start < 0) + start = 0; + } + if (start + length > len) + length = len - start; + return jsSubstring(exec, s, static_cast<unsigned>(start), static_cast<unsigned>(length)); +} + +JSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + UString s = thisValue.toThisString(exec); + int len = s.size(); + + JSValue a0 = args.at(0); + JSValue a1 = args.at(1); + + double start = a0.toNumber(exec); + double end = a1.toNumber(exec); + if (isnan(start)) + start = 0; + if (isnan(end)) + end = 0; + if (start < 0) + start = 0; + if (end < 0) + end = 0; + if (start > len) + start = len; + if (end > len) + end = len; + if (a1.isUndefined()) + end = len; + if (start > end) { + double temp = end; + end = start; + start = temp; + } + return jsSubstring(exec, s, static_cast<unsigned>(start), static_cast<unsigned>(end) - static_cast<unsigned>(start)); +} + +JSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + JSString* sVal = thisValue.toThisJSString(exec); + const UString& s = sVal->value(); + + int sSize = s.size(); + if (!sSize) + return sVal; + + const UChar* sData = s.data(); + Vector<UChar> buffer(sSize); + + UChar ored = 0; + for (int i = 0; i < sSize; i++) { + UChar c = sData[i]; + ored |= c; + buffer[i] = toASCIILower(c); + } + if (!(ored & ~0x7f)) + return jsString(exec, UString(buffer.releaseBuffer(), sSize, false)); + + bool error; + int length = Unicode::toLower(buffer.data(), sSize, sData, sSize, &error); + if (error) { + buffer.resize(length); + length = Unicode::toLower(buffer.data(), length, sData, sSize, &error); + if (error) + return sVal; + } + if (length == sSize && memcmp(buffer.data(), sData, length * sizeof(UChar)) == 0) + return sVal; + return jsString(exec, UString(buffer.releaseBuffer(), length, false)); +} + +JSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + JSString* sVal = thisValue.toThisJSString(exec); + const UString& s = sVal->value(); + + int sSize = s.size(); + if (!sSize) + return sVal; + + const UChar* sData = s.data(); + Vector<UChar> buffer(sSize); + + UChar ored = 0; + for (int i = 0; i < sSize; i++) { + UChar c = sData[i]; + ored |= c; + buffer[i] = toASCIIUpper(c); + } + if (!(ored & ~0x7f)) + return jsString(exec, UString(buffer.releaseBuffer(), sSize, false)); + + bool error; + int length = Unicode::toUpper(buffer.data(), sSize, sData, sSize, &error); + if (error) { + buffer.resize(length); + length = Unicode::toUpper(buffer.data(), length, sData, sSize, &error); + if (error) + return sVal; + } + if (length == sSize && memcmp(buffer.data(), sData, length * sizeof(UChar)) == 0) + return sVal; + return jsString(exec, UString(buffer.releaseBuffer(), length, false)); +} + +JSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + if (args.size() < 1) + return jsNumber(exec, 0); + + UString s = thisValue.toThisString(exec); + JSValue a0 = args.at(0); + return jsNumber(exec, localeCompare(s, a0.toString(exec))); +} + +JSValue JSC_HOST_CALL stringProtoFuncBig(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + UString s = thisValue.toThisString(exec); + return jsNontrivialString(exec, "<big>" + s + "</big>"); +} + +JSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + UString s = thisValue.toThisString(exec); + return jsNontrivialString(exec, "<small>" + s + "</small>"); +} + +JSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + UString s = thisValue.toThisString(exec); + return jsNontrivialString(exec, "<blink>" + s + "</blink>"); +} + +JSValue JSC_HOST_CALL stringProtoFuncBold(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + UString s = thisValue.toThisString(exec); + return jsNontrivialString(exec, "<b>" + s + "</b>"); +} + +JSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + UString s = thisValue.toThisString(exec); + return jsString(exec, "<tt>" + s + "</tt>"); +} + +JSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + UString s = thisValue.toThisString(exec); + return jsNontrivialString(exec, "<i>" + s + "</i>"); +} + +JSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + UString s = thisValue.toThisString(exec); + return jsNontrivialString(exec, "<strike>" + s + "</strike>"); +} + +JSValue JSC_HOST_CALL stringProtoFuncSub(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + UString s = thisValue.toThisString(exec); + return jsNontrivialString(exec, "<sub>" + s + "</sub>"); +} + +JSValue JSC_HOST_CALL stringProtoFuncSup(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + UString s = thisValue.toThisString(exec); + return jsNontrivialString(exec, "<sup>" + s + "</sup>"); +} + +JSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + UString s = thisValue.toThisString(exec); + JSValue a0 = args.at(0); + return jsNontrivialString(exec, "<font color=\"" + a0.toString(exec) + "\">" + s + "</font>"); +} + +JSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + UString s = thisValue.toThisString(exec); + JSValue a0 = args.at(0); + + uint32_t smallInteger; + if (a0.getUInt32(smallInteger) && smallInteger <= 9) { + unsigned stringSize = s.size(); + unsigned bufferSize = 22 + stringSize; + UChar* buffer = static_cast<UChar*>(tryFastMalloc(bufferSize * sizeof(UChar))); + if (!buffer) + return jsUndefined(); + buffer[0] = '<'; + buffer[1] = 'f'; + buffer[2] = 'o'; + buffer[3] = 'n'; + buffer[4] = 't'; + buffer[5] = ' '; + buffer[6] = 's'; + buffer[7] = 'i'; + buffer[8] = 'z'; + buffer[9] = 'e'; + buffer[10] = '='; + buffer[11] = '"'; + buffer[12] = '0' + smallInteger; + buffer[13] = '"'; + buffer[14] = '>'; + memcpy(&buffer[15], s.data(), stringSize * sizeof(UChar)); + buffer[15 + stringSize] = '<'; + buffer[16 + stringSize] = '/'; + buffer[17 + stringSize] = 'f'; + buffer[18 + stringSize] = 'o'; + buffer[19 + stringSize] = 'n'; + buffer[20 + stringSize] = 't'; + buffer[21 + stringSize] = '>'; + return jsNontrivialString(exec, UString(buffer, bufferSize, false)); + } + + return jsNontrivialString(exec, "<font size=\"" + a0.toString(exec) + "\">" + s + "</font>"); +} + +JSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + UString s = thisValue.toThisString(exec); + JSValue a0 = args.at(0); + return jsNontrivialString(exec, "<a name=\"" + a0.toString(exec) + "\">" + s + "</a>"); +} + +JSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) +{ + UString s = thisValue.toThisString(exec); + JSValue a0 = args.at(0); + UString linkText = a0.toString(exec); + + unsigned linkTextSize = linkText.size(); + unsigned stringSize = s.size(); + unsigned bufferSize = 15 + linkTextSize + stringSize; + UChar* buffer = static_cast<UChar*>(tryFastMalloc(bufferSize * sizeof(UChar))); + if (!buffer) + return jsUndefined(); + buffer[0] = '<'; + buffer[1] = 'a'; + buffer[2] = ' '; + buffer[3] = 'h'; + buffer[4] = 'r'; + buffer[5] = 'e'; + buffer[6] = 'f'; + buffer[7] = '='; + buffer[8] = '"'; + memcpy(&buffer[9], linkText.data(), linkTextSize * sizeof(UChar)); + buffer[9 + linkTextSize] = '"'; + buffer[10 + linkTextSize] = '>'; + memcpy(&buffer[11 + linkTextSize], s.data(), stringSize * sizeof(UChar)); + buffer[11 + linkTextSize + stringSize] = '<'; + buffer[12 + linkTextSize + stringSize] = '/'; + buffer[13 + linkTextSize + stringSize] = 'a'; + buffer[14 + linkTextSize + stringSize] = '>'; + return jsNontrivialString(exec, UString(buffer, bufferSize, false)); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringPrototype.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringPrototype.h new file mode 100644 index 0000000..6f5344e --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringPrototype.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 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 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 StringPrototype_h +#define StringPrototype_h + +#include "StringObject.h" + +namespace JSC { + + class ObjectPrototype; + + class StringPrototype : public StringObject { + public: + StringPrototype(ExecState*, PassRefPtr<Structure>); + + virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); + + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + }; + +} // namespace JSC + +#endif // StringPrototype_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Structure.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Structure.cpp new file mode 100644 index 0000000..38c086e --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Structure.cpp @@ -0,0 +1,1156 @@ +/* + * 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 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 "Structure.h" + +#include "Identifier.h" +#include "JSObject.h" +#include "PropertyNameArray.h" +#include "StructureChain.h" +#include "Lookup.h" +#include <wtf/RefCountedLeakCounter.h> +#include <wtf/RefPtr.h> + +#if ENABLE(JSC_MULTIPLE_THREADS) +#include <wtf/Threading.h> +#endif + +#define DUMP_STRUCTURE_ID_STATISTICS 0 + +#ifndef NDEBUG +#define DO_PROPERTYMAP_CONSTENCY_CHECK 0 +#else +#define DO_PROPERTYMAP_CONSTENCY_CHECK 0 +#endif + +using namespace std; +using namespace WTF; + +namespace JSC { + +// Choose a number for the following so that most property maps are smaller, +// but it's not going to blow out the stack to allocate this number of pointers. +static const int smallMapThreshold = 1024; + +// The point at which the function call overhead of the qsort implementation +// becomes small compared to the inefficiency of insertion sort. +static const unsigned tinyMapThreshold = 20; + +static const unsigned newTableSize = 16; + +#ifndef NDEBUG +static WTF::RefCountedLeakCounter structureCounter("Structure"); + +#if ENABLE(JSC_MULTIPLE_THREADS) +static Mutex& ignoreSetMutex = *(new Mutex); +#endif + +static bool shouldIgnoreLeaks; +static HashSet<Structure*>& ignoreSet = *(new HashSet<Structure*>); +#endif + +#if DUMP_STRUCTURE_ID_STATISTICS +static HashSet<Structure*>& liveStructureSet = *(new HashSet<Structure*>); +#endif + +void Structure::dumpStatistics() +{ +#if DUMP_STRUCTURE_ID_STATISTICS + unsigned numberLeaf = 0; + unsigned numberUsingSingleSlot = 0; + unsigned numberSingletons = 0; + unsigned numberWithPropertyMaps = 0; + unsigned totalPropertyMapsSize = 0; + + HashSet<Structure*>::const_iterator end = liveStructureSet.end(); + for (HashSet<Structure*>::const_iterator it = liveStructureSet.begin(); it != end; ++it) { + Structure* structure = *it; + if (structure->m_usingSingleTransitionSlot) { + if (!structure->m_transitions.singleTransition) + ++numberLeaf; + else + ++numberUsingSingleSlot; + + if (!structure->m_previous && !structure->m_transitions.singleTransition) + ++numberSingletons; + } + + if (structure->m_propertyTable) { + ++numberWithPropertyMaps; + totalPropertyMapsSize += PropertyMapHashTable::allocationSize(structure->m_propertyTable->size); + if (structure->m_propertyTable->deletedOffsets) + totalPropertyMapsSize += (structure->m_propertyTable->deletedOffsets->capacity() * sizeof(unsigned)); + } + } + + printf("Number of live Structures: %d\n", liveStructureSet.size()); + printf("Number of Structures using the single item optimization for transition map: %d\n", numberUsingSingleSlot); + printf("Number of Structures that are leaf nodes: %d\n", numberLeaf); + printf("Number of Structures that singletons: %d\n", numberSingletons); + printf("Number of Structures with PropertyMaps: %d\n", numberWithPropertyMaps); + + printf("Size of a single Structures: %d\n", static_cast<unsigned>(sizeof(Structure))); + printf("Size of sum of all property maps: %d\n", totalPropertyMapsSize); + printf("Size of average of all property maps: %f\n", static_cast<double>(totalPropertyMapsSize) / static_cast<double>(liveStructureSet.size())); +#else + printf("Dumping Structure statistics is not enabled.\n"); +#endif +} + +Structure::Structure(JSValue prototype, const TypeInfo& typeInfo) + : m_typeInfo(typeInfo) + , m_prototype(prototype) + , m_specificValueInPrevious(0) + , m_propertyTable(0) + , m_propertyStorageCapacity(JSObject::inlineStorageCapacity) + , m_offset(noOffset) + , m_isDictionary(false) + , m_isPinnedPropertyTable(false) + , m_hasGetterSetterProperties(false) + , m_usingSingleTransitionSlot(true) + , m_attributesInPrevious(0) +{ + ASSERT(m_prototype); + ASSERT(m_prototype.isObject() || m_prototype.isNull()); + + m_transitions.singleTransition = 0; + +#ifndef NDEBUG +#if ENABLE(JSC_MULTIPLE_THREADS) + MutexLocker protect(ignoreSetMutex); +#endif + if (shouldIgnoreLeaks) + ignoreSet.add(this); + else + structureCounter.increment(); +#endif + +#if DUMP_STRUCTURE_ID_STATISTICS + liveStructureSet.add(this); +#endif +} + +Structure::~Structure() +{ + if (m_previous) { + if (m_previous->m_usingSingleTransitionSlot) { + m_previous->m_transitions.singleTransition = 0; + } else { + ASSERT(m_previous->m_transitions.table->contains(make_pair(m_nameInPrevious.get(), make_pair(m_attributesInPrevious, m_specificValueInPrevious)))); + m_previous->m_transitions.table->remove(make_pair<RefPtr<UString::Rep>, std::pair<unsigned,JSCell*> >(m_nameInPrevious.get(), make_pair(m_attributesInPrevious, m_specificValueInPrevious))); + } + } + + if (m_cachedPropertyNameArrayData) + m_cachedPropertyNameArrayData->setCachedStructure(0); + + if (!m_usingSingleTransitionSlot) + delete m_transitions.table; + + if (m_propertyTable) { + unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; + for (unsigned i = 1; i <= entryCount; i++) { + if (UString::Rep* key = m_propertyTable->entries()[i].key) + key->deref(); + } + + delete m_propertyTable->deletedOffsets; + fastFree(m_propertyTable); + } + +#ifndef NDEBUG +#if ENABLE(JSC_MULTIPLE_THREADS) + MutexLocker protect(ignoreSetMutex); +#endif + HashSet<Structure*>::iterator it = ignoreSet.find(this); + if (it != ignoreSet.end()) + ignoreSet.remove(it); + else + structureCounter.decrement(); +#endif + +#if DUMP_STRUCTURE_ID_STATISTICS + liveStructureSet.remove(this); +#endif +} + +void Structure::startIgnoringLeaks() +{ +#ifndef NDEBUG + shouldIgnoreLeaks = true; +#endif +} + +void Structure::stopIgnoringLeaks() +{ +#ifndef NDEBUG + shouldIgnoreLeaks = false; +#endif +} + +static bool isPowerOf2(unsigned v) +{ + // Taken from http://www.cs.utk.edu/~vose/c-stuff/bithacks.html + + return !(v & (v - 1)) && v; +} + +static unsigned nextPowerOf2(unsigned v) +{ + // Taken from http://www.cs.utk.edu/~vose/c-stuff/bithacks.html + // Devised by Sean Anderson, Sepember 14, 2001 + + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + + return v; +} + +static unsigned sizeForKeyCount(size_t keyCount) +{ + if (keyCount == notFound) + return newTableSize; + + if (keyCount < 8) + return newTableSize; + + if (isPowerOf2(keyCount)) + return keyCount * 4; + + return nextPowerOf2(keyCount) * 2; +} + +void Structure::materializePropertyMap() +{ + ASSERT(!m_propertyTable); + + Vector<Structure*, 8> structures; + structures.append(this); + + Structure* structure = this; + + // Search for the last Structure with a property table. + while ((structure = structure->previousID())) { + if (structure->m_isPinnedPropertyTable) { + ASSERT(structure->m_propertyTable); + ASSERT(!structure->m_previous); + + m_propertyTable = structure->copyPropertyTable(); + break; + } + + structures.append(structure); + } + + if (!m_propertyTable) + createPropertyMapHashTable(sizeForKeyCount(m_offset + 1)); + else { + if (sizeForKeyCount(m_offset + 1) > m_propertyTable->size) + rehashPropertyMapHashTable(sizeForKeyCount(m_offset + 1)); // This could be made more efficient by combining with the copy above. + } + + for (ptrdiff_t i = structures.size() - 2; i >= 0; --i) { + structure = structures[i]; + structure->m_nameInPrevious->ref(); + PropertyMapEntry entry(structure->m_nameInPrevious.get(), structure->m_offset, structure->m_attributesInPrevious, structure->m_specificValueInPrevious, ++m_propertyTable->lastIndexUsed); + insertIntoPropertyMapHashTable(entry); + } +} + +void Structure::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, JSObject* baseObject, unsigned listedAttributes) +{ + bool shouldCache = propertyNames.shouldCache() && !(propertyNames.size() || m_isDictionary) && (listedAttributes & Prototype); + + if (shouldCache && m_cachedPropertyNameArrayData) { + if (m_cachedPropertyNameArrayData->cachedPrototypeChain() == prototypeChain(exec)) { + propertyNames.setData(m_cachedPropertyNameArrayData); + return; + } + clearEnumerationCache(); + } + bool includeNonEnumerable = false; + if (listedAttributes & NonEnumerable) + includeNonEnumerable = true; + getNamesFromPropertyTable(propertyNames, includeNonEnumerable); + getNamesFromClassInfoTable(exec, baseObject->classInfo(), propertyNames, includeNonEnumerable); + + if ((listedAttributes & Prototype) && m_prototype.isObject()) { + propertyNames.setShouldCache(false); // No need for our prototypes to waste memory on caching, since they're not being enumerated directly. + asObject(m_prototype)->getPropertyNames(exec, propertyNames); + } + + if (shouldCache) { + StructureChain* protoChain = prototypeChain(exec); + m_cachedPropertyNameArrayData = propertyNames.data(); + if (!protoChain->isCacheable()) + return; + m_cachedPropertyNameArrayData->setCachedPrototypeChain(protoChain); + m_cachedPropertyNameArrayData->setCachedStructure(this); + } +} + +void Structure::clearEnumerationCache() +{ + if (m_cachedPropertyNameArrayData) + m_cachedPropertyNameArrayData->setCachedStructure(0); + m_cachedPropertyNameArrayData.clear(); +} + +void Structure::growPropertyStorageCapacity() +{ + if (m_propertyStorageCapacity == JSObject::inlineStorageCapacity) + m_propertyStorageCapacity = JSObject::nonInlineBaseStorageCapacity; + else + m_propertyStorageCapacity *= 2; +} + +void Structure::despecifyDictionaryFunction(const Identifier& propertyName) +{ + const UString::Rep* rep = propertyName._ustring.rep(); + + materializePropertyMapIfNecessary(); + + ASSERT(m_isDictionary); + ASSERT(m_propertyTable); + + unsigned i = rep->computedHash(); + +#if DUMP_PROPERTYMAP_STATS + ++numProbes; +#endif + + unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; + ASSERT(entryIndex != emptyEntryIndex); + + if (rep == m_propertyTable->entries()[entryIndex - 1].key) { + m_propertyTable->entries()[entryIndex - 1].specificValue = 0; + return; + } + +#if DUMP_PROPERTYMAP_STATS + ++numCollisions; +#endif + + unsigned k = 1 | doubleHash(rep->computedHash()); + + while (1) { + i += k; + +#if DUMP_PROPERTYMAP_STATS + ++numRehashes; +#endif + + entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; + ASSERT(entryIndex != emptyEntryIndex); + + if (rep == m_propertyTable->entries()[entryIndex - 1].key) { + m_propertyTable->entries()[entryIndex - 1].specificValue = 0; + return; + } + } +} + +PassRefPtr<Structure> Structure::addPropertyTransitionToExistingStructure(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset) +{ + ASSERT(!structure->m_isDictionary); + ASSERT(structure->typeInfo().type() == ObjectType); + + if (structure->m_usingSingleTransitionSlot) { + Structure* existingTransition = structure->m_transitions.singleTransition; + if (existingTransition && existingTransition->m_nameInPrevious.get() == propertyName.ustring().rep() + && existingTransition->m_attributesInPrevious == attributes + && existingTransition->m_specificValueInPrevious == specificValue) { + + ASSERT(structure->m_transitions.singleTransition->m_offset != noOffset); + offset = structure->m_transitions.singleTransition->m_offset; + return existingTransition; + } + } else { + if (Structure* existingTransition = structure->m_transitions.table->get(make_pair<RefPtr<UString::Rep>, std::pair<unsigned, JSCell*> >(propertyName.ustring().rep(), make_pair(attributes, specificValue)))) { + ASSERT(existingTransition->m_offset != noOffset); + offset = existingTransition->m_offset; + return existingTransition; + } + } + + return 0; +} + +PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset) +{ + ASSERT(!structure->m_isDictionary); + ASSERT(structure->typeInfo().type() == ObjectType); + ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, specificValue, offset)); + + if (structure->transitionCount() > s_maxTransitionLength) { + RefPtr<Structure> transition = toDictionaryTransition(structure); + ASSERT(structure != transition); + offset = transition->put(propertyName, attributes, specificValue); + if (transition->propertyStorageSize() > transition->propertyStorageCapacity()) + transition->growPropertyStorageCapacity(); + return transition.release(); + } + + RefPtr<Structure> transition = create(structure->m_prototype, structure->typeInfo()); + + transition->m_cachedPrototypeChain = structure->m_cachedPrototypeChain; + transition->m_previous = structure; + transition->m_nameInPrevious = propertyName.ustring().rep(); + transition->m_attributesInPrevious = attributes; + transition->m_specificValueInPrevious = specificValue; + transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; + transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties; + + if (structure->m_propertyTable) { + if (structure->m_isPinnedPropertyTable) + transition->m_propertyTable = structure->copyPropertyTable(); + else { + transition->m_propertyTable = structure->m_propertyTable; + structure->m_propertyTable = 0; + } + } else { + if (structure->m_previous) + transition->materializePropertyMap(); + else + transition->createPropertyMapHashTable(); + } + + offset = transition->put(propertyName, attributes, specificValue); + if (transition->propertyStorageSize() > transition->propertyStorageCapacity()) + transition->growPropertyStorageCapacity(); + + transition->m_offset = offset; + + if (structure->m_usingSingleTransitionSlot) { + if (!structure->m_transitions.singleTransition) { + structure->m_transitions.singleTransition = transition.get(); + return transition.release(); + } + + Structure* existingTransition = structure->m_transitions.singleTransition; + structure->m_usingSingleTransitionSlot = false; + StructureTransitionTable* transitionTable = new StructureTransitionTable; + structure->m_transitions.table = transitionTable; + transitionTable->add(make_pair<RefPtr<UString::Rep>, std::pair<unsigned, JSCell*> >(existingTransition->m_nameInPrevious.get(), make_pair(existingTransition->m_attributesInPrevious, existingTransition->m_specificValueInPrevious)), existingTransition); + } + structure->m_transitions.table->add(make_pair<RefPtr<UString::Rep>, std::pair<unsigned, JSCell*> >(propertyName.ustring().rep(), make_pair(attributes, specificValue)), transition.get()); + return transition.release(); +} + +PassRefPtr<Structure> Structure::removePropertyTransition(Structure* structure, const Identifier& propertyName, size_t& offset) +{ + ASSERT(!structure->m_isDictionary); + + RefPtr<Structure> transition = toDictionaryTransition(structure); + + offset = transition->remove(propertyName); + + return transition.release(); +} + +PassRefPtr<Structure> Structure::changePrototypeTransition(Structure* structure, JSValue prototype) +{ + RefPtr<Structure> transition = create(prototype, structure->typeInfo()); + + transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; + transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties; + + // Don't set m_offset, as one can not transition to this. + + structure->materializePropertyMapIfNecessary(); + transition->m_propertyTable = structure->copyPropertyTable(); + transition->m_isPinnedPropertyTable = true; + + return transition.release(); +} + +PassRefPtr<Structure> Structure::despecifyFunctionTransition(Structure* structure, const Identifier& replaceFunction) +{ + RefPtr<Structure> transition = create(structure->storedPrototype(), structure->typeInfo()); + + transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; + transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties; + + // Don't set m_offset, as one can not transition to this. + + structure->materializePropertyMapIfNecessary(); + transition->m_propertyTable = structure->copyPropertyTable(); + transition->m_isPinnedPropertyTable = true; + + bool removed = transition->despecifyFunction(replaceFunction); + ASSERT_UNUSED(removed, removed); + + return transition.release(); +} + +PassRefPtr<Structure> Structure::getterSetterTransition(Structure* structure) +{ + RefPtr<Structure> transition = create(structure->storedPrototype(), structure->typeInfo()); + transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; + transition->m_hasGetterSetterProperties = transition->m_hasGetterSetterProperties; + + // Don't set m_offset, as one can not transition to this. + + structure->materializePropertyMapIfNecessary(); + transition->m_propertyTable = structure->copyPropertyTable(); + transition->m_isPinnedPropertyTable = true; + + return transition.release(); +} + +PassRefPtr<Structure> Structure::toDictionaryTransition(Structure* structure) +{ + ASSERT(!structure->m_isDictionary); + + RefPtr<Structure> transition = create(structure->m_prototype, structure->typeInfo()); + transition->m_isDictionary = true; + transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; + transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties; + + structure->materializePropertyMapIfNecessary(); + transition->m_propertyTable = structure->copyPropertyTable(); + transition->m_isPinnedPropertyTable = true; + + return transition.release(); +} + +PassRefPtr<Structure> Structure::fromDictionaryTransition(Structure* structure) +{ + ASSERT(structure->m_isDictionary); + + // Since dictionary Structures are not shared, and no opcodes specialize + // for them, we don't need to allocate a new Structure when transitioning + // to non-dictionary status. + + // FIMXE: We can make this more efficient by canonicalizing the Structure (draining the + // deleted offsets vector) before transitioning from dictionary. + if (!structure->m_propertyTable || !structure->m_propertyTable->deletedOffsets || structure->m_propertyTable->deletedOffsets->isEmpty()) + structure->m_isDictionary = false; + + return structure; +} + +size_t Structure::addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue) +{ + ASSERT(!m_transitions.singleTransition); + + materializePropertyMapIfNecessary(); + + m_isPinnedPropertyTable = true; + size_t offset = put(propertyName, attributes, specificValue); + if (propertyStorageSize() > propertyStorageCapacity()) + growPropertyStorageCapacity(); + clearEnumerationCache(); + return offset; +} + +size_t Structure::removePropertyWithoutTransition(const Identifier& propertyName) +{ + ASSERT(!m_transitions.singleTransition); + ASSERT(m_isDictionary); + + materializePropertyMapIfNecessary(); + + m_isPinnedPropertyTable = true; + size_t offset = remove(propertyName); + clearEnumerationCache(); + return offset; +} + +#if DUMP_PROPERTYMAP_STATS + +static int numProbes; +static int numCollisions; +static int numRehashes; +static int numRemoves; + +struct PropertyMapStatisticsExitLogger { + ~PropertyMapStatisticsExitLogger(); +}; + +static PropertyMapStatisticsExitLogger logger; + +PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger() +{ + printf("\nJSC::PropertyMap statistics\n\n"); + printf("%d probes\n", numProbes); + printf("%d collisions (%.1f%%)\n", numCollisions, 100.0 * numCollisions / numProbes); + printf("%d rehashes\n", numRehashes); + printf("%d removes\n", numRemoves); +} + +#endif + +static const unsigned deletedSentinelIndex = 1; + +#if !DO_PROPERTYMAP_CONSTENCY_CHECK + +inline void Structure::checkConsistency() +{ +} + +#endif + +PropertyMapHashTable* Structure::copyPropertyTable() +{ + if (!m_propertyTable) + return 0; + + size_t tableSize = PropertyMapHashTable::allocationSize(m_propertyTable->size); + PropertyMapHashTable* newTable = static_cast<PropertyMapHashTable*>(fastMalloc(tableSize)); + memcpy(newTable, m_propertyTable, tableSize); + + unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; + for (unsigned i = 1; i <= entryCount; ++i) { + if (UString::Rep* key = newTable->entries()[i].key) + key->ref(); + } + + // Copy the deletedOffsets vector. + if (m_propertyTable->deletedOffsets) + newTable->deletedOffsets = new Vector<unsigned>(*m_propertyTable->deletedOffsets); + + return newTable; +} + +size_t Structure::get(const UString::Rep* rep, unsigned& attributes, JSCell*& specificValue) +{ + materializePropertyMapIfNecessary(); + if (!m_propertyTable) + return notFound; + + unsigned i = rep->computedHash(); + +#if DUMP_PROPERTYMAP_STATS + ++numProbes; +#endif + + unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; + if (entryIndex == emptyEntryIndex) + return notFound; + + if (rep == m_propertyTable->entries()[entryIndex - 1].key) { + attributes = m_propertyTable->entries()[entryIndex - 1].attributes; + specificValue = m_propertyTable->entries()[entryIndex - 1].specificValue; + return m_propertyTable->entries()[entryIndex - 1].offset; + } + +#if DUMP_PROPERTYMAP_STATS + ++numCollisions; +#endif + + unsigned k = 1 | doubleHash(rep->computedHash()); + + while (1) { + i += k; + +#if DUMP_PROPERTYMAP_STATS + ++numRehashes; +#endif + + entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; + if (entryIndex == emptyEntryIndex) + return notFound; + + if (rep == m_propertyTable->entries()[entryIndex - 1].key) { + attributes = m_propertyTable->entries()[entryIndex - 1].attributes; + specificValue = m_propertyTable->entries()[entryIndex - 1].specificValue; + return m_propertyTable->entries()[entryIndex - 1].offset; + } + } +} + +bool Structure::despecifyFunction(const Identifier& propertyName) +{ + ASSERT(!propertyName.isNull()); + + materializePropertyMapIfNecessary(); + if (!m_propertyTable) + return false; + + UString::Rep* rep = propertyName._ustring.rep(); + + unsigned i = rep->computedHash(); + +#if DUMP_PROPERTYMAP_STATS + ++numProbes; +#endif + + unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; + if (entryIndex == emptyEntryIndex) + return false; + + if (rep == m_propertyTable->entries()[entryIndex - 1].key) { + ASSERT(m_propertyTable->entries()[entryIndex - 1].specificValue); + m_propertyTable->entries()[entryIndex - 1].specificValue = 0; + return true; + } + +#if DUMP_PROPERTYMAP_STATS + ++numCollisions; +#endif + + unsigned k = 1 | doubleHash(rep->computedHash()); + + while (1) { + i += k; + +#if DUMP_PROPERTYMAP_STATS + ++numRehashes; +#endif + + entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; + if (entryIndex == emptyEntryIndex) + return false; + + if (rep == m_propertyTable->entries()[entryIndex - 1].key) { + ASSERT(m_propertyTable->entries()[entryIndex - 1].specificValue); + m_propertyTable->entries()[entryIndex - 1].specificValue = 0; + return true; + } + } +} + +size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue) +{ + ASSERT(!propertyName.isNull()); + ASSERT(get(propertyName) == notFound); + + checkConsistency(); + + UString::Rep* rep = propertyName._ustring.rep(); + + if (!m_propertyTable) + createPropertyMapHashTable(); + + // FIXME: Consider a fast case for tables with no deleted sentinels. + + unsigned i = rep->computedHash(); + unsigned k = 0; + bool foundDeletedElement = false; + unsigned deletedElementIndex = 0; // initialize to make the compiler happy + +#if DUMP_PROPERTYMAP_STATS + ++numProbes; +#endif + + while (1) { + unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; + if (entryIndex == emptyEntryIndex) + break; + + if (entryIndex == deletedSentinelIndex) { + // If we find a deleted-element sentinel, remember it for use later. + if (!foundDeletedElement) { + foundDeletedElement = true; + deletedElementIndex = i; + } + } + + if (k == 0) { + k = 1 | doubleHash(rep->computedHash()); +#if DUMP_PROPERTYMAP_STATS + ++numCollisions; +#endif + } + + i += k; + +#if DUMP_PROPERTYMAP_STATS + ++numRehashes; +#endif + } + + // Figure out which entry to use. + unsigned entryIndex = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount + 2; + if (foundDeletedElement) { + i = deletedElementIndex; + --m_propertyTable->deletedSentinelCount; + + // Since we're not making the table bigger, we can't use the entry one past + // the end that we were planning on using, so search backwards for the empty + // slot that we can use. We know it will be there because we did at least one + // deletion in the past that left an entry empty. + while (m_propertyTable->entries()[--entryIndex - 1].key) { } + } + + // Create a new hash table entry. + m_propertyTable->entryIndices[i & m_propertyTable->sizeMask] = entryIndex; + + // Create a new hash table entry. + rep->ref(); + m_propertyTable->entries()[entryIndex - 1].key = rep; + m_propertyTable->entries()[entryIndex - 1].attributes = attributes; + m_propertyTable->entries()[entryIndex - 1].specificValue = specificValue; + m_propertyTable->entries()[entryIndex - 1].index = ++m_propertyTable->lastIndexUsed; + + unsigned newOffset; + if (m_propertyTable->deletedOffsets && !m_propertyTable->deletedOffsets->isEmpty()) { + newOffset = m_propertyTable->deletedOffsets->last(); + m_propertyTable->deletedOffsets->removeLast(); + } else + newOffset = m_propertyTable->keyCount; + m_propertyTable->entries()[entryIndex - 1].offset = newOffset; + + ++m_propertyTable->keyCount; + + if ((m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount) * 2 >= m_propertyTable->size) + expandPropertyMapHashTable(); + + checkConsistency(); + return newOffset; +} + +size_t Structure::remove(const Identifier& propertyName) +{ + ASSERT(!propertyName.isNull()); + + checkConsistency(); + + UString::Rep* rep = propertyName._ustring.rep(); + + if (!m_propertyTable) + return notFound; + +#if DUMP_PROPERTYMAP_STATS + ++numProbes; + ++numRemoves; +#endif + + // Find the thing to remove. + unsigned i = rep->computedHash(); + unsigned k = 0; + unsigned entryIndex; + UString::Rep* key = 0; + while (1) { + entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; + if (entryIndex == emptyEntryIndex) + return notFound; + + key = m_propertyTable->entries()[entryIndex - 1].key; + if (rep == key) + break; + + if (k == 0) { + k = 1 | doubleHash(rep->computedHash()); +#if DUMP_PROPERTYMAP_STATS + ++numCollisions; +#endif + } + + i += k; + +#if DUMP_PROPERTYMAP_STATS + ++numRehashes; +#endif + } + + // Replace this one element with the deleted sentinel. Also clear out + // the entry so we can iterate all the entries as needed. + m_propertyTable->entryIndices[i & m_propertyTable->sizeMask] = deletedSentinelIndex; + + size_t offset = m_propertyTable->entries()[entryIndex - 1].offset; + + key->deref(); + m_propertyTable->entries()[entryIndex - 1].key = 0; + m_propertyTable->entries()[entryIndex - 1].attributes = 0; + m_propertyTable->entries()[entryIndex - 1].specificValue = 0; + m_propertyTable->entries()[entryIndex - 1].offset = 0; + + if (!m_propertyTable->deletedOffsets) + m_propertyTable->deletedOffsets = new Vector<unsigned>; + m_propertyTable->deletedOffsets->append(offset); + + ASSERT(m_propertyTable->keyCount >= 1); + --m_propertyTable->keyCount; + ++m_propertyTable->deletedSentinelCount; + + if (m_propertyTable->deletedSentinelCount * 4 >= m_propertyTable->size) + rehashPropertyMapHashTable(); + + checkConsistency(); + return offset; +} + +void Structure::insertIntoPropertyMapHashTable(const PropertyMapEntry& entry) +{ + ASSERT(m_propertyTable); + + unsigned i = entry.key->computedHash(); + unsigned k = 0; + +#if DUMP_PROPERTYMAP_STATS + ++numProbes; +#endif + + while (1) { + unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; + if (entryIndex == emptyEntryIndex) + break; + + if (k == 0) { + k = 1 | doubleHash(entry.key->computedHash()); +#if DUMP_PROPERTYMAP_STATS + ++numCollisions; +#endif + } + + i += k; + +#if DUMP_PROPERTYMAP_STATS + ++numRehashes; +#endif + } + + unsigned entryIndex = m_propertyTable->keyCount + 2; + m_propertyTable->entryIndices[i & m_propertyTable->sizeMask] = entryIndex; + m_propertyTable->entries()[entryIndex - 1] = entry; + + ++m_propertyTable->keyCount; +} + +void Structure::createPropertyMapHashTable() +{ + ASSERT(sizeForKeyCount(7) == newTableSize); + createPropertyMapHashTable(newTableSize); +} + +void Structure::createPropertyMapHashTable(unsigned newTableSize) +{ + ASSERT(!m_propertyTable); + ASSERT(isPowerOf2(newTableSize)); + + checkConsistency(); + + m_propertyTable = static_cast<PropertyMapHashTable*>(fastZeroedMalloc(PropertyMapHashTable::allocationSize(newTableSize))); + m_propertyTable->size = newTableSize; + m_propertyTable->sizeMask = newTableSize - 1; + + checkConsistency(); +} + +void Structure::expandPropertyMapHashTable() +{ + ASSERT(m_propertyTable); + rehashPropertyMapHashTable(m_propertyTable->size * 2); +} + +void Structure::rehashPropertyMapHashTable() +{ + ASSERT(m_propertyTable); + ASSERT(m_propertyTable->size); + rehashPropertyMapHashTable(m_propertyTable->size); +} + +void Structure::rehashPropertyMapHashTable(unsigned newTableSize) +{ + ASSERT(m_propertyTable); + ASSERT(isPowerOf2(newTableSize)); + + checkConsistency(); + + PropertyMapHashTable* oldTable = m_propertyTable; + + m_propertyTable = static_cast<PropertyMapHashTable*>(fastZeroedMalloc(PropertyMapHashTable::allocationSize(newTableSize))); + m_propertyTable->size = newTableSize; + m_propertyTable->sizeMask = newTableSize - 1; + + unsigned lastIndexUsed = 0; + unsigned entryCount = oldTable->keyCount + oldTable->deletedSentinelCount; + for (unsigned i = 1; i <= entryCount; ++i) { + if (oldTable->entries()[i].key) { + lastIndexUsed = max(oldTable->entries()[i].index, lastIndexUsed); + insertIntoPropertyMapHashTable(oldTable->entries()[i]); + } + } + m_propertyTable->lastIndexUsed = lastIndexUsed; + m_propertyTable->deletedOffsets = oldTable->deletedOffsets; + + fastFree(oldTable); + + checkConsistency(); +} + +static int comparePropertyMapEntryIndices(const void* a, const void* b) +{ + unsigned ia = static_cast<PropertyMapEntry* const*>(a)[0]->index; + unsigned ib = static_cast<PropertyMapEntry* const*>(b)[0]->index; + if (ia < ib) + return -1; + if (ia > ib) + return +1; + return 0; +} + +void Structure::getNamesFromPropertyTable(PropertyNameArray& propertyNames, bool includeNonEnumerable) +{ + materializePropertyMapIfNecessary(); + if (!m_propertyTable) + return; + + if (m_propertyTable->keyCount < tinyMapThreshold) { + PropertyMapEntry* a[tinyMapThreshold]; + int i = 0; + unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; + for (unsigned k = 1; k <= entryCount; k++) { + if (m_propertyTable->entries()[k].key + && (includeNonEnumerable || !(m_propertyTable->entries()[k].attributes & DontEnum))) { + PropertyMapEntry* value = &m_propertyTable->entries()[k]; + int j; + for (j = i - 1; j >= 0 && a[j]->index > value->index; --j) + a[j + 1] = a[j]; + a[j + 1] = value; + ++i; + } + } + if (!propertyNames.size()) { + for (int k = 0; k < i; ++k) + propertyNames.addKnownUnique(a[k]->key); + } else { + for (int k = 0; k < i; ++k) + propertyNames.add(a[k]->key); + } + + return; + } + + // Allocate a buffer to use to sort the keys. + Vector<PropertyMapEntry*, smallMapThreshold> sortedEnumerables(m_propertyTable->keyCount); + + // Get pointers to the enumerable entries in the buffer. + PropertyMapEntry** p = sortedEnumerables.data(); + unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; + for (unsigned i = 1; i <= entryCount; i++) { + if (m_propertyTable->entries()[i].key + && (includeNonEnumerable || !(m_propertyTable->entries()[i].attributes & DontEnum))) + *p++ = &m_propertyTable->entries()[i]; + } + + size_t enumerableCount = p - sortedEnumerables.data(); + // Sort the entries by index. + qsort(sortedEnumerables.data(), enumerableCount, sizeof(PropertyMapEntry*), comparePropertyMapEntryIndices); + sortedEnumerables.resize(enumerableCount); + + // Put the keys of the sorted entries into the list. + if (!propertyNames.size()) { + for (size_t i = 0; i < sortedEnumerables.size(); ++i) + propertyNames.addKnownUnique(sortedEnumerables[i]->key); + } else { + for (size_t i = 0; i < sortedEnumerables.size(); ++i) + propertyNames.add(sortedEnumerables[i]->key); + } +} + +void Structure::getNamesFromClassInfoTable(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, bool includeNonEnumerable) +{ + // Add properties from the static hashtables of properties + for (; classInfo; classInfo = classInfo->parentClass) { + const HashTable* table = classInfo->propHashTable(exec); + if (!table) + continue; + 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() && (includeNonEnumerable || !(entry->attributes() & DontEnum))) + propertyNames.add(entry->key()); + } + } +} + +#if DO_PROPERTYMAP_CONSTENCY_CHECK + +void Structure::checkConsistency() +{ + if (!m_propertyTable) + return; + + ASSERT(m_propertyTable->size >= newTableSize); + ASSERT(m_propertyTable->sizeMask); + ASSERT(m_propertyTable->size == m_propertyTable->sizeMask + 1); + ASSERT(!(m_propertyTable->size & m_propertyTable->sizeMask)); + + ASSERT(m_propertyTable->keyCount <= m_propertyTable->size / 2); + ASSERT(m_propertyTable->deletedSentinelCount <= m_propertyTable->size / 4); + + ASSERT(m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount <= m_propertyTable->size / 2); + + unsigned indexCount = 0; + unsigned deletedIndexCount = 0; + for (unsigned a = 0; a != m_propertyTable->size; ++a) { + unsigned entryIndex = m_propertyTable->entryIndices[a]; + if (entryIndex == emptyEntryIndex) + continue; + if (entryIndex == deletedSentinelIndex) { + ++deletedIndexCount; + continue; + } + ASSERT(entryIndex > deletedSentinelIndex); + ASSERT(entryIndex - 1 <= m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount); + ++indexCount; + + for (unsigned b = a + 1; b != m_propertyTable->size; ++b) + ASSERT(m_propertyTable->entryIndices[b] != entryIndex); + } + ASSERT(indexCount == m_propertyTable->keyCount); + ASSERT(deletedIndexCount == m_propertyTable->deletedSentinelCount); + + ASSERT(m_propertyTable->entries()[0].key == 0); + + unsigned nonEmptyEntryCount = 0; + for (unsigned c = 1; c <= m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; ++c) { + UString::Rep* rep = m_propertyTable->entries()[c].key; + if (!rep) + continue; + ++nonEmptyEntryCount; + unsigned i = rep->computedHash(); + unsigned k = 0; + unsigned entryIndex; + while (1) { + entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; + ASSERT(entryIndex != emptyEntryIndex); + if (rep == m_propertyTable->entries()[entryIndex - 1].key) + break; + if (k == 0) + k = 1 | doubleHash(rep->computedHash()); + i += k; + } + ASSERT(entryIndex == c + 1); + } + + ASSERT(nonEmptyEntryCount == m_propertyTable->keyCount); +} + +#endif // DO_PROPERTYMAP_CONSTENCY_CHECK + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Structure.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Structure.h new file mode 100644 index 0000000..ca4552b --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Structure.h @@ -0,0 +1,242 @@ +/* + * 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 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 Structure_h +#define Structure_h + +#include "Identifier.h" +#include "JSType.h" +#include "JSValue.h" +#include "PropertyMapHashTable.h" +#include "StructureTransitionTable.h" +#include "JSTypeInfo.h" +#include "UString.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +#ifndef NDEBUG +#define DUMP_PROPERTYMAP_STATS 0 +#else +#define DUMP_PROPERTYMAP_STATS 0 +#endif + +namespace JSC { + + class PropertyNameArray; + class PropertyNameArrayData; + class StructureChain; + + class Structure : public RefCounted<Structure> { + public: + enum ListedAttribute { + NonEnumerable = 1 << 1, + Prototype = 1 << 2 + }; + + friend class JIT; + static PassRefPtr<Structure> create(JSValue prototype, const TypeInfo& typeInfo) + { + return adoptRef(new Structure(prototype, typeInfo)); + } + + static void startIgnoringLeaks(); + static void stopIgnoringLeaks(); + + static void dumpStatistics(); + + static PassRefPtr<Structure> addPropertyTransition(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset); + static PassRefPtr<Structure> addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset); + static PassRefPtr<Structure> removePropertyTransition(Structure*, const Identifier& propertyName, size_t& offset); + static PassRefPtr<Structure> changePrototypeTransition(Structure*, JSValue prototype); + static PassRefPtr<Structure> despecifyFunctionTransition(Structure*, const Identifier&); + static PassRefPtr<Structure> getterSetterTransition(Structure*); + static PassRefPtr<Structure> toDictionaryTransition(Structure*); + static PassRefPtr<Structure> fromDictionaryTransition(Structure*); + + ~Structure(); + + void mark() + { + if (!m_prototype.marked()) + m_prototype.mark(); + } + + // These should be used with caution. + size_t addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue); + size_t removePropertyWithoutTransition(const Identifier& propertyName); + void setPrototypeWithoutTransition(JSValue prototype) { m_prototype = prototype; } + + bool isDictionary() const { return m_isDictionary; } + + const TypeInfo& typeInfo() const { return m_typeInfo; } + + JSValue storedPrototype() const { return m_prototype; } + JSValue prototypeForLookup(ExecState*) const; + StructureChain* prototypeChain(ExecState*) const; + + Structure* previousID() const { return m_previous.get(); } + + void growPropertyStorageCapacity(); + size_t propertyStorageCapacity() const { return m_propertyStorageCapacity; } + size_t propertyStorageSize() const { return m_propertyTable ? m_propertyTable->keyCount + (m_propertyTable->deletedOffsets ? m_propertyTable->deletedOffsets->size() : 0) : m_offset + 1; } + bool isUsingInlineStorage() const; + + size_t get(const Identifier& propertyName); + size_t get(const UString::Rep* rep, unsigned& attributes, JSCell*& specificValue); + size_t get(const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue) + { + ASSERT(!propertyName.isNull()); + return get(propertyName._ustring.rep(), attributes, specificValue); + } + + void getPropertyNames(ExecState*, PropertyNameArray&, JSObject*, unsigned listedAttributes = Prototype); + + bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; } + void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; } + + bool isEmpty() const { return m_propertyTable ? !m_propertyTable->keyCount : m_offset == noOffset; } + + JSCell* specificValue() { return m_specificValueInPrevious; } + void despecifyDictionaryFunction(const Identifier& propertyName); + + private: + Structure(JSValue prototype, const TypeInfo&); + + size_t put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue); + size_t remove(const Identifier& propertyName); + void getNamesFromPropertyTable(PropertyNameArray&, bool includeNonEnumerable = false); + void getNamesFromClassInfoTable(ExecState*, const ClassInfo*, PropertyNameArray&, bool includeNonEnumerable = false); + + void expandPropertyMapHashTable(); + void rehashPropertyMapHashTable(); + void rehashPropertyMapHashTable(unsigned newTableSize); + void createPropertyMapHashTable(); + void createPropertyMapHashTable(unsigned newTableSize); + void insertIntoPropertyMapHashTable(const PropertyMapEntry&); + void checkConsistency(); + + bool despecifyFunction(const Identifier&); + + PropertyMapHashTable* copyPropertyTable(); + void materializePropertyMap(); + void materializePropertyMapIfNecessary() + { + if (m_propertyTable || !m_previous) + return; + materializePropertyMap(); + } + + void clearEnumerationCache(); + + signed char transitionCount() const + { + // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both. + return m_offset == noOffset ? 0 : m_offset + 1; + } + + bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const; + + static const unsigned emptyEntryIndex = 0; + + static const signed char s_maxTransitionLength = 64; + + static const signed char noOffset = -1; + + TypeInfo m_typeInfo; + + JSValue m_prototype; + mutable RefPtr<StructureChain> m_cachedPrototypeChain; + + RefPtr<Structure> m_previous; + RefPtr<UString::Rep> m_nameInPrevious; + + union { + Structure* singleTransition; + StructureTransitionTable* table; + } m_transitions; + JSCell* m_specificValueInPrevious; + + RefPtr<PropertyNameArrayData> m_cachedPropertyNameArrayData; + + PropertyMapHashTable* m_propertyTable; + + size_t m_propertyStorageCapacity; + signed char m_offset; + + bool m_isDictionary : 1; + bool m_isPinnedPropertyTable : 1; + bool m_hasGetterSetterProperties : 1; + bool m_usingSingleTransitionSlot : 1; + unsigned m_attributesInPrevious : 7; + }; + + inline size_t Structure::get(const Identifier& propertyName) + { + ASSERT(!propertyName.isNull()); + + materializePropertyMapIfNecessary(); + if (!m_propertyTable) + return WTF::notFound; + + UString::Rep* rep = propertyName._ustring.rep(); + + unsigned i = rep->computedHash(); + +#if DUMP_PROPERTYMAP_STATS + ++numProbes; +#endif + + unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; + if (entryIndex == emptyEntryIndex) + return WTF::notFound; + + if (rep == m_propertyTable->entries()[entryIndex - 1].key) + return m_propertyTable->entries()[entryIndex - 1].offset; + +#if DUMP_PROPERTYMAP_STATS + ++numCollisions; +#endif + + unsigned k = 1 | WTF::doubleHash(rep->computedHash()); + + while (1) { + i += k; + +#if DUMP_PROPERTYMAP_STATS + ++numRehashes; +#endif + + entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask]; + if (entryIndex == emptyEntryIndex) + return WTF::notFound; + + if (rep == m_propertyTable->entries()[entryIndex - 1].key) + return m_propertyTable->entries()[entryIndex - 1].offset; + } + } + +} // namespace JSC + +#endif // Structure_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureChain.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureChain.cpp new file mode 100644 index 0000000..acebc86 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureChain.cpp @@ -0,0 +1,66 @@ +/* + * 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 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 "StructureChain.h" +#include "Structure.h" + +#include "JSObject.h" +#include "Structure.h" +#include <wtf/RefPtr.h> + +namespace JSC { + +StructureChain::StructureChain(Structure* head) +{ + size_t size = 0; + for (Structure* current = head; current; current = current->storedPrototype().isNull() ? 0 : asObject(current->storedPrototype())->structure()) + ++size; + + m_vector.set(new RefPtr<Structure>[size + 1]); + + size_t i = 0; + for (Structure* current = head; current; current = current->storedPrototype().isNull() ? 0 : asObject(current->storedPrototype())->structure()) + m_vector[i++] = current; + m_vector[i] = 0; +} + +PassRefPtr<StructureChain> StructureChain::create(Structure* head) +{ + return adoptRef(new StructureChain(head)); +} + +bool StructureChain::isCacheable() const +{ + uint32_t i = 0; + + while (m_vector[i]) { + if (m_vector[i++]->isDictionary()) + return false; + } + return true; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureChain.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureChain.h new file mode 100644 index 0000000..5990e17 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureChain.h @@ -0,0 +1,52 @@ +/* + * 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 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 StructureChain_h +#define StructureChain_h + +#include <wtf/OwnArrayPtr.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace JSC { + + class Structure; + + class StructureChain : public RefCounted<StructureChain> { + public: + static PassRefPtr<StructureChain> create(Structure* head); + RefPtr<Structure>* head() { return m_vector.get(); } + bool isCacheable() const; + + private: + StructureChain(Structure* head); + + OwnArrayPtr<RefPtr<Structure> > m_vector; + }; + +} // namespace JSC + +#endif // StructureChain_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureTransitionTable.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureTransitionTable.h new file mode 100644 index 0000000..804cbeb --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureTransitionTable.h @@ -0,0 +1,73 @@ +/* + * 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 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 StructureTransitionTable_h +#define StructureTransitionTable_h + +#include "UString.h" +#include <wtf/HashFunctions.h> +#include <wtf/HashMap.h> +#include <wtf/HashTraits.h> +#include <wtf/RefPtr.h> + +namespace JSC { + + class Structure; + + struct StructureTransitionTableHash { + typedef std::pair<RefPtr<UString::Rep>, std::pair<unsigned, JSCell*> > Key; + static unsigned hash(const Key& p) + { + return p.first->computedHash(); + } + + static bool equal(const Key& a, const Key& b) + { + return a == b; + } + + static const bool safeToCompareToEmptyOrDeleted = true; + }; + + struct StructureTransitionTableHashTraits { + typedef WTF::HashTraits<RefPtr<UString::Rep> > FirstTraits; + typedef WTF::GenericHashTraits<unsigned> SecondFirstTraits; + typedef WTF::GenericHashTraits<JSCell*> SecondSecondTraits; + typedef std::pair<FirstTraits::TraitType, std::pair<SecondFirstTraits::TraitType, SecondSecondTraits::TraitType> > TraitType; + + static const bool emptyValueIsZero = FirstTraits::emptyValueIsZero && SecondFirstTraits::emptyValueIsZero && SecondSecondTraits::emptyValueIsZero; + static TraitType emptyValue() { return std::make_pair(FirstTraits::emptyValue(), std::make_pair(SecondFirstTraits::emptyValue(), SecondSecondTraits::emptyValue())); } + + static const bool needsDestruction = FirstTraits::needsDestruction || SecondFirstTraits::needsDestruction || SecondSecondTraits::needsDestruction; + + static void constructDeletedValue(TraitType& slot) { FirstTraits::constructDeletedValue(slot.first); } + static bool isDeletedValue(const TraitType& value) { return FirstTraits::isDeletedValue(value.first); } + }; + + typedef HashMap<StructureTransitionTableHash::Key, Structure*, StructureTransitionTableHash, StructureTransitionTableHashTraits> StructureTransitionTable; + +} // namespace JSC + +#endif // StructureTransitionTable_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/SymbolTable.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/SymbolTable.h new file mode 100644 index 0000000..c00f95a --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/SymbolTable.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SymbolTable_h +#define SymbolTable_h + +#include "JSObject.h" +#include "UString.h" +#include <wtf/AlwaysInline.h> + +namespace JSC { + + static ALWAYS_INLINE int missingSymbolMarker() { return std::numeric_limits<int>::max(); } + + // The bit twiddling in this class assumes that every register index is a + // reasonably small positive or negative number, and therefore has its high + // four bits all set or all unset. + + struct SymbolTableEntry { + SymbolTableEntry() + : m_bits(0) + { + } + + SymbolTableEntry(int index) + { + ASSERT(isValidIndex(index)); + pack(index, false, false); + } + + SymbolTableEntry(int index, unsigned attributes) + { + ASSERT(isValidIndex(index)); + pack(index, attributes & ReadOnly, attributes & DontEnum); + } + + bool isNull() const + { + return !m_bits; + } + + int getIndex() const + { + return m_bits >> FlagBits; + } + + unsigned getAttributes() const + { + unsigned attributes = 0; + if (m_bits & ReadOnlyFlag) + attributes |= ReadOnly; + if (m_bits & DontEnumFlag) + attributes |= DontEnum; + return attributes; + } + + void setAttributes(unsigned attributes) + { + pack(getIndex(), attributes & ReadOnly, attributes & DontEnum); + } + + bool isReadOnly() const + { + return m_bits & ReadOnlyFlag; + } + + private: + static const unsigned ReadOnlyFlag = 0x1; + static const unsigned DontEnumFlag = 0x2; + static const unsigned NotNullFlag = 0x4; + static const unsigned FlagBits = 3; + + void pack(int index, bool readOnly, bool dontEnum) + { + m_bits = (index << FlagBits) | NotNullFlag; + if (readOnly) + m_bits |= ReadOnlyFlag; + if (dontEnum) + m_bits |= DontEnumFlag; + } + + bool isValidIndex(int index) + { + return ((index << FlagBits) >> FlagBits) == index; + } + + int m_bits; + }; + + struct SymbolTableIndexHashTraits { + typedef SymbolTableEntry TraitType; + static SymbolTableEntry emptyValue() { return SymbolTableEntry(); } + static const bool emptyValueIsZero = true; + static const bool needsDestruction = false; + }; + + typedef HashMap<RefPtr<UString::Rep>, SymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<UString::Rep> >, SymbolTableIndexHashTraits> SymbolTable; + +} // namespace JSC + +#endif // SymbolTable_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/TimeoutChecker.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/TimeoutChecker.cpp new file mode 100644 index 0000000..045a33a --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/TimeoutChecker.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "TimeoutChecker.h" + +#include "CallFrame.h" +#include "JSGlobalObject.h" + +#if PLATFORM(DARWIN) +#include <mach/mach.h> +#endif + +#if HAVE(SYS_TIME_H) +#include <sys/time.h> +#endif + +#if PLATFORM(WIN_OS) +#include <windows.h> +#endif + +#if PLATFORM(QT) +#include <QDateTime> +#endif + +using namespace std; + +namespace JSC { + +// Number of ticks before the first timeout check is done. +static const int ticksUntilFirstCheck = 1024; + +// Default number of milliseconds between each timeout check. +static const int defaultIntervalBetweenChecks = 1000; + +// Returns the time the current thread has spent executing, in milliseconds. +static inline unsigned getCPUTime() +{ +#if PLATFORM(DARWIN) + mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT; + thread_basic_info_data_t info; + + // Get thread information + mach_port_t threadPort = mach_thread_self(); + thread_info(threadPort, THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount); + mach_port_deallocate(mach_task_self(), threadPort); + + unsigned time = info.user_time.seconds * 1000 + info.user_time.microseconds / 1000; + time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000; + + return time; +#elif HAVE(SYS_TIME_H) + // FIXME: This should probably use getrusage with the RUSAGE_THREAD flag. + struct timeval tv; + gettimeofday(&tv, 0); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +#elif PLATFORM(QT) + QDateTime t = QDateTime::currentDateTime(); + return t.toTime_t() * 1000 + t.time().msec(); +#elif PLATFORM(WIN_OS) + union { + FILETIME fileTime; + unsigned long long fileTimeAsLong; + } userTime, kernelTime; + + // GetThreadTimes won't accept NULL arguments so we pass these even though + // they're not used. + FILETIME creationTime, exitTime; + + GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime); + + return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000; +#else +#error Platform does not have getCurrentTime function +#endif +} + +TimeoutChecker::TimeoutChecker() + : m_timeoutInterval(0) + , m_startCount(0) + , m_intervalBetweenChecks(defaultIntervalBetweenChecks) +{ + reset(); +} + +TimeoutChecker::~TimeoutChecker() +{ +} + +void TimeoutChecker::reset() +{ + m_ticksUntilNextCheck = ticksUntilFirstCheck; + m_timeAtLastCheck = 0; + m_timeExecuting = 0; +} + +bool TimeoutChecker::didTimeOut(ExecState* exec) +{ + unsigned currentTime = getCPUTime(); + + if (!m_timeAtLastCheck) { + // Suspicious amount of looping in a script -- start timing it + m_timeAtLastCheck = currentTime; + return false; + } + + unsigned timeDiff = currentTime - m_timeAtLastCheck; + + if (timeDiff == 0) + timeDiff = 1; + + m_timeExecuting += timeDiff; + m_timeAtLastCheck = currentTime; + + // Adjust the tick threshold so we get the next checkTimeout call in the + // interval specified in intervalBetweenChecks. + m_ticksUntilNextCheck = static_cast<unsigned>((static_cast<float>(m_intervalBetweenChecks) / timeDiff) * m_ticksUntilNextCheck); + // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the + // preferred script check time interval. + if (m_ticksUntilNextCheck == 0) + m_ticksUntilNextCheck = ticksUntilFirstCheck; + + if (m_timeoutInterval && m_timeExecuting > m_timeoutInterval) { + if (exec->dynamicGlobalObject()->shouldInterruptScript()) + return true; + + reset(); + } + + return false; +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/TimeoutChecker.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/TimeoutChecker.h new file mode 100644 index 0000000..1680d6d --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/TimeoutChecker.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TimeoutChecker_h +#define TimeoutChecker_h + +#include <wtf/Assertions.h> + +namespace JSC { + + class ExecState; + + class TimeoutChecker { + public: + TimeoutChecker(); + virtual ~TimeoutChecker(); + + void setTimeoutInterval(unsigned timeoutInterval) { m_timeoutInterval = timeoutInterval; } + void setCheckInterval(unsigned checkInterval) { if (checkInterval) m_intervalBetweenChecks = checkInterval; } + + unsigned ticksUntilNextCheck() { return m_ticksUntilNextCheck; } + + void start() + { + if (!m_startCount) + reset(); + ++m_startCount; + } + + void stop() + { + ASSERT(m_startCount); + --m_startCount; + } + + void reset(); + + virtual bool didTimeOut(ExecState*); + + private: + unsigned m_timeoutInterval; + unsigned m_timeAtLastCheck; + unsigned m_timeExecuting; + unsigned m_startCount; + unsigned m_ticksUntilNextCheck; + unsigned m_intervalBetweenChecks; + }; + +} // namespace JSC + +#endif // TimeoutChecker_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Tracing.d b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Tracing.d new file mode 100644 index 0000000..b9efaff --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Tracing.d @@ -0,0 +1,40 @@ +/* + * 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(int, int); + + probe profile__will_execute(int, char*, char*, int); + probe profile__did_execute(int, char*, char*, 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/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Tracing.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Tracing.h new file mode 100644 index 0000000..e544f66 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Tracing.h @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#ifndef Tracing_h +#define Tracing_h + +#if HAVE(DTRACE) +#include "TracingDtrace.h" +#else + +#define JAVASCRIPTCORE_GC_BEGIN() +#define JAVASCRIPTCORE_GC_BEGIN_ENABLED() 0 + +#define JAVASCRIPTCORE_GC_END(arg0, arg1) +#define JAVASCRIPTCORE_GC_END_ENABLED() 0 + +#define JAVASCRIPTCORE_GC_MARKED() +#define JAVASCRIPTCORE_GC_MARKED_ENABLED() 0 + +#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) +#define JAVASCRIPTCORE_PROFILE_DID_EXECUTE_ENABLED() 0 + +#endif + +#endif // Tracing_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/UString.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/UString.cpp new file mode 100644 index 0000000..fa19932 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/UString.cpp @@ -0,0 +1,1781 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) + * Copyright (C) 2009 Google 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 "UString.h" + +#include "JSGlobalObjectFunctions.h" +#include "Collector.h" +#include "dtoa.h" +#include "Identifier.h" +#include "Operations.h" +#include <ctype.h> +#include <float.h> +#include <limits.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <wtf/ASCIICType.h> +#include <wtf/Assertions.h> +#include <wtf/MathExtras.h> +#include <wtf/Vector.h> +#include <wtf/unicode/UTF8.h> +#include <wtf/StringExtras.h> + +#if HAVE(STRING_H) +#include <string.h> +#endif +#if HAVE(STRINGS_H) +#include <strings.h> +#endif + +using namespace WTF; +using namespace WTF::Unicode; +using namespace std; + +// This can be tuned differently per platform by putting platform #ifs right here. +// If you don't define this macro at all, then copyChars will just call directly +// to memcpy. +#define USTRING_COPY_CHARS_INLINE_CUTOFF 20 + +namespace JSC { + +extern const double NaN; +extern const double Inf; + +// This number must be at least 2 to avoid sharing empty, null as well as 1 character strings from SmallStrings. +static const int minLengthToShare = 10; + +static inline size_t overflowIndicator() { return std::numeric_limits<size_t>::max(); } +static inline size_t maxUChars() { return std::numeric_limits<size_t>::max() / sizeof(UChar); } + +static inline UChar* allocChars(size_t length) +{ + ASSERT(length); + if (length > maxUChars()) + return 0; + return static_cast<UChar*>(tryFastMalloc(sizeof(UChar) * length)); +} + +static inline UChar* reallocChars(UChar* buffer, size_t length) +{ + ASSERT(length); + if (length > maxUChars()) + return 0; + return static_cast<UChar*>(tryFastRealloc(buffer, sizeof(UChar) * length)); +} + +static inline void copyChars(UChar* destination, const UChar* source, unsigned numCharacters) +{ +#ifdef USTRING_COPY_CHARS_INLINE_CUTOFF + if (numCharacters <= USTRING_COPY_CHARS_INLINE_CUTOFF) { + for (unsigned i = 0; i < numCharacters; ++i) + destination[i] = source[i]; + return; + } +#endif + memcpy(destination, source, numCharacters * sizeof(UChar)); +} + +COMPILE_ASSERT(sizeof(UChar) == 2, uchar_is_2_bytes); + +CString::CString(const char* c) + : m_length(strlen(c)) + , m_data(new char[m_length + 1]) +{ + memcpy(m_data, c, m_length + 1); +} + +CString::CString(const char* c, size_t length) + : m_length(length) + , m_data(new char[length + 1]) +{ + memcpy(m_data, c, m_length); + m_data[m_length] = 0; +} + +CString::CString(const CString& b) +{ + m_length = b.m_length; + if (b.m_data) { + m_data = new char[m_length + 1]; + memcpy(m_data, b.m_data, m_length + 1); + } else + m_data = 0; +} + +CString::~CString() +{ + delete [] m_data; +} + +CString CString::adopt(char* c, size_t length) +{ + CString s; + s.m_data = c; + s.m_length = length; + return s; +} + +CString& CString::append(const CString& t) +{ + char* n; + n = new char[m_length + t.m_length + 1]; + if (m_length) + memcpy(n, m_data, m_length); + if (t.m_length) + memcpy(n + m_length, t.m_data, t.m_length); + m_length += t.m_length; + n[m_length] = 0; + + delete [] m_data; + m_data = n; + + return *this; +} + +CString& CString::operator=(const char* c) +{ + if (m_data) + delete [] m_data; + m_length = strlen(c); + m_data = new char[m_length + 1]; + memcpy(m_data, c, m_length + 1); + + return *this; +} + +CString& CString::operator=(const CString& str) +{ + if (this == &str) + return *this; + + if (m_data) + delete [] m_data; + m_length = str.m_length; + if (str.m_data) { + m_data = new char[m_length + 1]; + memcpy(m_data, str.m_data, m_length + 1); + } else + m_data = 0; + + return *this; +} + +bool operator==(const CString& c1, const CString& c2) +{ + size_t len = c1.size(); + return len == c2.size() && (len == 0 || memcmp(c1.c_str(), c2.c_str(), len) == 0); +} + +// These static strings are immutable, except for rc, whose initial value is chosen to +// reduce the possibility of it becoming zero due to ref/deref not being thread-safe. +static UChar sharedEmptyChar; +UString::BaseString* UString::Rep::nullBaseString; +UString::BaseString* UString::Rep::emptyBaseString; +UString* UString::nullUString; + +static void initializeStaticBaseString(UString::BaseString& base) +{ + base.rc = INT_MAX / 2; + base.m_identifierTableAndFlags.setFlag(UString::Rep::StaticFlag); + base.checkConsistency(); +} + +void initializeUString() +{ + UString::Rep::nullBaseString = new UString::BaseString(0, 0); + initializeStaticBaseString(*UString::Rep::nullBaseString); + + UString::Rep::emptyBaseString = new UString::BaseString(&sharedEmptyChar, 0); + initializeStaticBaseString(*UString::Rep::emptyBaseString); + + UString::nullUString = new UString; +} + +static char* statBuffer = 0; // Only used for debugging via UString::ascii(). + +PassRefPtr<UString::Rep> UString::Rep::createCopying(const UChar* d, int l) +{ + UChar* copyD = static_cast<UChar*>(fastMalloc(l * sizeof(UChar))); + copyChars(copyD, d, l); + return create(copyD, l); +} + +PassRefPtr<UString::Rep> UString::Rep::createFromUTF8(const char* string) +{ + if (!string) + return &UString::Rep::null(); + + size_t length = strlen(string); + Vector<UChar, 1024> buffer(length); + UChar* p = buffer.data(); + if (conversionOK != convertUTF8ToUTF16(&string, string + length, &p, p + length)) + return &UString::Rep::null(); + + return UString::Rep::createCopying(buffer.data(), p - buffer.data()); +} + +PassRefPtr<UString::Rep> UString::Rep::create(UChar* string, int length, PassRefPtr<UString::SharedUChar> sharedBuffer) +{ + PassRefPtr<UString::Rep> rep = create(string, length); + rep->baseString()->setSharedBuffer(sharedBuffer); + rep->checkConsistency(); + return rep; +} + +UString::SharedUChar* UString::Rep::sharedBuffer() +{ + UString::BaseString* base = baseString(); + if (len < minLengthToShare) + return 0; + + return base->sharedBuffer(); +} + +void UString::Rep::destroy() +{ + checkConsistency(); + + // Static null and empty strings can never be destroyed, but we cannot rely on + // reference counting, because ref/deref are not thread-safe. + if (!isStatic()) { + if (identifierTable()) + Identifier::remove(this); + + UString::BaseString* base = baseString(); + if (base == this) { + if (m_sharedBuffer) + m_sharedBuffer->deref(); + else + fastFree(base->buf); + } else + base->deref(); + + delete this; + } +} + +// Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's +// or anything like that. +const unsigned PHI = 0x9e3779b9U; + +// Paul Hsieh's SuperFastHash +// http://www.azillionmonkeys.com/qed/hash.html +unsigned UString::Rep::computeHash(const UChar* s, int len) +{ + unsigned l = len; + uint32_t hash = PHI; + uint32_t tmp; + + int rem = l & 1; + l >>= 1; + + // Main loop + for (; l > 0; l--) { + hash += s[0]; + tmp = (s[1] << 11) ^ hash; + hash = (hash << 16) ^ tmp; + s += 2; + hash += hash >> 11; + } + + // Handle end case + if (rem) { + hash += s[0]; + hash ^= hash << 11; + hash += hash >> 17; + } + + // Force "avalanching" of final 127 bits + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 2; + hash += hash >> 15; + hash ^= hash << 10; + + // this avoids ever returning a hash code of 0, since that is used to + // signal "hash not computed yet", using a value that is likely to be + // effectively the same as 0 when the low bits are masked + if (hash == 0) + hash = 0x80000000; + + return hash; +} + +// Paul Hsieh's SuperFastHash +// http://www.azillionmonkeys.com/qed/hash.html +unsigned UString::Rep::computeHash(const char* s, int l) +{ + // This hash is designed to work on 16-bit chunks at a time. But since the normal case + // (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they + // were 16-bit chunks, which should give matching results + + uint32_t hash = PHI; + uint32_t tmp; + + size_t rem = l & 1; + l >>= 1; + + // Main loop + for (; l > 0; l--) { + hash += static_cast<unsigned char>(s[0]); + tmp = (static_cast<unsigned char>(s[1]) << 11) ^ hash; + hash = (hash << 16) ^ tmp; + s += 2; + hash += hash >> 11; + } + + // Handle end case + if (rem) { + hash += static_cast<unsigned char>(s[0]); + hash ^= hash << 11; + hash += hash >> 17; + } + + // Force "avalanching" of final 127 bits + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 2; + hash += hash >> 15; + hash ^= hash << 10; + + // this avoids ever returning a hash code of 0, since that is used to + // signal "hash not computed yet", using a value that is likely to be + // effectively the same as 0 when the low bits are masked + if (hash == 0) + hash = 0x80000000; + + return hash; +} + +#ifndef NDEBUG +void UString::Rep::checkConsistency() const +{ + const UString::BaseString* base = baseString(); + + // There is no recursion for base strings. + ASSERT(base == base->baseString()); + + if (isStatic()) { + // There are only two static strings: null and empty. + ASSERT(!len); + + // Static strings cannot get in identifier tables, because they are globally shared. + ASSERT(!identifierTable()); + } + + // The string fits in buffer. + ASSERT(base->usedPreCapacity <= base->preCapacity); + ASSERT(base->usedCapacity <= base->capacity); + ASSERT(-offset <= base->usedPreCapacity); + ASSERT(offset + len <= base->usedCapacity); +} +#endif + +UString::SharedUChar* UString::BaseString::sharedBuffer() +{ + if (!m_sharedBuffer) + setSharedBuffer(SharedUChar::create(new OwnFastMallocPtr<UChar>(buf))); + return m_sharedBuffer; +} + +void UString::BaseString::setSharedBuffer(PassRefPtr<UString::SharedUChar> sharedBuffer) +{ + // The manual steps below are because m_sharedBuffer can't be a RefPtr. m_sharedBuffer + // is in a union with another variable to avoid making BaseString any larger. + if (m_sharedBuffer) + m_sharedBuffer->deref(); + m_sharedBuffer = sharedBuffer.releaseRef(); +} + +bool UString::BaseString::slowIsBufferReadOnly() +{ + // The buffer may not be modified as soon as the underlying data has been shared with another class. + if (m_sharedBuffer->isShared()) + return true; + + // At this point, we know it that the underlying buffer isn't shared outside of this base class, + // so get rid of m_sharedBuffer. + OwnPtr<OwnFastMallocPtr<UChar> > mallocPtr(m_sharedBuffer->release()); + UChar* unsharedBuf = const_cast<UChar*>(mallocPtr->release()); + setSharedBuffer(0); + preCapacity += (buf - unsharedBuf); + buf = unsharedBuf; + return false; +} + +// Put these early so they can be inlined. +static inline size_t expandedSize(size_t capacitySize, size_t precapacitySize) +{ + // Combine capacitySize & precapacitySize to produce a single size to allocate, + // check that doing so does not result in overflow. + size_t size = capacitySize + precapacitySize; + if (size < capacitySize) + return overflowIndicator(); + + // Small Strings (up to 4 pages): + // Expand the allocation size to 112.5% of the amount requested. This is largely sicking + // to our previous policy, however 112.5% is cheaper to calculate. + if (size < 0x4000) { + size_t expandedSize = ((size + (size >> 3)) | 15) + 1; + // Given the limited range within which we calculate the expansion in this + // fashion the above calculation should never overflow. + ASSERT(expandedSize >= size); + ASSERT(expandedSize < maxUChars()); + return expandedSize; + } + + // Medium Strings (up to 128 pages): + // For pages covering multiple pages over-allocation is less of a concern - any unused + // space will not be paged in if it is not used, so this is purely a VM overhead. For + // these strings allocate 2x the requested size. + if (size < 0x80000) { + size_t expandedSize = ((size + size) | 0xfff) + 1; + // Given the limited range within which we calculate the expansion in this + // fashion the above calculation should never overflow. + ASSERT(expandedSize >= size); + ASSERT(expandedSize < maxUChars()); + return expandedSize; + } + + // Large Strings (to infinity and beyond!): + // Revert to our 112.5% policy - probably best to limit the amount of unused VM we allow + // any individual string be responsible for. + size_t expandedSize = ((size + (size >> 3)) | 0xfff) + 1; + + // Check for overflow - any result that is at least as large as requested (but + // still below the limit) is okay. + if ((expandedSize >= size) && (expandedSize < maxUChars())) + return expandedSize; + return overflowIndicator(); +} + +static inline bool expandCapacity(UString::Rep* rep, int requiredLength) +{ + rep->checkConsistency(); + ASSERT(!rep->baseString()->isBufferReadOnly()); + + UString::BaseString* base = rep->baseString(); + + if (requiredLength > base->capacity) { + size_t newCapacity = expandedSize(requiredLength, base->preCapacity); + UChar* oldBuf = base->buf; + base->buf = reallocChars(base->buf, newCapacity); + if (!base->buf) { + base->buf = oldBuf; + return false; + } + base->capacity = newCapacity - base->preCapacity; + } + if (requiredLength > base->usedCapacity) + base->usedCapacity = requiredLength; + + rep->checkConsistency(); + return true; +} + +bool UString::Rep::reserveCapacity(int capacity) +{ + // If this is an empty string there is no point 'growing' it - just allocate a new one. + // If the BaseString is shared with another string that is using more capacity than this + // string is, then growing the buffer won't help. + // If the BaseString's buffer is readonly, then it isn't allowed to grow. + UString::BaseString* base = baseString(); + if (!base->buf || !base->capacity || (offset + len) != base->usedCapacity || base->isBufferReadOnly()) + return false; + + // If there is already sufficient capacity, no need to grow! + if (capacity <= base->capacity) + return true; + + checkConsistency(); + + size_t newCapacity = expandedSize(capacity, base->preCapacity); + UChar* oldBuf = base->buf; + base->buf = reallocChars(base->buf, newCapacity); + if (!base->buf) { + base->buf = oldBuf; + return false; + } + base->capacity = newCapacity - base->preCapacity; + + checkConsistency(); + return true; +} + +void UString::expandCapacity(int requiredLength) +{ + if (!JSC::expandCapacity(m_rep.get(), requiredLength)) + makeNull(); +} + +void UString::expandPreCapacity(int requiredPreCap) +{ + m_rep->checkConsistency(); + ASSERT(!m_rep->baseString()->isBufferReadOnly()); + + BaseString* base = m_rep->baseString(); + + if (requiredPreCap > base->preCapacity) { + size_t newCapacity = expandedSize(requiredPreCap, base->capacity); + int delta = newCapacity - base->capacity - base->preCapacity; + + UChar* newBuf = allocChars(newCapacity); + if (!newBuf) { + makeNull(); + return; + } + copyChars(newBuf + delta, base->buf, base->capacity + base->preCapacity); + fastFree(base->buf); + base->buf = newBuf; + + base->preCapacity = newCapacity - base->capacity; + } + if (requiredPreCap > base->usedPreCapacity) + base->usedPreCapacity = requiredPreCap; + + m_rep->checkConsistency(); +} + +static PassRefPtr<UString::Rep> createRep(const char* c) +{ + if (!c) + return &UString::Rep::null(); + + if (!c[0]) + return &UString::Rep::empty(); + + size_t length = strlen(c); + UChar* d = allocChars(length); + if (!d) + return &UString::Rep::null(); + else { + for (size_t i = 0; i < length; i++) + d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend + return UString::Rep::create(d, static_cast<int>(length)); + } + +} + +UString::UString(const char* c) + : m_rep(createRep(c)) +{ +} + +UString::UString(const UChar* c, int length) +{ + if (length == 0) + m_rep = &Rep::empty(); + else + m_rep = Rep::createCopying(c, length); +} + +UString::UString(UChar* c, int length, bool copy) +{ + if (length == 0) + m_rep = &Rep::empty(); + else if (copy) + m_rep = Rep::createCopying(c, length); + else + m_rep = Rep::create(c, length); +} + +UString::UString(const Vector<UChar>& buffer) +{ + if (!buffer.size()) + m_rep = &Rep::empty(); + else + m_rep = Rep::createCopying(buffer.data(), buffer.size()); +} + +static ALWAYS_INLINE int newCapacityWithOverflowCheck(const int currentCapacity, const int extendLength, const bool plusOne = false) +{ + ASSERT_WITH_MESSAGE(extendLength >= 0, "extendedLength = %d", extendLength); + + const int plusLength = plusOne ? 1 : 0; + if (currentCapacity > std::numeric_limits<int>::max() - extendLength - plusLength) + CRASH(); + + return currentCapacity + extendLength + plusLength; +} + +static ALWAYS_INLINE PassRefPtr<UString::Rep> concatenate(PassRefPtr<UString::Rep> r, const UChar* tData, int tSize) +{ + RefPtr<UString::Rep> rep = r; + + rep->checkConsistency(); + + int thisSize = rep->size(); + int thisOffset = rep->offset; + int length = thisSize + tSize; + UString::BaseString* base = rep->baseString(); + + // possible cases: + if (tSize == 0) { + // t is empty + } else if (thisSize == 0) { + // this is empty + rep = UString::Rep::createCopying(tData, tSize); + } else if (rep == base && !base->isShared()) { + // this is direct and has refcount of 1 (so we can just alter it directly) + if (!expandCapacity(rep.get(), newCapacityWithOverflowCheck(thisOffset, length))) + rep = &UString::Rep::null(); + if (rep->data()) { + copyChars(rep->data() + thisSize, tData, tSize); + rep->len = length; + rep->_hash = 0; + } + } else if (thisOffset + thisSize == base->usedCapacity && thisSize >= minShareSize && !base->isBufferReadOnly()) { + // this reaches the end of the buffer - extend it if it's long enough to append to + if (!expandCapacity(rep.get(), newCapacityWithOverflowCheck(thisOffset, length))) + rep = &UString::Rep::null(); + if (rep->data()) { + copyChars(rep->data() + thisSize, tData, tSize); + rep = UString::Rep::create(rep, 0, length); + } + } else { + // This is shared in some way that prevents us from modifying base, so we must make a whole new string. + size_t newCapacity = expandedSize(length, 0); + UChar* d = allocChars(newCapacity); + if (!d) + rep = &UString::Rep::null(); + else { + copyChars(d, rep->data(), thisSize); + copyChars(d + thisSize, tData, tSize); + rep = UString::Rep::create(d, length); + rep->baseString()->capacity = newCapacity; + } + } + + rep->checkConsistency(); + + return rep.release(); +} + +static ALWAYS_INLINE PassRefPtr<UString::Rep> concatenate(PassRefPtr<UString::Rep> r, const char* t) +{ + RefPtr<UString::Rep> rep = r; + + rep->checkConsistency(); + + int thisSize = rep->size(); + int thisOffset = rep->offset; + int tSize = static_cast<int>(strlen(t)); + int length = thisSize + tSize; + UString::BaseString* base = rep->baseString(); + + // possible cases: + if (thisSize == 0) { + // this is empty + rep = createRep(t); + } else if (tSize == 0) { + // t is empty, we'll just return *this below. + } else if (rep == base && !base->isShared()) { + // this is direct and has refcount of 1 (so we can just alter it directly) + expandCapacity(rep.get(), newCapacityWithOverflowCheck(thisOffset, length)); + UChar* d = rep->data(); + if (d) { + for (int i = 0; i < tSize; ++i) + d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend + rep->len = length; + rep->_hash = 0; + } + } else if (thisOffset + thisSize == base->usedCapacity && thisSize >= minShareSize && !base->isBufferReadOnly()) { + // this string reaches the end of the buffer - extend it + expandCapacity(rep.get(), newCapacityWithOverflowCheck(thisOffset, length)); + UChar* d = rep->data(); + if (d) { + for (int i = 0; i < tSize; ++i) + d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend + rep = UString::Rep::create(rep, 0, length); + } + } else { + // This is shared in some way that prevents us from modifying base, so we must make a whole new string. + size_t newCapacity = expandedSize(length, 0); + UChar* d = allocChars(newCapacity); + if (!d) + rep = &UString::Rep::null(); + else { + copyChars(d, rep->data(), thisSize); + for (int i = 0; i < tSize; ++i) + d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend + rep = UString::Rep::create(d, length); + rep->baseString()->capacity = newCapacity; + } + } + + rep->checkConsistency(); + + return rep.release(); +} + +PassRefPtr<UString::Rep> concatenate(UString::Rep* a, UString::Rep* b) +{ + a->checkConsistency(); + b->checkConsistency(); + + int aSize = a->size(); + int bSize = b->size(); + int aOffset = a->offset; + + // possible cases: + + UString::BaseString* aBase = a->baseString(); + if (bSize == 1 && aOffset + aSize == aBase->usedCapacity && aOffset + aSize < aBase->capacity && !aBase->isBufferReadOnly()) { + // b is a single character (common fast case) + ++aBase->usedCapacity; + a->data()[aSize] = b->data()[0]; + return UString::Rep::create(a, 0, aSize + 1); + } + + // a is empty + if (aSize == 0) + return b; + // b is empty + if (bSize == 0) + return a; + + int bOffset = b->offset; + int length = aSize + bSize; + + UString::BaseString* bBase = b->baseString(); + if (aOffset + aSize == aBase->usedCapacity && aSize >= minShareSize && 4 * aSize >= bSize + && (-bOffset != bBase->usedPreCapacity || aSize >= bSize) && !aBase->isBufferReadOnly()) { + // - a reaches the end of its buffer so it qualifies for shared append + // - also, it's at least a quarter the length of b - appending to a much shorter + // string does more harm than good + // - however, if b qualifies for prepend and is longer than a, we'd rather prepend + + UString x(a); + x.expandCapacity(newCapacityWithOverflowCheck(aOffset, length)); + if (!a->data() || !x.data()) + return 0; + copyChars(a->data() + aSize, b->data(), bSize); + PassRefPtr<UString::Rep> result = UString::Rep::create(a, 0, length); + + a->checkConsistency(); + b->checkConsistency(); + result->checkConsistency(); + + return result; + } + + if (-bOffset == bBase->usedPreCapacity && bSize >= minShareSize && 4 * bSize >= aSize && !bBase->isBufferReadOnly()) { + // - b reaches the beginning of its buffer so it qualifies for shared prepend + // - also, it's at least a quarter the length of a - prepending to a much shorter + // string does more harm than good + UString y(b); + y.expandPreCapacity(-bOffset + aSize); + if (!b->data() || !y.data()) + return 0; + copyChars(b->data() - aSize, a->data(), aSize); + PassRefPtr<UString::Rep> result = UString::Rep::create(b, -aSize, length); + + a->checkConsistency(); + b->checkConsistency(); + result->checkConsistency(); + + return result; + } + + // a does not qualify for append, and b does not qualify for prepend, gotta make a whole new string + size_t newCapacity = expandedSize(length, 0); + UChar* d = allocChars(newCapacity); + if (!d) + return 0; + copyChars(d, a->data(), aSize); + copyChars(d + aSize, b->data(), bSize); + PassRefPtr<UString::Rep> result = UString::Rep::create(d, length); + result->baseString()->capacity = newCapacity; + + a->checkConsistency(); + b->checkConsistency(); + result->checkConsistency(); + + return result; +} + +PassRefPtr<UString::Rep> concatenate(UString::Rep* rep, int i) +{ + UChar buf[1 + sizeof(i) * 3]; + UChar* end = buf + sizeof(buf) / sizeof(UChar); + UChar* p = end; + + if (i == 0) + *--p = '0'; + else if (i == INT_MIN) { + char minBuf[1 + sizeof(i) * 3]; + sprintf(minBuf, "%d", INT_MIN); + return concatenate(rep, minBuf); + } else { + bool negative = false; + if (i < 0) { + negative = true; + i = -i; + } + while (i) { + *--p = static_cast<unsigned short>((i % 10) + '0'); + i /= 10; + } + if (negative) + *--p = '-'; + } + + return concatenate(rep, p, static_cast<int>(end - p)); + +} + +PassRefPtr<UString::Rep> concatenate(UString::Rep* rep, double d) +{ + // avoid ever printing -NaN, in JS conceptually there is only one NaN value + if (isnan(d)) + return concatenate(rep, "NaN"); + + if (d == 0.0) // stringify -0 as 0 + d = 0.0; + + char buf[80]; + int decimalPoint; + int sign; + + char result[80]; + WTF::dtoa(result, d, 0, &decimalPoint, &sign, NULL); + int length = static_cast<int>(strlen(result)); + + int i = 0; + if (sign) + buf[i++] = '-'; + + if (decimalPoint <= 0 && decimalPoint > -6) { + buf[i++] = '0'; + buf[i++] = '.'; + for (int j = decimalPoint; j < 0; j++) + buf[i++] = '0'; + strcpy(buf + i, result); + } else if (decimalPoint <= 21 && decimalPoint > 0) { + if (length <= decimalPoint) { + strcpy(buf + i, result); + i += length; + for (int j = 0; j < decimalPoint - length; j++) + buf[i++] = '0'; + buf[i] = '\0'; + } else { + strncpy(buf + i, result, decimalPoint); + i += decimalPoint; + buf[i++] = '.'; + strcpy(buf + i, result + decimalPoint); + } + } else if (result[0] < '0' || result[0] > '9') + strcpy(buf + i, result); + else { + buf[i++] = result[0]; + if (length > 1) { + buf[i++] = '.'; + strcpy(buf + i, result + 1); + i += length - 1; + } + + buf[i++] = 'e'; + buf[i++] = (decimalPoint >= 0) ? '+' : '-'; + // decimalPoint can't be more than 3 digits decimal given the + // nature of float representation + int exponential = decimalPoint - 1; + if (exponential < 0) + exponential = -exponential; + if (exponential >= 100) + buf[i++] = static_cast<char>('0' + exponential / 100); + if (exponential >= 10) + buf[i++] = static_cast<char>('0' + (exponential % 100) / 10); + buf[i++] = static_cast<char>('0' + exponential % 10); + buf[i++] = '\0'; + } + + return concatenate(rep, buf); +} + +UString UString::from(int i) +{ + UChar buf[1 + sizeof(i) * 3]; + UChar* end = buf + sizeof(buf) / sizeof(UChar); + UChar* p = end; + + if (i == 0) + *--p = '0'; + else if (i == INT_MIN) { + char minBuf[1 + sizeof(i) * 3]; + sprintf(minBuf, "%d", INT_MIN); + return UString(minBuf); + } else { + bool negative = false; + if (i < 0) { + negative = true; + i = -i; + } + while (i) { + *--p = static_cast<unsigned short>((i % 10) + '0'); + i /= 10; + } + if (negative) + *--p = '-'; + } + + return UString(p, static_cast<int>(end - p)); +} + +#if PLATFORM(WIN_OS) && PLATFORM(X86_64) && COMPILER(MSVC) +UString UString::from(int64_t i) +{ + UChar buf[1 + sizeof(i) * 3]; + UChar* end = buf + sizeof(buf) / sizeof(UChar); + UChar* p = end; + + if (i == 0) + *--p = '0'; + else if (i == LLONG_MIN) { + char minBuf[1 + sizeof(i) * 3]; + snprintf(minBuf, sizeof(minBuf) - 1, "%I64d", LLONG_MIN); + return UString(minBuf); + } else { + bool negative = false; + if (i < 0) { + negative = true; + i = -i; + } + while (i) { + *--p = static_cast<unsigned short>((i % 10) + '0'); + i /= 10; + } + if (negative) + *--p = '-'; + } + + return UString(p, static_cast<int>(end - p)); +} +#endif + +UString UString::from(unsigned int u) +{ + UChar buf[sizeof(u) * 3]; + UChar* end = buf + sizeof(buf) / sizeof(UChar); + UChar* p = end; + + if (u == 0) + *--p = '0'; + else { + while (u) { + *--p = static_cast<unsigned short>((u % 10) + '0'); + u /= 10; + } + } + + return UString(p, static_cast<int>(end - p)); +} + +UString UString::from(long l) +{ + UChar buf[1 + sizeof(l) * 3]; + UChar* end = buf + sizeof(buf) / sizeof(UChar); + UChar* p = end; + + if (l == 0) + *--p = '0'; + else if (l == LONG_MIN) { + char minBuf[1 + sizeof(l) * 3]; + sprintf(minBuf, "%ld", LONG_MIN); + return UString(minBuf); + } else { + bool negative = false; + if (l < 0) { + negative = true; + l = -l; + } + while (l) { + *--p = static_cast<unsigned short>((l % 10) + '0'); + l /= 10; + } + if (negative) + *--p = '-'; + } + + return UString(p, static_cast<int>(end - p)); +} + +UString UString::from(double d) +{ + // avoid ever printing -NaN, in JS conceptually there is only one NaN value + if (isnan(d)) + return "NaN"; + + char buf[80]; + int decimalPoint; + int sign; + + char result[80]; + WTF::dtoa(result, d, 0, &decimalPoint, &sign, NULL); + int length = static_cast<int>(strlen(result)); + + int i = 0; + if (sign) + buf[i++] = '-'; + + if (decimalPoint <= 0 && decimalPoint > -6) { + buf[i++] = '0'; + buf[i++] = '.'; + for (int j = decimalPoint; j < 0; j++) + buf[i++] = '0'; + strcpy(buf + i, result); + } else if (decimalPoint <= 21 && decimalPoint > 0) { + if (length <= decimalPoint) { + strcpy(buf + i, result); + i += length; + for (int j = 0; j < decimalPoint - length; j++) + buf[i++] = '0'; + buf[i] = '\0'; + } else { + strncpy(buf + i, result, decimalPoint); + i += decimalPoint; + buf[i++] = '.'; + strcpy(buf + i, result + decimalPoint); + } + } else if (result[0] < '0' || result[0] > '9') + strcpy(buf + i, result); + else { + buf[i++] = result[0]; + if (length > 1) { + buf[i++] = '.'; + strcpy(buf + i, result + 1); + i += length - 1; + } + + buf[i++] = 'e'; + buf[i++] = (decimalPoint >= 0) ? '+' : '-'; + // decimalPoint can't be more than 3 digits decimal given the + // nature of float representation + int exponential = decimalPoint - 1; + if (exponential < 0) + exponential = -exponential; + if (exponential >= 100) + buf[i++] = static_cast<char>('0' + exponential / 100); + if (exponential >= 10) + buf[i++] = static_cast<char>('0' + (exponential % 100) / 10); + buf[i++] = static_cast<char>('0' + exponential % 10); + buf[i++] = '\0'; + } + + return UString(buf); +} + +UString UString::spliceSubstringsWithSeparators(const Range* substringRanges, int rangeCount, const UString* separators, int separatorCount) const +{ + m_rep->checkConsistency(); + + if (rangeCount == 1 && separatorCount == 0) { + int thisSize = size(); + int position = substringRanges[0].position; + int length = substringRanges[0].length; + if (position <= 0 && length >= thisSize) + return *this; + return UString::Rep::create(m_rep, max(0, position), min(thisSize, length)); + } + + int totalLength = 0; + for (int i = 0; i < rangeCount; i++) + totalLength += substringRanges[i].length; + for (int i = 0; i < separatorCount; i++) + totalLength += separators[i].size(); + + if (totalLength == 0) + return ""; + + UChar* buffer = allocChars(totalLength); + if (!buffer) + return null(); + + int maxCount = max(rangeCount, separatorCount); + int bufferPos = 0; + for (int i = 0; i < maxCount; i++) { + if (i < rangeCount) { + copyChars(buffer + bufferPos, data() + substringRanges[i].position, substringRanges[i].length); + bufferPos += substringRanges[i].length; + } + if (i < separatorCount) { + copyChars(buffer + bufferPos, separators[i].data(), separators[i].size()); + bufferPos += separators[i].size(); + } + } + + return UString::Rep::create(buffer, totalLength); +} + +UString UString::replaceRange(int rangeStart, int rangeLength, const UString& replacement) const +{ + m_rep->checkConsistency(); + + int replacementLength = replacement.size(); + int totalLength = size() - rangeLength + replacementLength; + if (totalLength == 0) + return ""; + + UChar* buffer = allocChars(totalLength); + if (!buffer) + return null(); + + copyChars(buffer, data(), rangeStart); + copyChars(buffer + rangeStart, replacement.data(), replacementLength); + int rangeEnd = rangeStart + rangeLength; + copyChars(buffer + rangeStart + replacementLength, data() + rangeEnd, size() - rangeEnd); + + return UString::Rep::create(buffer, totalLength); +} + + +UString& UString::append(const UString &t) +{ + m_rep->checkConsistency(); + t.rep()->checkConsistency(); + + int thisSize = size(); + int thisOffset = m_rep->offset; + int tSize = t.size(); + int length = thisSize + tSize; + BaseString* base = m_rep->baseString(); + + // possible cases: + if (thisSize == 0) { + // this is empty + *this = t; + } else if (tSize == 0) { + // t is empty + } else if (m_rep == base && !base->isShared()) { + // this is direct and has refcount of 1 (so we can just alter it directly) + expandCapacity(newCapacityWithOverflowCheck(thisOffset, length)); + if (data()) { + copyChars(m_rep->data() + thisSize, t.data(), tSize); + m_rep->len = length; + m_rep->_hash = 0; + } + } else if (thisOffset + thisSize == base->usedCapacity && thisSize >= minShareSize && !base->isBufferReadOnly()) { + // this reaches the end of the buffer - extend it if it's long enough to append to + expandCapacity(newCapacityWithOverflowCheck(thisOffset, length)); + if (data()) { + copyChars(m_rep->data() + thisSize, t.data(), tSize); + m_rep = Rep::create(m_rep, 0, length); + } + } else { + // This is shared in some way that prevents us from modifying base, so we must make a whole new string. + size_t newCapacity = expandedSize(length, 0); + UChar* d = allocChars(newCapacity); + if (!d) + makeNull(); + else { + copyChars(d, data(), thisSize); + copyChars(d + thisSize, t.data(), tSize); + m_rep = Rep::create(d, length); + m_rep->baseString()->capacity = newCapacity; + } + } + + m_rep->checkConsistency(); + t.rep()->checkConsistency(); + + return *this; +} + +UString& UString::append(const UChar* tData, int tSize) +{ + m_rep = concatenate(m_rep.release(), tData, tSize); + return *this; +} + +UString& UString::appendNumeric(int i) +{ + m_rep = concatenate(rep(), i); + return *this; +} + +UString& UString::appendNumeric(double d) +{ + m_rep = concatenate(rep(), d); + return *this; +} + +UString& UString::append(const char* t) +{ + m_rep = concatenate(m_rep.release(), t); + return *this; +} + +UString& UString::append(UChar c) +{ + m_rep->checkConsistency(); + + int thisOffset = m_rep->offset; + int length = size(); + BaseString* base = m_rep->baseString(); + + // possible cases: + if (length == 0) { + // this is empty - must make a new m_rep because we don't want to pollute the shared empty one + size_t newCapacity = expandedSize(1, 0); + UChar* d = allocChars(newCapacity); + if (!d) + makeNull(); + else { + d[0] = c; + m_rep = Rep::create(d, 1); + m_rep->baseString()->capacity = newCapacity; + } + } else if (m_rep == base && !base->isShared()) { + // this is direct and has refcount of 1 (so we can just alter it directly) + expandCapacity(newCapacityWithOverflowCheck(thisOffset, length, true)); + UChar* d = m_rep->data(); + if (d) { + d[length] = c; + m_rep->len = length + 1; + m_rep->_hash = 0; + } + } else if (thisOffset + length == base->usedCapacity && length >= minShareSize && !base->isBufferReadOnly()) { + // this reaches the end of the string - extend it and share + expandCapacity(newCapacityWithOverflowCheck(thisOffset, length, true)); + UChar* d = m_rep->data(); + if (d) { + d[length] = c; + m_rep = Rep::create(m_rep, 0, length + 1); + } + } else { + // This is shared in some way that prevents us from modifying base, so we must make a whole new string. + size_t newCapacity = expandedSize(length + 1, 0); + UChar* d = allocChars(newCapacity); + if (!d) + makeNull(); + else { + copyChars(d, data(), length); + d[length] = c; + m_rep = Rep::create(d, length + 1); + m_rep->baseString()->capacity = newCapacity; + } + } + + m_rep->checkConsistency(); + + return *this; +} + +bool UString::getCString(CStringBuffer& buffer) const +{ + int length = size(); + int neededSize = length + 1; + buffer.resize(neededSize); + char* buf = buffer.data(); + + UChar ored = 0; + const UChar* p = data(); + char* q = buf; + const UChar* limit = p + length; + while (p != limit) { + UChar c = p[0]; + ored |= c; + *q = static_cast<char>(c); + ++p; + ++q; + } + *q = '\0'; + + return !(ored & 0xFF00); +} + +char* UString::ascii() const +{ + int length = size(); + int neededSize = length + 1; + delete[] statBuffer; + statBuffer = new char[neededSize]; + + const UChar* p = data(); + char* q = statBuffer; + const UChar* limit = p + length; + while (p != limit) { + *q = static_cast<char>(p[0]); + ++p; + ++q; + } + *q = '\0'; + + return statBuffer; +} + +UString& UString::operator=(const char* c) +{ + if (!c) { + m_rep = &Rep::null(); + return *this; + } + + if (!c[0]) { + m_rep = &Rep::empty(); + return *this; + } + + int l = static_cast<int>(strlen(c)); + UChar* d; + BaseString* base = m_rep->baseString(); + if (!base->isShared() && l <= base->capacity && m_rep == base && m_rep->offset == 0 && base->preCapacity == 0) { + d = base->buf; + m_rep->_hash = 0; + m_rep->len = l; + } else { + d = allocChars(l); + if (!d) { + makeNull(); + return *this; + } + m_rep = Rep::create(d, l); + } + for (int i = 0; i < l; i++) + d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend + + return *this; +} + +bool UString::is8Bit() const +{ + const UChar* u = data(); + const UChar* limit = u + size(); + while (u < limit) { + if (u[0] > 0xFF) + return false; + ++u; + } + + return true; +} + +UChar UString::operator[](int pos) const +{ + if (pos >= size()) + return '\0'; + return data()[pos]; +} + +double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const +{ + if (size() == 1) { + UChar c = data()[0]; + if (isASCIIDigit(c)) + return c - '0'; + if (isASCIISpace(c) && tolerateEmptyString) + return 0; + return NaN; + } + + // FIXME: If tolerateTrailingJunk is true, then we want to tolerate non-8-bit junk + // after the number, so this is too strict a check. + CStringBuffer s; + if (!getCString(s)) + return NaN; + const char* c = s.data(); + + // skip leading white space + while (isASCIISpace(*c)) + c++; + + // empty string ? + if (*c == '\0') + return tolerateEmptyString ? 0.0 : NaN; + + double d; + + // hex number ? + if (*c == '0' && (*(c + 1) == 'x' || *(c + 1) == 'X')) { + const char* firstDigitPosition = c + 2; + c++; + d = 0.0; + while (*(++c)) { + if (*c >= '0' && *c <= '9') + d = d * 16.0 + *c - '0'; + else if ((*c >= 'A' && *c <= 'F') || (*c >= 'a' && *c <= 'f')) + d = d * 16.0 + (*c & 0xdf) - 'A' + 10.0; + else + break; + } + + if (d >= mantissaOverflowLowerBound) + d = parseIntOverflow(firstDigitPosition, c - firstDigitPosition, 16); + } else { + // regular number ? + char* end; + d = WTF::strtod(c, &end); + if ((d != 0.0 || end != c) && d != Inf && d != -Inf) { + c = end; + } else { + double sign = 1.0; + + if (*c == '+') + c++; + else if (*c == '-') { + sign = -1.0; + c++; + } + + // We used strtod() to do the conversion. However, strtod() handles + // infinite values slightly differently than JavaScript in that it + // converts the string "inf" with any capitalization to infinity, + // whereas the ECMA spec requires that it be converted to NaN. + + if (c[0] == 'I' && c[1] == 'n' && c[2] == 'f' && c[3] == 'i' && c[4] == 'n' && c[5] == 'i' && c[6] == 't' && c[7] == 'y') { + d = sign * Inf; + c += 8; + } else if ((d == Inf || d == -Inf) && *c != 'I' && *c != 'i') + c = end; + else + return NaN; + } + } + + // allow trailing white space + while (isASCIISpace(*c)) + c++; + // don't allow anything after - unless tolerant=true + if (!tolerateTrailingJunk && *c != '\0') + d = NaN; + + return d; +} + +double UString::toDouble(bool tolerateTrailingJunk) const +{ + return toDouble(tolerateTrailingJunk, true); +} + +double UString::toDouble() const +{ + return toDouble(false, true); +} + +uint32_t UString::toUInt32(bool* ok) const +{ + double d = toDouble(); + bool b = true; + + if (d != static_cast<uint32_t>(d)) { + b = false; + d = 0; + } + + if (ok) + *ok = b; + + return static_cast<uint32_t>(d); +} + +uint32_t UString::toUInt32(bool* ok, bool tolerateEmptyString) const +{ + double d = toDouble(false, tolerateEmptyString); + bool b = true; + + if (d != static_cast<uint32_t>(d)) { + b = false; + d = 0; + } + + if (ok) + *ok = b; + + return static_cast<uint32_t>(d); +} + +uint32_t UString::toStrictUInt32(bool* ok) const +{ + if (ok) + *ok = false; + + // Empty string is not OK. + int len = m_rep->len; + if (len == 0) + return 0; + const UChar* p = m_rep->data(); + unsigned short c = p[0]; + + // If the first digit is 0, only 0 itself is OK. + if (c == '0') { + if (len == 1 && ok) + *ok = true; + return 0; + } + + // Convert to UInt32, checking for overflow. + uint32_t i = 0; + while (1) { + // Process character, turning it into a digit. + if (c < '0' || c > '9') + return 0; + const unsigned d = c - '0'; + + // Multiply by 10, checking for overflow out of 32 bits. + if (i > 0xFFFFFFFFU / 10) + return 0; + i *= 10; + + // Add in the digit, checking for overflow out of 32 bits. + const unsigned max = 0xFFFFFFFFU - d; + if (i > max) + return 0; + i += d; + + // Handle end of string. + if (--len == 0) { + if (ok) + *ok = true; + return i; + } + + // Get next character. + c = *(++p); + } +} + +int UString::find(const UString& f, int pos) const +{ + int fsz = f.size(); + + if (pos < 0) + pos = 0; + + if (fsz == 1) { + UChar ch = f[0]; + const UChar* end = data() + size(); + for (const UChar* c = data() + pos; c < end; c++) { + if (*c == ch) + return static_cast<int>(c - data()); + } + return -1; + } + + int sz = size(); + if (sz < fsz) + return -1; + if (fsz == 0) + return pos; + const UChar* end = data() + sz - fsz; + int fsizeminusone = (fsz - 1) * sizeof(UChar); + const UChar* fdata = f.data(); + unsigned short fchar = fdata[0]; + ++fdata; + for (const UChar* c = data() + pos; c <= end; c++) { + if (c[0] == fchar && !memcmp(c + 1, fdata, fsizeminusone)) + return static_cast<int>(c - data()); + } + + return -1; +} + +int UString::find(UChar ch, int pos) const +{ + if (pos < 0) + pos = 0; + const UChar* end = data() + size(); + for (const UChar* c = data() + pos; c < end; c++) { + if (*c == ch) + return static_cast<int>(c - data()); + } + + return -1; +} + +int UString::rfind(const UString& f, int pos) const +{ + int sz = size(); + int fsz = f.size(); + if (sz < fsz) + return -1; + if (pos < 0) + pos = 0; + if (pos > sz - fsz) + pos = sz - fsz; + if (fsz == 0) + return pos; + int fsizeminusone = (fsz - 1) * sizeof(UChar); + const UChar* fdata = f.data(); + for (const UChar* c = data() + pos; c >= data(); c--) { + if (*c == *fdata && !memcmp(c + 1, fdata + 1, fsizeminusone)) + return static_cast<int>(c - data()); + } + + return -1; +} + +int UString::rfind(UChar ch, int pos) const +{ + if (isEmpty()) + return -1; + if (pos + 1 >= size()) + pos = size() - 1; + for (const UChar* c = data() + pos; c >= data(); c--) { + if (*c == ch) + return static_cast<int>(c - data()); + } + + return -1; +} + +UString UString::substr(int pos, int len) const +{ + int s = size(); + + if (pos < 0) + pos = 0; + else if (pos >= s) + pos = s; + if (len < 0) + len = s; + if (pos + len >= s) + len = s - pos; + + if (pos == 0 && len == s) + return *this; + + return UString(Rep::create(m_rep, pos, len)); +} + +bool operator==(const UString& s1, const char *s2) +{ + if (s2 == 0) + return s1.isEmpty(); + + const UChar* u = s1.data(); + const UChar* uend = u + s1.size(); + while (u != uend && *s2) { + if (u[0] != (unsigned char)*s2) + return false; + s2++; + u++; + } + + return u == uend && *s2 == 0; +} + +bool operator<(const UString& s1, const UString& s2) +{ + const int l1 = s1.size(); + const int l2 = s2.size(); + const int lmin = l1 < l2 ? l1 : l2; + const UChar* c1 = s1.data(); + const UChar* c2 = s2.data(); + int l = 0; + while (l < lmin && *c1 == *c2) { + c1++; + c2++; + l++; + } + if (l < lmin) + return (c1[0] < c2[0]); + + return (l1 < l2); +} + +bool operator>(const UString& s1, const UString& s2) +{ + const int l1 = s1.size(); + const int l2 = s2.size(); + const int lmin = l1 < l2 ? l1 : l2; + const UChar* c1 = s1.data(); + const UChar* c2 = s2.data(); + int l = 0; + while (l < lmin && *c1 == *c2) { + c1++; + c2++; + l++; + } + if (l < lmin) + return (c1[0] > c2[0]); + + return (l1 > l2); +} + +int compare(const UString& s1, const UString& s2) +{ + const int l1 = s1.size(); + const int l2 = s2.size(); + const int lmin = l1 < l2 ? l1 : l2; + const UChar* c1 = s1.data(); + const UChar* c2 = s2.data(); + int l = 0; + while (l < lmin && *c1 == *c2) { + c1++; + c2++; + l++; + } + + if (l < lmin) + return (c1[0] > c2[0]) ? 1 : -1; + + if (l1 == l2) + return 0; + + return (l1 > l2) ? 1 : -1; +} + +bool equal(const UString::Rep* r, const UString::Rep* b) +{ + int length = r->len; + if (length != b->len) + return false; + const UChar* d = r->data(); + const UChar* s = b->data(); + for (int i = 0; i != length; ++i) { + if (d[i] != s[i]) + return false; + } + return true; +} + +CString UString::UTF8String(bool strict) const +{ + // Allocate a buffer big enough to hold all the characters. + const int length = size(); + Vector<char, 1024> buffer(length * 3); + + // Convert to runs of 8-bit characters. + char* p = buffer.data(); + const UChar* d = reinterpret_cast<const UChar*>(&data()[0]); + ConversionResult result = convertUTF16ToUTF8(&d, d + length, &p, p + buffer.size(), strict); + if (result != conversionOK) + return CString(); + + return CString(buffer.data(), p - buffer.data()); +} + +// For use in error handling code paths -- having this not be inlined helps avoid PIC branches to fetch the global on Mac OS X. +NEVER_INLINE void UString::makeNull() +{ + m_rep = &Rep::null(); +} + +// For use in error handling code paths -- having this not be inlined helps avoid PIC branches to fetch the global on Mac OS X. +NEVER_INLINE UString::Rep* UString::nullRep() +{ + return &Rep::null(); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/UString.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/UString.h new file mode 100644 index 0000000..ab64f52 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/UString.h @@ -0,0 +1,604 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef UString_h +#define UString_h + +#include "Collector.h" +#include <stdint.h> +#include <string.h> +#include <wtf/Assertions.h> +#include <wtf/CrossThreadRefCounted.h> +#include <wtf/OwnFastMallocPtr.h> +#include <wtf/PassRefPtr.h> +#include <wtf/PtrAndFlags.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> +#include <wtf/unicode/Unicode.h> + +namespace JSC { + + using WTF::PlacementNewAdoptType; + using WTF::PlacementNewAdopt; + + class IdentifierTable; + + class CString { + public: + CString() + : m_length(0) + , m_data(0) + { + } + + CString(const char*); + CString(const char*, size_t); + CString(const CString&); + + ~CString(); + + static CString adopt(char*, size_t); // buffer should be allocated with new[]. + + CString& append(const CString&); + CString& operator=(const char* c); + CString& operator=(const CString&); + CString& operator+=(const CString& c) { return append(c); } + + size_t size() const { return m_length; } + const char* c_str() const { return m_data; } + + private: + size_t m_length; + char* m_data; + }; + + typedef Vector<char, 32> CStringBuffer; + + class UString { + friend class JIT; + + public: + + typedef CrossThreadRefCounted<OwnFastMallocPtr<UChar> > SharedUChar; + struct BaseString; + struct Rep : Noncopyable { + friend class JIT; + + static PassRefPtr<Rep> create(UChar* buffer, int length) + { + return adoptRef(new BaseString(buffer, length)); + } + + static PassRefPtr<Rep> createEmptyBuffer(size_t size) + { + // Guard against integer overflow + if (size < (std::numeric_limits<size_t>::max() / sizeof(UChar))) { + if (void * buf = tryFastMalloc(size * sizeof(UChar))) + return adoptRef(new BaseString(static_cast<UChar*>(buf), 0, size)); + } + return adoptRef(new BaseString(0, 0, 0)); + } + + static PassRefPtr<Rep> createCopying(const UChar*, int); + static PassRefPtr<Rep> create(PassRefPtr<Rep> base, int offset, int length); + + // Constructs a string from a UTF-8 string, using strict conversion (see comments in UTF8.h). + // Returns UString::Rep::null for null input or conversion failure. + static PassRefPtr<Rep> createFromUTF8(const char*); + + // Uses SharedUChar to have joint ownership over the UChar*. + static PassRefPtr<Rep> create(UChar*, int, PassRefPtr<SharedUChar>); + + SharedUChar* sharedBuffer(); + void destroy(); + + bool baseIsSelf() const { return m_identifierTableAndFlags.isFlagSet(BaseStringFlag); } + UChar* data() const; + int size() const { return len; } + + unsigned hash() const { if (_hash == 0) _hash = computeHash(data(), len); return _hash; } + unsigned computedHash() const { ASSERT(_hash); return _hash; } // fast path for Identifiers + + static unsigned computeHash(const UChar*, int length); + static unsigned computeHash(const char*, int length); + static unsigned computeHash(const char* s) { return computeHash(s, strlen(s)); } + + IdentifierTable* identifierTable() const { return m_identifierTableAndFlags.get(); } + void setIdentifierTable(IdentifierTable* table) { ASSERT(!isStatic()); m_identifierTableAndFlags.set(table); } + + bool isStatic() const { return m_identifierTableAndFlags.isFlagSet(StaticFlag); } + void setStatic(bool); + void setBaseString(PassRefPtr<BaseString>); + BaseString* baseString(); + const BaseString* baseString() const; + + Rep* ref() { ++rc; return this; } + ALWAYS_INLINE void deref() { if (--rc == 0) destroy(); } + + void checkConsistency() const; + enum UStringFlags { + StaticFlag, + BaseStringFlag + }; + + // unshared data + int offset; + int len; + int rc; // For null and empty static strings, this field does not reflect a correct count, because ref/deref are not thread-safe. A special case in destroy() guarantees that these do not get deleted. + mutable unsigned _hash; + PtrAndFlags<IdentifierTable, UStringFlags> m_identifierTableAndFlags; + + static BaseString& null() { return *nullBaseString; } + static BaseString& empty() { return *emptyBaseString; } + + bool reserveCapacity(int capacity); + + protected: + // Constructor for use by BaseString subclass; they use the union with m_baseString for another purpose. + Rep(int length) + : offset(0) + , len(length) + , rc(1) + , _hash(0) + , m_baseString(0) + { + } + + Rep(PassRefPtr<BaseString> base, int offsetInBase, int length) + : offset(offsetInBase) + , len(length) + , rc(1) + , _hash(0) + , m_baseString(base.releaseRef()) + { + checkConsistency(); + } + + union { + // If !baseIsSelf() + BaseString* m_baseString; + // If baseIsSelf() + SharedUChar* m_sharedBuffer; + }; + + private: + // For SmallStringStorage which allocates an array and does initialization manually. + Rep() { } + + friend class SmallStringsStorage; + friend void initializeUString(); + JS_EXPORTDATA static BaseString* nullBaseString; + JS_EXPORTDATA static BaseString* emptyBaseString; + }; + + + struct BaseString : public Rep { + bool isShared() { return rc != 1 || isBufferReadOnly(); } + void setSharedBuffer(PassRefPtr<SharedUChar>); + + bool isBufferReadOnly() + { + if (!m_sharedBuffer) + return false; + return slowIsBufferReadOnly(); + } + + // potentially shared data. + UChar* buf; + int preCapacity; + int usedPreCapacity; + int capacity; + int usedCapacity; + + size_t reportedCost; + + private: + BaseString(UChar* buffer, int length, int additionalCapacity = 0) + : Rep(length) + , buf(buffer) + , preCapacity(0) + , usedPreCapacity(0) + , capacity(length + additionalCapacity) + , usedCapacity(length) + , reportedCost(0) + { + m_identifierTableAndFlags.setFlag(BaseStringFlag); + checkConsistency(); + } + + SharedUChar* sharedBuffer(); + bool slowIsBufferReadOnly(); + + friend struct Rep; + friend class SmallStringsStorage; + friend void initializeUString(); + }; + + public: + UString(); + UString(const char*); + UString(const UChar*, int length); + UString(UChar*, int length, bool copy); + + UString(const UString& s) + : m_rep(s.m_rep) + { + } + + UString(const Vector<UChar>& buffer); + + ~UString() + { + } + + // Special constructor for cases where we overwrite an object in place. + UString(PlacementNewAdoptType) + : m_rep(PlacementNewAdopt) + { + } + + static UString from(int); +#if PLATFORM(WIN_OS) && PLATFORM(X86_64) && COMPILER(MSVC) + static UString from(int64_t i); +#endif + static UString from(unsigned int); + static UString from(long); + static UString from(double); + + struct Range { + public: + Range(int pos, int len) + : position(pos) + , length(len) + { + } + + Range() + { + } + + int position; + int length; + }; + + UString spliceSubstringsWithSeparators(const Range* substringRanges, int rangeCount, const UString* separators, int separatorCount) const; + + UString replaceRange(int rangeStart, int RangeEnd, const UString& replacement) const; + + UString& append(const UString&); + UString& append(const char*); + UString& append(UChar); + UString& append(char c) { return append(static_cast<UChar>(static_cast<unsigned char>(c))); } + UString& append(const UChar*, int size); + UString& appendNumeric(int); + UString& appendNumeric(double); + + bool getCString(CStringBuffer&) const; + + // NOTE: This method should only be used for *debugging* purposes as it + // is neither Unicode safe nor free from side effects nor thread-safe. + char* ascii() const; + + /** + * Convert the string to UTF-8, assuming it is UTF-16 encoded. + * In non-strict mode, this function is tolerant of badly formed UTF-16, it + * can create UTF-8 strings that are invalid because they have characters in + * the range U+D800-U+DDFF, U+FFFE, or U+FFFF, but the UTF-8 string is + * guaranteed to be otherwise valid. + * In strict mode, error is returned as null CString. + */ + CString UTF8String(bool strict = false) const; + + UString& operator=(const char*c); + + UString& operator+=(const UString& s) { return append(s); } + UString& operator+=(const char* s) { return append(s); } + + const UChar* data() const { return m_rep->data(); } + + bool isNull() const { return (m_rep == &Rep::null()); } + bool isEmpty() const { return (!m_rep->len); } + + bool is8Bit() const; + + int size() const { return m_rep->size(); } + + UChar operator[](int pos) const; + + double toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const; + double toDouble(bool tolerateTrailingJunk) const; + double toDouble() const; + + uint32_t toUInt32(bool* ok = 0) const; + uint32_t toUInt32(bool* ok, bool tolerateEmptyString) const; + uint32_t toStrictUInt32(bool* ok = 0) const; + + unsigned toArrayIndex(bool* ok = 0) const; + + int find(const UString& f, int pos = 0) const; + int find(UChar, int pos = 0) const; + int rfind(const UString& f, int pos) const; + int rfind(UChar, int pos) const; + + UString substr(int pos = 0, int len = -1) const; + + static const UString& null() { return *nullUString; } + + Rep* rep() const { return m_rep.get(); } + static Rep* nullRep(); + + UString(PassRefPtr<Rep> r) + : m_rep(r) + { + ASSERT(m_rep); + } + + size_t cost() const; + + // Attempt to grow this string such that it can grow to a total length of 'capacity' + // without reallocation. This may fail a number of reasons - if the BasicString is + // shared and another string is using part of the capacity beyond our end point, if + // the realloc fails, or if this string is empty and has no storage. + // + // This method returns a boolean indicating success. + bool reserveCapacity(int capacity) + { + return m_rep->reserveCapacity(capacity); + } + +#if PLATFORM(QT) + operator QT_PREPEND_NAMESPACE(QString)() const + { + QT_USE_NAMESPACE; + return QString(reinterpret_cast<const QChar*>(this->data()), this->size()); + } + + UString(const QT_PREPEND_NAMESPACE(QString)& str) + { + *this = JSC::UString(reinterpret_cast<const UChar*>(str.constData()), str.length()); + } +#endif + + + private: + void expandCapacity(int requiredLength); + void expandPreCapacity(int requiredPreCap); + void makeNull(); + + RefPtr<Rep> m_rep; + static UString* nullUString; + + friend void initializeUString(); + friend bool operator==(const UString&, const UString&); + friend PassRefPtr<Rep> concatenate(Rep*, Rep*); // returns 0 if out of memory + }; + PassRefPtr<UString::Rep> concatenate(UString::Rep*, UString::Rep*); + PassRefPtr<UString::Rep> concatenate(UString::Rep*, int); + PassRefPtr<UString::Rep> concatenate(UString::Rep*, double); + + inline bool operator==(const UString& s1, const UString& s2) + { + int size = s1.size(); + switch (size) { + case 0: + return !s2.size(); + case 1: + return s2.size() == 1 && s1.data()[0] == s2.data()[0]; + case 2: { + if (s2.size() != 2) + return false; + const UChar* d1 = s1.data(); + const UChar* d2 = s2.data(); + return (d1[0] == d2[0]) & (d1[1] == d2[1]); + } + default: + return s2.size() == size && memcmp(s1.data(), s2.data(), size * sizeof(UChar)) == 0; + } + } + + + inline bool operator!=(const UString& s1, const UString& s2) + { + return !JSC::operator==(s1, s2); + } + + bool operator<(const UString& s1, const UString& s2); + bool operator>(const UString& s1, const UString& s2); + + bool operator==(const UString& s1, const char* s2); + + inline bool operator!=(const UString& s1, const char* s2) + { + return !JSC::operator==(s1, s2); + } + + inline bool operator==(const char *s1, const UString& s2) + { + return operator==(s2, s1); + } + + inline bool operator!=(const char *s1, const UString& s2) + { + return !JSC::operator==(s1, s2); + } + + bool operator==(const CString&, const CString&); + + inline UString operator+(const UString& s1, const UString& s2) + { + RefPtr<UString::Rep> result = concatenate(s1.rep(), s2.rep()); + return UString(result ? result.release() : UString::nullRep()); + } + + int compare(const UString&, const UString&); + + bool equal(const UString::Rep*, const UString::Rep*); + + inline PassRefPtr<UString::Rep> UString::Rep::create(PassRefPtr<UString::Rep> rep, int offset, int length) + { + ASSERT(rep); + rep->checkConsistency(); + + int repOffset = rep->offset; + + PassRefPtr<BaseString> base = rep->baseString(); + + ASSERT(-(offset + repOffset) <= base->usedPreCapacity); + ASSERT(offset + repOffset + length <= base->usedCapacity); + + // Steal the single reference this Rep was created with. + return adoptRef(new Rep(base, repOffset + offset, length)); + } + + inline UChar* UString::Rep::data() const + { + const BaseString* base = baseString(); + return base->buf + base->preCapacity + offset; + } + + inline void UString::Rep::setStatic(bool v) + { + ASSERT(!identifierTable()); + if (v) + m_identifierTableAndFlags.setFlag(StaticFlag); + else + m_identifierTableAndFlags.clearFlag(StaticFlag); + } + + inline void UString::Rep::setBaseString(PassRefPtr<BaseString> base) + { + ASSERT(base != this); + ASSERT(!baseIsSelf()); + m_baseString = base.releaseRef(); + } + + inline UString::BaseString* UString::Rep::baseString() + { + return !baseIsSelf() ? m_baseString : reinterpret_cast<BaseString*>(this) ; + } + + inline const UString::BaseString* UString::Rep::baseString() const + { + return const_cast<Rep*>(this)->baseString(); + } + +#ifdef NDEBUG + inline void UString::Rep::checkConsistency() const + { + } +#endif + + inline UString::UString() + : m_rep(&Rep::null()) + { + } + + // Rule from ECMA 15.2 about what an array index is. + // Must exactly match string form of an unsigned integer, and be less than 2^32 - 1. + inline unsigned UString::toArrayIndex(bool* ok) const + { + unsigned i = toStrictUInt32(ok); + if (ok && i >= 0xFFFFFFFFU) + *ok = false; + return i; + } + + // We'd rather not do shared substring append for small strings, since + // this runs too much risk of a tiny initial string holding down a + // huge buffer. + // FIXME: this should be size_t but that would cause warnings until we + // fix UString sizes to be size_t instead of int + static const int minShareSize = Heap::minExtraCostSize / sizeof(UChar); + + inline size_t UString::cost() const + { + BaseString* base = m_rep->baseString(); + size_t capacity = (base->capacity + base->preCapacity) * sizeof(UChar); + size_t reportedCost = base->reportedCost; + ASSERT(capacity >= reportedCost); + + size_t capacityDelta = capacity - reportedCost; + + if (capacityDelta < static_cast<size_t>(minShareSize)) + return 0; + + base->reportedCost = capacity; + + return capacityDelta; + } + +#if PLATFORM(QT) + + inline UString operator+(const char* s1, const UString& s2) + { + return operator+(UString(s1), s2); + } + + inline UString operator+(const UString& s1, const char* s2) + { + return operator+(s1, UString(s2)); + } + +#endif + + struct IdentifierRepHash : PtrHash<RefPtr<JSC::UString::Rep> > { + static unsigned hash(const RefPtr<JSC::UString::Rep>& key) { return key->computedHash(); } + static unsigned hash(JSC::UString::Rep* key) { return key->computedHash(); } + }; + + void initializeUString(); +} // namespace JSC + +namespace WTF { + + template<typename T> struct DefaultHash; + template<typename T> struct StrHash; + + template<> struct StrHash<JSC::UString::Rep*> { + static unsigned hash(const JSC::UString::Rep* key) { return key->hash(); } + static bool equal(const JSC::UString::Rep* a, const JSC::UString::Rep* b) { return JSC::equal(a, b); } + static const bool safeToCompareToEmptyOrDeleted = false; + }; + + template<> struct StrHash<RefPtr<JSC::UString::Rep> > : public StrHash<JSC::UString::Rep*> { + using StrHash<JSC::UString::Rep*>::hash; + static unsigned hash(const RefPtr<JSC::UString::Rep>& key) { return key->hash(); } + using StrHash<JSC::UString::Rep*>::equal; + static bool equal(const RefPtr<JSC::UString::Rep>& a, const RefPtr<JSC::UString::Rep>& b) { return JSC::equal(a.get(), b.get()); } + static bool equal(const JSC::UString::Rep* a, const RefPtr<JSC::UString::Rep>& b) { return JSC::equal(a, b.get()); } + static bool equal(const RefPtr<JSC::UString::Rep>& a, const JSC::UString::Rep* b) { return JSC::equal(a.get(), b); } + + static const bool safeToCompareToEmptyOrDeleted = false; + }; + + template<> struct DefaultHash<JSC::UString::Rep*> { + typedef StrHash<JSC::UString::Rep*> Hash; + }; + + template<> struct DefaultHash<RefPtr<JSC::UString::Rep> > { + typedef StrHash<RefPtr<JSC::UString::Rep> > Hash; + + }; + +} // namespace WTF + +#endif |