diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:05:15 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:05:15 -0800 |
commit | 1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353 (patch) | |
tree | 4457a7306ea5acb43fe05bfe0973b1f7faf97ba2 /JavaScriptCore/runtime | |
parent | 9364f22aed35e1a1e9d07c121510f80be3ab0502 (diff) | |
download | external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.zip external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.gz external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.bz2 |
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'JavaScriptCore/runtime')
141 files changed, 21018 insertions, 0 deletions
diff --git a/JavaScriptCore/runtime/ArgList.cpp b/JavaScriptCore/runtime/ArgList.cpp new file mode 100644 index 0000000..7675b20 --- /dev/null +++ b/JavaScriptCore/runtime/ArgList.cpp @@ -0,0 +1,84 @@ +/* + * 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 +{ + ASSERT(!result.m_isReadOnly); + + const_iterator start = min(begin() + startIndex, end()); + result.m_vector.appendRange(start, end()); + result.m_size = result.m_vector.size(); + result.m_buffer = result.m_vector.data(); +} + +void ArgList::markLists(ListSet& markSet) +{ + ListSet::iterator end = markSet.end(); + for (ListSet::iterator it = markSet.begin(); it != end; ++it) { + ArgList* list = *it; + + iterator end2 = list->end(); + for (iterator it2 = list->begin(); it2 != end2; ++it2) + if (!(*it2).marked()) + (*it2).mark(); + } +} + +void ArgList::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/JavaScriptCore/runtime/ArgList.h b/JavaScriptCore/runtime/ArgList.h new file mode 100644 index 0000000..44446aa --- /dev/null +++ b/JavaScriptCore/runtime/ArgList.h @@ -0,0 +1,161 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2003, 2007, 2008 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 ArgList : Noncopyable { + private: + static const unsigned inlineCapacity = 8; + typedef Vector<Register, inlineCapacity> VectorType; + typedef HashSet<ArgList*> 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. + ArgList() + : 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. + ArgList(Register* buffer, size_t size) + : m_buffer(buffer) + , m_size(size) + , 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 + } + + ~ArgList() + { + if (m_markSet) + m_markSet->remove(this); + } + + size_t size() const { return m_size; } + bool isEmpty() const { return !m_size; } + + JSValue* at(ExecState* exec, size_t i) const + { + if (i < m_size) + return m_buffer[i].jsValue(exec); + return jsUndefined(); + } + + void clear() + { + m_vector.clear(); + m_buffer = 0; + m_size = 0; + } + + void append(JSValue* v) + { + ASSERT(!m_isReadOnly); + + if (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; + } + } + + void getSlice(int startIndex, ArgList& result) const; + + 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; + + 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); + }; + +} // namespace JSC + +#endif // ArgList_h diff --git a/JavaScriptCore/runtime/Arguments.cpp b/JavaScriptCore/runtime/Arguments.cpp new file mode 100644 index 0000000..fe1de62 --- /dev/null +++ b/JavaScriptCore/runtime/Arguments.cpp @@ -0,0 +1,232 @@ +/* + * 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::fillArgList(ExecState* exec, ArgList& args) +{ + 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(exec)); + for (; i < d->numArguments; ++i) + args.append(d->extraArguments[i - d->numParameters].jsValue(exec)); + 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(exec)); + else + args.append(get(exec, i)); + } + for (; i < d->numArguments; ++i) { + if (!d->deletedArguments[i]) + args.append(d->extraArguments[i - d->numParameters].jsValue(exec)); + 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(exec)); + 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(exec)); + 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] = value; + else + d->extraArguments[i - d->numParameters] = 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] = value; + else + d->extraArguments[i - d->numParameters] = 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) +{ + 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))); +} + +bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName) +{ + 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); +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/Arguments.h b/JavaScriptCore/runtime/Arguments.h new file mode 100644 index 0000000..93cc64f --- /dev/null +++ b/JavaScriptCore/runtime/Arguments.h @@ -0,0 +1,227 @@ +/* + * 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 "Machine.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]; + + JSFunction* 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*, ArgList&); + + void copyRegisters(); + bool isTornOff() const { return d->registerArray; } + void setActivation(JSActivation* activation) + { + d->activation = activation; + d->registers = &activation->registerAt(0); + } + + static PassRefPtr<StructureID> createStructureID(JSValue* prototype) + { + return StructureID::create(prototype, TypeInfo(ObjectType)); + } + + private: + void getArgumentsData(CallFrame*, JSFunction*&, 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); + virtual bool deleteProperty(ExecState*, unsigned propertyName); + + 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, JSFunction*& function, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc) + { + function = callFrame->callee(); + + CodeBlock* codeBlock = &function->m_body->generatedByteCode(); + int numParameters = codeBlock->numParameters; + 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) + { + JSFunction* callee; + ptrdiff_t firstParameterIndex; + Register* argv; + int numArguments; + getArgumentsData(callFrame, callee, firstParameterIndex, argv, numArguments); + + d->numParameters = callee->m_body->parameterCount(); + 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) + { + ASSERT(!callFrame->callee()->m_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; + 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().numParameters - 1; + size_t numVars = d()->functionBody->generatedByteCode().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/JavaScriptCore/runtime/ArrayConstructor.cpp b/JavaScriptCore/runtime/ArrayConstructor.cpp new file mode 100644 index 0000000..5784af0 --- /dev/null +++ b/JavaScriptCore/runtime/ArrayConstructor.cpp @@ -0,0 +1,84 @@ +/* + * 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 "lookup.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(ArrayConstructor); + +ArrayConstructor::ArrayConstructor(ExecState* exec, PassRefPtr<StructureID> 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(exec, 0)->isNumber()) { + uint32_t n = args.at(exec, 0)->toUInt32(exec); + if (n != args.at(exec, 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, 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* 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/JavaScriptCore/runtime/ArrayConstructor.h b/JavaScriptCore/runtime/ArrayConstructor.h new file mode 100644 index 0000000..6f0f866 --- /dev/null +++ b/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<StructureID>, ArrayPrototype*); + + virtual ConstructType getConstructData(ConstructData&); + virtual CallType getCallData(CallData&); + }; + +} // namespace JSC + +#endif // ArrayConstructor_h diff --git a/JavaScriptCore/runtime/ArrayPrototype.cpp b/JavaScriptCore/runtime/ArrayPrototype.cpp new file mode 100644 index 0000000..5280784 --- /dev/null +++ b/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -0,0 +1,794 @@ +/* + * 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 "ArrayPrototype.h" + +#include "Machine.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* arrayProtoFuncToString(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* arrayProtoFuncToLocaleString(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* arrayProtoFuncConcat(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* arrayProtoFuncJoin(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* arrayProtoFuncPop(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* arrayProtoFuncPush(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* arrayProtoFuncReverse(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* arrayProtoFuncShift(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* arrayProtoFuncSlice(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* arrayProtoFuncSort(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* arrayProtoFuncSplice(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* arrayProtoFuncUnShift(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* arrayProtoFuncEvery(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* arrayProtoFuncForEach(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* arrayProtoFuncSome(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* arrayProtoFuncIndexOf(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* arrayProtoFuncFilter(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* arrayProtoFuncMap(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* arrayProtoFuncLastIndexOf(ExecState*, JSObject*, JSValue*, const ArgList&); + +} + +#include "ArrayPrototype.lut.h" + +namespace JSC { + +// ------------------------------ 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 + map arrayProtoFuncMap DontEnum|Function 1 +@end +*/ + +// ECMA 15.4.4 +ArrayPrototype::ArrayPrototype(PassRefPtr<StructureID> 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 noValue(); + 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* 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() > MaxReentryDepth) + 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* 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() > MaxReentryDepth) + 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* arrayProtoFuncJoin(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + JSObject* thisObj = thisValue->toThisObject(exec); + + HashSet<JSObject*>& arrayVisitedElements = exec->globalData().arrayVisitedElements; + if (arrayVisitedElements.size() > MaxReentryDepth) + 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(exec, 0)->isUndefined() ? UString(&comma, 1) : args.at(exec, 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* 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)) { + JSArray* curArray = asArray(curArg); + unsigned length = curArray->length(); + for (unsigned k = 0; k < length; ++k) { + if (JSValue* v = getProperty(exec, curArray, k)) + arr->put(exec, n, v); + n++; + } + } else { + arr->put(exec, n, curArg); + n++; + } + if (it == end) + break; + curArg = (*it).jsValue(exec); + ++it; + } + arr->setLength(n); + return arr; +} + +JSValue* arrayProtoFuncPop(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&) +{ + if (exec->machine()->isJSArray(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* arrayProtoFuncPush(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + if (exec->machine()->isJSArray(thisValue) && args.size() == 1) { + JSArray* array = asArray(thisValue); + array->push(exec, args.begin()->jsValue(exec)); + 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(exec, n)); + length += args.size(); + putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(exec, length)); + return jsNumber(exec, length); +} + +JSValue* 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* 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* 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(exec, 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(exec, 1)->isUndefined()) + end = length; + else { + end = args.at(exec, 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* arrayProtoFuncSort(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + JSObject* thisObj = thisValue->toThisObject(exec); + + JSValue* function = args.at(exec, 0); + CallData callData; + CallType callType = function->getCallData(callData); + + if (thisObj->classInfo() == &JSArray::info) { + 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) { + ArgList 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* 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(exec, 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(exec, 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(exec, k + 2)); + + putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(exec, length - deleteCount + additionalArgs)); + return result; +} + +JSValue* 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(exec, k)); + JSValue* result = jsNumber(exec, length + nrArgs); + putProperty(exec, thisObj, exec->propertyNames().length, result); + return result; +} + +JSValue* arrayProtoFuncFilter(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + JSObject* thisObj = thisValue->toThisObject(exec); + + JSValue* function = args.at(exec, 0); + CallData callData; + CallType callType = function->getCallData(callData); + if (callType == CallTypeNone) + return throwError(exec, TypeError); + + JSObject* applyThis = args.at(exec, 1)->isUndefinedOrNull() ? exec->globalThisValue() : args.at(exec, 1)->toObject(exec); + JSArray* resultArray = constructEmptyArray(exec); + + unsigned filterIndex = 0; + unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec); + for (unsigned k = 0; k < length && !exec->hadException(); ++k) { + PropertySlot slot(thisObj); + + if (!thisObj->getPropertySlot(exec, k, slot)) + continue; + + JSValue* v = slot.getValue(exec, k); + + ArgList 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* arrayProtoFuncMap(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + JSObject* thisObj = thisValue->toThisObject(exec); + + JSValue* function = args.at(exec, 0); + CallData callData; + CallType callType = function->getCallData(callData); + if (callType == CallTypeNone) + return throwError(exec, TypeError); + + JSObject* applyThis = args.at(exec, 1)->isUndefinedOrNull() ? exec->globalThisValue() : args.at(exec, 1)->toObject(exec); + + unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec); + + JSArray* resultArray = constructEmptyArray(exec, length); + + for (unsigned k = 0; k < length && !exec->hadException(); ++k) { + PropertySlot slot(thisObj); + if (!thisObj->getPropertySlot(exec, k, slot)) + continue; + + JSValue* v = slot.getValue(exec, k); + + ArgList 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* arrayProtoFuncEvery(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + JSObject* thisObj = thisValue->toThisObject(exec); + + JSValue* function = args.at(exec, 0); + CallData callData; + CallType callType = function->getCallData(callData); + if (callType == CallTypeNone) + return throwError(exec, TypeError); + + JSObject* applyThis = args.at(exec, 1)->isUndefinedOrNull() ? exec->globalThisValue() : args.at(exec, 1)->toObject(exec); + + JSValue* result = jsBoolean(true); + + unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec); + for (unsigned k = 0; k < length && !exec->hadException(); ++k) { + PropertySlot slot(thisObj); + + if (!thisObj->getPropertySlot(exec, k, slot)) + continue; + + ArgList 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* arrayProtoFuncForEach(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + JSObject* thisObj = thisValue->toThisObject(exec); + + JSValue* function = args.at(exec, 0); + CallData callData; + CallType callType = function->getCallData(callData); + if (callType == CallTypeNone) + return throwError(exec, TypeError); + + JSObject* applyThis = args.at(exec, 1)->isUndefinedOrNull() ? exec->globalThisValue() : args.at(exec, 1)->toObject(exec); + + unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec); + for (unsigned k = 0; k < length && !exec->hadException(); ++k) { + PropertySlot slot(thisObj); + if (!thisObj->getPropertySlot(exec, k, slot)) + continue; + + ArgList 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* arrayProtoFuncSome(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + JSObject* thisObj = thisValue->toThisObject(exec); + + JSValue* function = args.at(exec, 0); + CallData callData; + CallType callType = function->getCallData(callData); + if (callType == CallTypeNone) + return throwError(exec, TypeError); + + JSObject* applyThis = args.at(exec, 1)->isUndefinedOrNull() ? exec->globalThisValue() : args.at(exec, 1)->toObject(exec); + + JSValue* result = jsBoolean(false); + + unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec); + for (unsigned k = 0; k < length && !exec->hadException(); ++k) { + PropertySlot slot(thisObj); + if (!thisObj->getPropertySlot(exec, k, slot)) + continue; + + ArgList 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* 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(exec, 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(exec, 0); + for (; index < length; ++index) { + JSValue* e = getProperty(exec, thisObj, index); + if (!e) + continue; + if (strictEqual(searchElement, e)) + return jsNumber(exec, index); + } + + return jsNumber(exec, -1); +} + +JSValue* 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(exec, 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(exec, 0); + for (; index >= 0; --index) { + JSValue* e = getProperty(exec, thisObj, index); + if (!e) + continue; + if (strictEqual(searchElement, e)) + return jsNumber(exec, index); + } + + return jsNumber(exec, -1); +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/ArrayPrototype.h b/JavaScriptCore/runtime/ArrayPrototype.h new file mode 100644 index 0000000..33ce30b --- /dev/null +++ b/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<StructureID>); + + 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/JavaScriptCore/runtime/BatchedTransitionOptimizer.h b/JavaScriptCore/runtime/BatchedTransitionOptimizer.h new file mode 100644 index 0000000..536d09c --- /dev/null +++ b/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 : Noncopyable { + public: + BatchedTransitionOptimizer(JSObject* object) + : m_object(object) + { + if (!m_object->structureID()->isDictionary()) + m_object->setStructureID(StructureID::toDictionaryTransition(m_object->structureID())); + } + + ~BatchedTransitionOptimizer() + { + m_object->setStructureID(StructureID::fromDictionaryTransition(m_object->structureID())); + } + + private: + JSObject* m_object; + }; + +} // namespace JSC + +#endif // BatchedTransitionOptimizer_h diff --git a/JavaScriptCore/runtime/BooleanConstructor.cpp b/JavaScriptCore/runtime/BooleanConstructor.cpp new file mode 100644 index 0000000..46a6018 --- /dev/null +++ b/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<StructureID> 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(exec, 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* callBooleanConstructor(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + return jsBoolean(args.at(exec, 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/JavaScriptCore/runtime/BooleanConstructor.h b/JavaScriptCore/runtime/BooleanConstructor.h new file mode 100644 index 0000000..3b1f1a0 --- /dev/null +++ b/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<StructureID>, 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/JavaScriptCore/runtime/BooleanObject.cpp b/JavaScriptCore/runtime/BooleanObject.cpp new file mode 100644 index 0000000..2ebfb1b --- /dev/null +++ b/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<StructureID> structure) + : JSWrapperObject(structure) +{ +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/BooleanObject.h b/JavaScriptCore/runtime/BooleanObject.h new file mode 100644 index 0000000..5963b28 --- /dev/null +++ b/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<StructureID>); + + 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/JavaScriptCore/runtime/BooleanPrototype.cpp b/JavaScriptCore/runtime/BooleanPrototype.cpp new file mode 100644 index 0000000..b47aeac --- /dev/null +++ b/JavaScriptCore/runtime/BooleanPrototype.cpp @@ -0,0 +1,82 @@ +/* + * 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 "JSString.h" +#include "ObjectPrototype.h" +#include "PrototypeFunction.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(BooleanPrototype); + +// Functions +static JSValue* booleanProtoFuncToString(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* booleanProtoFuncValueOf(ExecState*, JSObject*, JSValue*, const ArgList&); + +// ECMA 15.6.4 + +BooleanPrototype::BooleanPrototype(ExecState* exec, PassRefPtr<StructureID> structure, StructureID* prototypeFunctionStructure) + : BooleanObject(structure) +{ + setInternalValue(jsBoolean(false)); + + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 0, exec->propertyNames().toString, booleanProtoFuncToString), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 0, exec->propertyNames().valueOf, booleanProtoFuncValueOf), DontEnum); +} + + +// ------------------------------ Functions -------------------------- + +// ECMA 15.6.4.2 + 15.6.4.3 + +JSValue* 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* booleanProtoFuncValueOf(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&) +{ + if (JSImmediate::isBoolean(thisValue)) + return thisValue; + + if (!thisValue->isObject(&BooleanObject::info)) + return throwError(exec, TypeError); + + return asBooleanObject(thisValue)->internalValue(); +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/BooleanPrototype.h b/JavaScriptCore/runtime/BooleanPrototype.h new file mode 100644 index 0000000..484bb7d --- /dev/null +++ b/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<StructureID>, StructureID* prototypeFunctionStructure); + }; + +} // namespace JSC + +#endif // BooleanPrototype_h diff --git a/JavaScriptCore/runtime/CallData.cpp b/JavaScriptCore/runtime/CallData.cpp new file mode 100644 index 0000000..572c495 --- /dev/null +++ b/JavaScriptCore/runtime/CallData.cpp @@ -0,0 +1,42 @@ +/* + * 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" + +namespace JSC { + +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/JavaScriptCore/runtime/CallData.h b/JavaScriptCore/runtime/CallData.h new file mode 100644 index 0000000..5be011a --- /dev/null +++ b/JavaScriptCore/runtime/CallData.h @@ -0,0 +1,64 @@ +/* + * 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 "JSImmediate.h" + +namespace JSC { + + class ArgList; + class ExecState; + class FunctionBodyNode; + class JSObject; + class ScopeChainNode; + + enum CallType { + CallTypeNone, + CallTypeHost, + CallTypeJS + }; + + typedef JSValue* (*NativeFunction)(ExecState*, JSObject*, JSValue* thisValue, const ArgList&); + + union CallData { + struct { + NativeFunction function; + } 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/JavaScriptCore/runtime/ClassInfo.h b/JavaScriptCore/runtime/ClassInfo.h new file mode 100644 index 0000000..979145e --- /dev/null +++ b/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 "ExecState.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/JavaScriptCore/runtime/CollectorHeapIterator.h b/JavaScriptCore/runtime/CollectorHeapIterator.h new file mode 100644 index 0000000..c5e1d78 --- /dev/null +++ b/JavaScriptCore/runtime/CollectorHeapIterator.h @@ -0,0 +1,85 @@ +/* + * 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 "collector.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 diff --git a/JavaScriptCore/runtime/CommonIdentifiers.cpp b/JavaScriptCore/runtime/CommonIdentifiers.cpp new file mode 100644 index 0000000..fe0a830 --- /dev/null +++ b/JavaScriptCore/runtime/CommonIdentifiers.cpp @@ -0,0 +1,38 @@ +/* + * 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. + * + */ + +#include "config.h" +#include "CommonIdentifiers.h" + +namespace JSC { + +const char* const nullCString = 0; + +#define INITIALIZE_PROPERTY_NAME(name) , name(globalData, #name) + +CommonIdentifiers::CommonIdentifiers(JSGlobalData* globalData) + : nullIdentifier(globalData, nullCString) + , underscoreProto(globalData, "__proto__") + , thisIdentifier(globalData, "this") + JSC_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PROPERTY_NAME) +{ +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/CommonIdentifiers.h b/JavaScriptCore/runtime/CommonIdentifiers.h new file mode 100644 index 0000000..1788c77 --- /dev/null +++ b/JavaScriptCore/runtime/CommonIdentifiers.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2003,2007 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 CommonIdentifiers_h +#define CommonIdentifiers_h + +#include "identifier.h" +#include <wtf/Noncopyable.h> + +// ArgList 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(toLocaleString) \ + macro(toPrecision) \ + macro(toString) \ + macro(UTC) \ + macro(valueOf) + +namespace JSC { + + class CommonIdentifiers : Noncopyable { + private: + CommonIdentifiers(JSGlobalData*); + friend class JSGlobalData; + + public: + const Identifier nullIdentifier; + 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/JavaScriptCore/runtime/ConstructData.cpp b/JavaScriptCore/runtime/ConstructData.cpp new file mode 100644 index 0000000..88a8ef6 --- /dev/null +++ b/JavaScriptCore/runtime/ConstructData.cpp @@ -0,0 +1,42 @@ +/* + * 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" + +namespace JSC { + +JSObject* construct(ExecState* exec, JSValue* object, ConstructType constructType, const ConstructData& constructData, const ArgList& args) +{ + if (constructType == ConstructTypeHost) + return constructData.native.function(exec, asObject(object), args); + ASSERT(constructType == ConstructTypeJS); + // FIXME: Can this be done more efficiently using the constructData? + return asFunction(object)->construct(exec, args); +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/ConstructData.h b/JavaScriptCore/runtime/ConstructData.h new file mode 100644 index 0000000..3cc52a0 --- /dev/null +++ b/JavaScriptCore/runtime/ConstructData.h @@ -0,0 +1,64 @@ +/* + * 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 + +#include "JSImmediate.h" // temporary until JSValue* becomes a class we can forward-declare + +namespace JSC { + + class ArgList; + class ExecState; + class FunctionBodyNode; + class JSObject; + class ScopeChainNode; + + enum ConstructType { + ConstructTypeNone, + ConstructTypeHost, + ConstructTypeJS + }; + + typedef JSObject* (*NativeConstructor)(ExecState*, JSObject*, const ArgList&); + + union ConstructData { + struct { + NativeConstructor function; + } 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/JavaScriptCore/runtime/DateConstructor.cpp b/JavaScriptCore/runtime/DateConstructor.cpp new file mode 100644 index 0000000..8339ff3 --- /dev/null +++ b/JavaScriptCore/runtime/DateConstructor.cpp @@ -0,0 +1,175 @@ +/* + * 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 "DateInstance.h" +#include "DateMath.h" +#include "DatePrototype.h" +#include "JSGlobalObject.h" +#include "JSString.h" +#include "ObjectPrototype.h" +#include "PrototypeFunction.h" +#include <math.h> +#include <time.h> +#include <wtf/MathExtras.h> + +#if HAVE(SYS_TIME_H) +#include <sys/time.h> +#endif + +#if HAVE(SYS_TIMEB_H) +#include <sys/timeb.h> +#endif + +namespace JSC { + +// TODO: MakeTime (15.9.11.1) etc. ? + +ASSERT_CLASS_FITS_IN_CELL(DateConstructor); + +static JSValue* dateParse(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateNow(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateUTC(ExecState*, JSObject*, JSValue*, const ArgList&); + +DateConstructor::DateConstructor(ExecState* exec, PassRefPtr<StructureID> structure, StructureID* prototypeFunctionStructure, DatePrototype* datePrototype) + : InternalFunction(&exec->globalData(), structure, Identifier(exec, datePrototype->classInfo()->className)) +{ + putDirectWithoutTransition(exec->propertyNames().prototype, datePrototype, DontEnum|DontDelete|ReadOnly); + + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 1, exec->propertyNames().parse, dateParse), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 7, exec->propertyNames().UTC, dateUTC), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(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(exec, 0)->isObject(&DateInstance::info)) + value = asDateInstance(args.at(exec, 0))->internalNumber(); + else { + JSValue* primitive = args.at(exec, 0)->toPrimitive(exec); + if (primitive->isString()) + value = parseDate(primitive->getString()); + else + value = primitive->toNumber(exec); + } + } else { + if (isnan(args.at(exec, 0)->toNumber(exec)) + || isnan(args.at(exec, 1)->toNumber(exec)) + || (numArgs >= 3 && isnan(args.at(exec, 2)->toNumber(exec))) + || (numArgs >= 4 && isnan(args.at(exec, 3)->toNumber(exec))) + || (numArgs >= 5 && isnan(args.at(exec, 4)->toNumber(exec))) + || (numArgs >= 6 && isnan(args.at(exec, 5)->toNumber(exec))) + || (numArgs >= 7 && isnan(args.at(exec, 6)->toNumber(exec)))) + value = NaN; + else { + GregorianDateTime t; + int year = args.at(exec, 0)->toInt32(exec); + t.year = (year >= 0 && year <= 99) ? year : year - 1900; + t.month = args.at(exec, 1)->toInt32(exec); + t.monthDay = (numArgs >= 3) ? args.at(exec, 2)->toInt32(exec) : 1; + t.hour = args.at(exec, 3)->toInt32(exec); + t.minute = args.at(exec, 4)->toInt32(exec); + t.second = args.at(exec, 5)->toInt32(exec); + t.isDST = -1; + double ms = (numArgs >= 7) ? args.at(exec, 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* 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* dateParse(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + return jsNumber(exec, parseDate(args.at(exec, 0)->toString(exec))); +} + +static JSValue* dateNow(ExecState* exec, JSObject*, JSValue*, const ArgList&) +{ + return jsNumber(exec, getCurrentUTCTime()); +} + +static JSValue* dateUTC(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + int n = args.size(); + if (isnan(args.at(exec, 0)->toNumber(exec)) + || isnan(args.at(exec, 1)->toNumber(exec)) + || (n >= 3 && isnan(args.at(exec, 2)->toNumber(exec))) + || (n >= 4 && isnan(args.at(exec, 3)->toNumber(exec))) + || (n >= 5 && isnan(args.at(exec, 4)->toNumber(exec))) + || (n >= 6 && isnan(args.at(exec, 5)->toNumber(exec))) + || (n >= 7 && isnan(args.at(exec, 6)->toNumber(exec)))) + return jsNaN(exec); + + GregorianDateTime t; + int year = args.at(exec, 0)->toInt32(exec); + t.year = (year >= 0 && year <= 99) ? year : year - 1900; + t.month = args.at(exec, 1)->toInt32(exec); + t.monthDay = (n >= 3) ? args.at(exec, 2)->toInt32(exec) : 1; + t.hour = args.at(exec, 3)->toInt32(exec); + t.minute = args.at(exec, 4)->toInt32(exec); + t.second = args.at(exec, 5)->toInt32(exec); + double ms = (n >= 7) ? args.at(exec, 6)->toNumber(exec) : 0; + return jsNumber(exec, gregorianDateTimeToMS(t, ms, true)); +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/DateConstructor.h b/JavaScriptCore/runtime/DateConstructor.h new file mode 100644 index 0000000..1279f82 --- /dev/null +++ b/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<StructureID>, StructureID* prototypeFunctionStructure, DatePrototype*); + + private: + virtual ConstructType getConstructData(ConstructData&); + virtual CallType getCallData(CallData&); + }; + + JSObject* constructDate(ExecState*, const ArgList&); + +} // namespace JSC + +#endif // DateConstructor_h diff --git a/JavaScriptCore/runtime/DateInstance.cpp b/JavaScriptCore/runtime/DateInstance.cpp new file mode 100644 index 0000000..b38c6ef --- /dev/null +++ b/JavaScriptCore/runtime/DateInstance.cpp @@ -0,0 +1,116 @@ +/* + * 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 "DateMath.h" +#include <math.h> +#include <wtf/MathExtras.h> + +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<StructureID> 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) { + JSC::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) { + JSC::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/JavaScriptCore/runtime/DateInstance.h b/JavaScriptCore/runtime/DateInstance.h new file mode 100644 index 0000000..98f4b64 --- /dev/null +++ b/JavaScriptCore/runtime/DateInstance.h @@ -0,0 +1,65 @@ +/* + * 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 JSC { + + struct GregorianDateTime; + + class DateInstance : public JSWrapperObject { + public: + explicit DateInstance(PassRefPtr<StructureID>); + virtual ~DateInstance(); + + double internalNumber() const { return internalValue()->uncheckedGetNumber(); } + + bool getTime(GregorianDateTime&, int& offset) const; + bool getUTCTime(GregorianDateTime&) const; + bool getTime(double& milliseconds, int& offset) const; + bool getUTCTime(double& milliseconds) const; + + static const ClassInfo info; + + void msToGregorianDateTime(double, bool outputIsUTC, 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/JavaScriptCore/runtime/DateMath.cpp b/JavaScriptCore/runtime/DateMath.cpp new file mode 100644 index 0000000..ec2a3f6 --- /dev/null +++ b/JavaScriptCore/runtime/DateMath.cpp @@ -0,0 +1,1046 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2006, 2007 Apple 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 "DateMath.h" + +#include "JSNumberCell.h" +#include <math.h> +#include <stdint.h> +#include <time.h> +#include <wtf/ASCIICType.h> +#include <wtf/Assertions.h> +#include <wtf/MathExtras.h> +#include <wtf/StringExtras.h> + +#if HAVE(ERRNO_H) +#include <errno.h> +#endif + +#if PLATFORM(DARWIN) +#include <notify.h> +#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 { + +/* Constants */ + +static const double minutesPerDay = 24.0 * 60.0; +static const double secondsPerDay = 24.0 * 60.0 * 60.0; +static const double secondsPerYear = 24.0 * 60.0 * 60.0 * 365.0; + +static const double usecPerSec = 1000000.0; + +static const double maxUnixTime = 2145859200.0; // 12/31/2037 + +// Day of year for the first day of each month, where index 0 is January, and day 0 is January 1. +// First for non-leap years, then for leap years. +static const int firstDayOfMonth[2][12] = { + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, + {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335} +}; + +static inline bool isLeapYear(int year) +{ + if (year % 4 != 0) + return false; + if (year % 400 == 0) + return true; + if (year % 100 == 0) + return false; + return true; +} + +static inline int daysInYear(int year) +{ + return 365 + isLeapYear(year); +} + +static inline double daysFrom1970ToYear(int year) +{ + // The Gregorian Calendar rules for leap years: + // Every fourth year is a leap year. 2004, 2008, and 2012 are leap years. + // However, every hundredth year is not a leap year. 1900 and 2100 are not leap years. + // Every four hundred years, there's a leap year after all. 2000 and 2400 are leap years. + + static const int leapDaysBefore1971By4Rule = 1970 / 4; + static const int excludedLeapDaysBefore1971By100Rule = 1970 / 100; + static const int leapDaysBefore1971By400Rule = 1970 / 400; + + const double yearMinusOne = year - 1; + const double yearsToAddBy4Rule = floor(yearMinusOne / 4.0) - leapDaysBefore1971By4Rule; + const double yearsToExcludeBy100Rule = floor(yearMinusOne / 100.0) - excludedLeapDaysBefore1971By100Rule; + const double yearsToAddBy400Rule = floor(yearMinusOne / 400.0) - leapDaysBefore1971By400Rule; + + return 365.0 * (year - 1970) + yearsToAddBy4Rule - yearsToExcludeBy100Rule + yearsToAddBy400Rule; +} + +static inline double msToDays(double ms) +{ + return floor(ms / msPerDay); +} + +static inline int msToYear(double ms) +{ + int approxYear = static_cast<int>(floor(ms / (msPerDay * 365.2425)) + 1970); + double msFromApproxYearTo1970 = msPerDay * daysFrom1970ToYear(approxYear); + if (msFromApproxYearTo1970 > ms) + return approxYear - 1; + if (msFromApproxYearTo1970 + msPerDay * daysInYear(approxYear) <= ms) + return approxYear + 1; + return approxYear; +} + +static inline int dayInYear(double ms, int year) +{ + return static_cast<int>(msToDays(ms) - daysFrom1970ToYear(year)); +} + +static inline double msToMilliseconds(double ms) +{ + double result = fmod(ms, msPerDay); + if (result < 0) + result += msPerDay; + return result; +} + +// 0: Sunday, 1: Monday, etc. +static inline int msToWeekDay(double ms) +{ + int wd = (static_cast<int>(msToDays(ms)) + 4) % 7; + if (wd < 0) + wd += 7; + return wd; +} + +static inline int msToSeconds(double ms) +{ + double result = fmod(floor(ms / msPerSecond), secondsPerMinute); + if (result < 0) + result += secondsPerMinute; + return static_cast<int>(result); +} + +static inline int msToMinutes(double ms) +{ + double result = fmod(floor(ms / msPerMinute), minutesPerHour); + if (result < 0) + result += minutesPerHour; + return static_cast<int>(result); +} + +static inline int msToHours(double ms) +{ + double result = fmod(floor(ms/msPerHour), hoursPerDay); + if (result < 0) + result += hoursPerDay; + return static_cast<int>(result); +} + +static inline int monthFromDayInYear(int dayInYear, bool leapYear) +{ + const int d = dayInYear; + int step; + + if (d < (step = 31)) + return 0; + step += (leapYear ? 29 : 28); + if (d < step) + return 1; + if (d < (step += 31)) + return 2; + if (d < (step += 30)) + return 3; + if (d < (step += 31)) + return 4; + if (d < (step += 30)) + return 5; + if (d < (step += 31)) + return 6; + if (d < (step += 31)) + return 7; + if (d < (step += 30)) + return 8; + if (d < (step += 31)) + return 9; + if (d < (step += 30)) + return 10; + return 11; +} + +static inline bool checkMonth(int dayInYear, int& startDayOfThisMonth, int& startDayOfNextMonth, int daysInThisMonth) +{ + startDayOfThisMonth = startDayOfNextMonth; + startDayOfNextMonth += daysInThisMonth; + return (dayInYear <= startDayOfNextMonth); +} + +static inline int dayInMonthFromDayInYear(int dayInYear, bool leapYear) +{ + const int d = dayInYear; + int step; + int next = 30; + + if (d <= next) + return d + 1; + const int daysInFeb = (leapYear ? 29 : 28); + if (checkMonth(d, step, next, daysInFeb)) + return d - step; + if (checkMonth(d, step, next, 31)) + return d - step; + if (checkMonth(d, step, next, 30)) + return d - step; + if (checkMonth(d, step, next, 31)) + return d - step; + if (checkMonth(d, step, next, 30)) + return d - step; + if (checkMonth(d, step, next, 31)) + return d - step; + if (checkMonth(d, step, next, 31)) + return d - step; + if (checkMonth(d, step, next, 30)) + return d - step; + if (checkMonth(d, step, next, 31)) + return d - step; + if (checkMonth(d, step, next, 30)) + return d - step; + step = next; + return d - step; +} + +static inline int monthToDayInYear(int month, bool isLeapYear) +{ + return firstDayOfMonth[isLeapYear][month]; +} + +static inline double timeToMS(double hour, double min, double sec, double ms) +{ + return (((hour * minutesPerHour + min) * secondsPerMinute + sec) * msPerSecond + ms); +} + +static int dateToDayInYear(int year, int month, int day) +{ + year += month / 12; + + month %= 12; + if (month < 0) { + month += 12; + --year; + } + + int yearday = static_cast<int>(floor(daysFrom1970ToYear(year))); + int monthday = monthToDayInYear(month, isLeapYear(year)); + + return yearday + monthday + day - 1; +} + +double getCurrentUTCTime() +{ + return floor(getCurrentUTCTimeWithMicroseconds()); +} + +#if PLATFORM(WIN_OS) + +static LARGE_INTEGER qpcFrequency; +static bool syncedTime; + +static double highResUpTime() +{ + // We use QPC, but only after sanity checking its result, due to bugs: + // http://support.microsoft.com/kb/274323 + // http://support.microsoft.com/kb/895980 + // http://msdn.microsoft.com/en-us/library/ms644904.aspx ("...you can get different results on different processors due to bugs in the basic input/output system (BIOS) or the hardware abstraction layer (HAL)." + + static LARGE_INTEGER qpcLast; + static DWORD tickCountLast; + static bool inited; + + LARGE_INTEGER qpc; + QueryPerformanceCounter(&qpc); + DWORD tickCount = GetTickCount(); + + if (inited) { + __int64 qpcElapsed = ((qpc.QuadPart - qpcLast.QuadPart) * 1000) / qpcFrequency.QuadPart; + __int64 tickCountElapsed; + if (tickCount >= tickCountLast) + tickCountElapsed = (tickCount - tickCountLast); + else { +#if COMPILER(MINGW) + __int64 tickCountLarge = tickCount + 0x100000000ULL; +#else + __int64 tickCountLarge = tickCount + 0x100000000I64; +#endif + tickCountElapsed = tickCountLarge - tickCountLast; + } + + // force a re-sync if QueryPerformanceCounter differs from GetTickCount by more than 500ms. + // (500ms value is from http://support.microsoft.com/kb/274323) + __int64 diff = tickCountElapsed - qpcElapsed; + if (diff > 500 || diff < -500) + syncedTime = false; + } else + inited = true; + + qpcLast = qpc; + tickCountLast = tickCount; + + return (1000.0 * qpc.QuadPart) / static_cast<double>(qpcFrequency.QuadPart);; +} + +static double lowResUTCTime() +{ + struct _timeb timebuffer; + _ftime(&timebuffer); + return timebuffer.time * msPerSecond + timebuffer.millitm; +} + +static bool qpcAvailable() +{ + static bool available; + static bool checked; + + if (checked) + return available; + + available = QueryPerformanceFrequency(&qpcFrequency); + checked = true; + return available; +} + +#endif + +double getCurrentUTCTimeWithMicroseconds() +{ +#if PLATFORM(WIN_OS) + // Use a combination of ftime and QueryPerformanceCounter. + // ftime returns the information we want, but doesn't have sufficient resolution. + // QueryPerformanceCounter has high resolution, but is only usable to measure time intervals. + // To combine them, we call ftime and QueryPerformanceCounter initially. Later calls will use QueryPerformanceCounter + // by itself, adding the delta to the saved ftime. We periodically re-sync to correct for drift. + static bool started; + static double syncLowResUTCTime; + static double syncHighResUpTime; + static double lastUTCTime; + + double lowResTime = lowResUTCTime(); + + if (!qpcAvailable()) + return lowResTime; + + double highResTime = highResUpTime(); + + if (!syncedTime) { + timeBeginPeriod(1); // increase time resolution around low-res time getter + syncLowResUTCTime = lowResTime = lowResUTCTime(); + timeEndPeriod(1); // restore time resolution + syncHighResUpTime = highResTime; + syncedTime = true; + } + + double highResElapsed = highResTime - syncHighResUpTime; + double utc = syncLowResUTCTime + highResElapsed; + + // force a clock re-sync if we've drifted + double lowResElapsed = lowResTime - syncLowResUTCTime; + const double maximumAllowedDriftMsec = 15.625 * 2.0; // 2x the typical low-res accuracy + if (fabs(highResElapsed - lowResElapsed) > maximumAllowedDriftMsec) + syncedTime = false; + + // make sure time doesn't run backwards (only correct if difference is < 2 seconds, since DST or clock changes could occur) + const double backwardTimeLimit = 2000.0; + if (utc < lastUTCTime && (lastUTCTime - utc) < backwardTimeLimit) + return lastUTCTime; + lastUTCTime = utc; +#else + struct timeval tv; + gettimeofday(&tv, 0); + double utc = tv.tv_sec * msPerSecond + tv.tv_usec / 1000.0; +#endif + return utc; +} + +void getLocalTime(const time_t* localTime, struct tm* localTM) +{ +#if COMPILER(MSVC7) || COMPILER(MINGW) + *localTM = *localtime(localTime); +#elif COMPILER(MSVC) + localtime_s(localTM, localTime); +#else + localtime_r(localTime, localTM); +#endif +} + +// There is a hard limit at 2038 that we currently do not have a workaround +// for (rdar://problem/5052975). +static inline int maximumYearForDST() +{ + return 2037; +} + +static inline int minimumYearForDST() +{ + // Because of the 2038 issue (see maximumYearForDST) if the current year is + // greater than the max year minus 27 (2010), we want to use the max year + // minus 27 instead, to ensure there is a range of 28 years that all years + // can map to. + return std::min(msToYear(getCurrentUTCTime()), maximumYearForDST() - 27) ; +} + +/* + * Find an equivalent year for the one given, where equivalence is deterined by + * the two years having the same leapness and the first day of the year, falling + * on the same day of the week. + * + * This function returns a year between this current year and 2037, however this + * function will potentially return incorrect results if the current year is after + * 2010, (rdar://problem/5052975), if the year passed in is before 1900 or after + * 2100, (rdar://problem/5055038). + */ +int equivalentYearForDST(int year) +{ + // It is ok if the cached year is not the current year as long as the rules + // for DST did not change between the two years; if they did the app would need + // to be restarted. + static int minYear = minimumYearForDST(); + int maxYear = maximumYearForDST(); + + int difference; + if (year > maxYear) + difference = minYear - year; + else if (year < minYear) + difference = maxYear - year; + else + return year; + + int quotient = difference / 28; + int product = (quotient) * 28; + + year += product; + ASSERT((year >= minYear && year <= maxYear) || (product - year == static_cast<int>(NaN))); + return year; +} + +static int32_t calculateUTCOffset() +{ + tm localt; + memset(&localt, 0, sizeof(localt)); + + // get the difference between this time zone and UTC on Jan 01, 2000 12:00:00 AM + localt.tm_mday = 1; + localt.tm_year = 100; + time_t utcOffset = 946684800 - mktime(&localt); + + return static_cast<int32_t>(utcOffset * 1000); +} + +#if PLATFORM(DARWIN) +static int32_t s_cachedUTCOffset; // In milliseconds. An assumption here is that access to an int32_t variable is atomic on platforms that take this code path. +static bool s_haveCachedUTCOffset; +static int s_notificationToken; +#endif + +/* + * Get the difference in milliseconds between this time zone and UTC (GMT) + * NOT including DST. + */ +double getUTCOffset() +{ +#if PLATFORM(DARWIN) + if (s_haveCachedUTCOffset) { + int notified; + uint32_t status = notify_check(s_notificationToken, ¬ified); + if (status == NOTIFY_STATUS_OK && !notified) + return s_cachedUTCOffset; + } +#endif + + int32_t utcOffset = calculateUTCOffset(); + +#if PLATFORM(DARWIN) + // Theoretically, it is possible that several threads will be executing this code at once, in which case we will have a race condition, + // and a newer value may be overwritten. In practice, time zones don't change that often. + s_cachedUTCOffset = utcOffset; +#endif + + return utcOffset; +} + +/* + * Get the DST offset for the time passed in. Takes + * seconds (not milliseconds) and cannot handle dates before 1970 + * on some OS' + */ +static double getDSTOffsetSimple(double localTimeSeconds, double utcOffset) +{ + if (localTimeSeconds > maxUnixTime) + localTimeSeconds = maxUnixTime; + else if (localTimeSeconds < 0) // Go ahead a day to make localtime work (does not work with 0) + localTimeSeconds += secondsPerDay; + + //input is UTC so we have to shift back to local time to determine DST thus the + getUTCOffset() + double offsetTime = (localTimeSeconds * msPerSecond) + utcOffset; + + // Offset from UTC but doesn't include DST obviously + int offsetHour = msToHours(offsetTime); + int offsetMinute = msToMinutes(offsetTime); + + // FIXME: time_t has a potential problem in 2038 + time_t localTime = static_cast<time_t>(localTimeSeconds); + + tm localTM; + getLocalTime(&localTime, &localTM); + + double diff = ((localTM.tm_hour - offsetHour) * secondsPerHour) + ((localTM.tm_min - offsetMinute) * 60); + + if (diff < 0) + diff += secondsPerDay; + + return (diff * msPerSecond); +} + +// Get the DST offset, given a time in UTC +static double getDSTOffset(double ms, double utcOffset) +{ + // On Mac OS X, the call to localtime (see getDSTOffsetSimple) will return historically accurate + // DST information (e.g. New Zealand did not have DST from 1946 to 1974) however the JavaScript + // standard explicitly dictates that historical information should not be considered when + // determining DST. For this reason we shift away from years that localtime can handle but would + // return historically accurate information. + int year = msToYear(ms); + int equivalentYear = equivalentYearForDST(year); + if (year != equivalentYear) { + bool leapYear = isLeapYear(year); + int dayInYearLocal = dayInYear(ms, year); + int dayInMonth = dayInMonthFromDayInYear(dayInYearLocal, leapYear); + int month = monthFromDayInYear(dayInYearLocal, leapYear); + int day = dateToDayInYear(equivalentYear, month, dayInMonth); + ms = (day * msPerDay) + msToMilliseconds(ms); + } + + return getDSTOffsetSimple(ms / msPerSecond, utcOffset); +} + +double gregorianDateTimeToMS(const GregorianDateTime& t, double milliSeconds, bool inputIsUTC) +{ + int day = dateToDayInYear(t.year + 1900, t.month, t.monthDay); + double ms = timeToMS(t.hour, t.minute, t.second, milliSeconds); + double result = (day * msPerDay) + ms; + + if (!inputIsUTC) { // convert to UTC + double utcOffset = getUTCOffset(); + result -= utcOffset; + result -= getDSTOffset(result, utcOffset); + } + + return result; +} + +void msToGregorianDateTime(double ms, bool outputIsUTC, GregorianDateTime& tm) +{ + // input is UTC + double dstOff = 0.0; + const double utcOff = getUTCOffset(); + + if (!outputIsUTC) { // convert to local time + dstOff = getDSTOffset(ms, utcOff); + ms += dstOff + utcOff; + } + + const int year = msToYear(ms); + tm.second = msToSeconds(ms); + tm.minute = msToMinutes(ms); + tm.hour = msToHours(ms); + tm.weekDay = msToWeekDay(ms); + tm.yearDay = dayInYear(ms, year); + tm.monthDay = dayInMonthFromDayInYear(tm.yearDay, isLeapYear(year)); + tm.month = monthFromDayInYear(tm.yearDay, isLeapYear(year)); + tm.year = year - 1900; + tm.isDST = dstOff != 0.0; + + tm.utcOffset = static_cast<long>((dstOff + utcOff) / msPerSecond); + tm.timeZone = NULL; +} + +void initDateMath() +{ +#ifndef NDEBUG + static bool alreadyInitialized; + ASSERT(!alreadyInitialized++); +#endif + + equivalentYearForDST(2000); // Need to call once to initialize a static used in this function. +#if PLATFORM(DARWIN) + // Register for a notification whenever the time zone changes. + uint32_t status = notify_register_check("com.apple.system.timezone", &s_notificationToken); + if (status == NOTIFY_STATUS_OK) { + s_cachedUTCOffset = calculateUTCOffset(); + s_haveCachedUTCOffset = true; + } +#endif +} + +static inline double ymdhmsToSeconds(long year, int mon, int day, int hour, int minute, int second) +{ + double days = (day - 32075) + + floor(1461 * (year + 4800.0 + (mon - 14) / 12) / 4) + + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12 + - floor(3 * ((year + 4900.0 + (mon - 14) / 12) / 100) / 4) + - 2440588; + return ((days * hoursPerDay + hour) * minutesPerHour + minute) * secondsPerMinute + second; +} + +// We follow the recommendation of RFC 2822 to consider all +// obsolete time zones not listed here equivalent to "-0000". +static const struct KnownZone { +#if !PLATFORM(WIN_OS) + const +#endif + char tzName[4]; + int tzOffset; +} known_zones[] = { + { "UT", 0 }, + { "GMT", 0 }, + { "EST", -300 }, + { "EDT", -240 }, + { "CST", -360 }, + { "CDT", -300 }, + { "MST", -420 }, + { "MDT", -360 }, + { "PST", -480 }, + { "PDT", -420 } +}; + +inline static void skipSpacesAndComments(const char*& s) +{ + int nesting = 0; + char ch; + while ((ch = *s)) { + if (!isASCIISpace(ch)) { + if (ch == '(') + nesting++; + else if (ch == ')' && nesting > 0) + nesting--; + else if (nesting == 0) + break; + } + s++; + } +} + +// returns 0-11 (Jan-Dec); -1 on failure +static int findMonth(const char* monthStr) +{ + ASSERT(monthStr); + char needle[4]; + for (int i = 0; i < 3; ++i) { + if (!*monthStr) + return -1; + needle[i] = static_cast<char>(toASCIILower(*monthStr++)); + } + needle[3] = '\0'; + const char *haystack = "janfebmaraprmayjunjulaugsepoctnovdec"; + const char *str = strstr(haystack, needle); + if (str) { + int position = static_cast<int>(str - haystack); + if (position % 3 == 0) + return position / 3; + } + return -1; +} + +double parseDate(const UString &date) +{ + // This parses a date in the form: + // Tuesday, 09-Nov-99 23:12:40 GMT + // or + // Sat, 01-Jan-2000 08:00:00 GMT + // or + // Sat, 01 Jan 2000 08:00:00 GMT + // or + // 01 Jan 99 22:00 +0100 (exceptions in rfc822/rfc2822) + // ### non RFC formats, added for Javascript: + // [Wednesday] January 09 1999 23:12:40 GMT + // [Wednesday] January 09 23:12:40 GMT 1999 + // + // We ignore the weekday. + + CString dateCString = date.UTF8String(); + const char *dateString = dateCString.c_str(); + + // Skip leading space + skipSpacesAndComments(dateString); + + long month = -1; + const char *wordStart = dateString; + // Check contents of first words if not number + while (*dateString && !isASCIIDigit(*dateString)) { + if (isASCIISpace(*dateString) || *dateString == '(') { + if (dateString - wordStart >= 3) + month = findMonth(wordStart); + skipSpacesAndComments(dateString); + wordStart = dateString; + } else + dateString++; + } + + // Missing delimiter between month and day (like "January29")? + if (month == -1 && wordStart != dateString) + month = findMonth(wordStart); + + skipSpacesAndComments(dateString); + + if (!*dateString) + return NaN; + + // ' 09-Nov-99 23:12:40 GMT' + char *newPosStr; + errno = 0; + long day = strtol(dateString, &newPosStr, 10); + if (errno) + return NaN; + dateString = newPosStr; + + if (!*dateString) + return NaN; + + if (day < 0) + return NaN; + + long year = 0; + if (day > 31) { + // ### where is the boundary and what happens below? + if (*dateString != '/') + return NaN; + // looks like a YYYY/MM/DD date + if (!*++dateString) + return NaN; + year = day; + month = strtol(dateString, &newPosStr, 10) - 1; + if (errno) + return NaN; + dateString = newPosStr; + if (*dateString++ != '/' || !*dateString) + return NaN; + day = strtol(dateString, &newPosStr, 10); + if (errno) + return NaN; + dateString = newPosStr; + } else if (*dateString == '/' && month == -1) { + dateString++; + // This looks like a MM/DD/YYYY date, not an RFC date. + month = day - 1; // 0-based + day = strtol(dateString, &newPosStr, 10); + if (errno) + return NaN; + if (day < 1 || day > 31) + return NaN; + dateString = newPosStr; + if (*dateString == '/') + dateString++; + if (!*dateString) + return NaN; + } else { + if (*dateString == '-') + dateString++; + + skipSpacesAndComments(dateString); + + if (*dateString == ',') + dateString++; + + if (month == -1) { // not found yet + month = findMonth(dateString); + if (month == -1) + return NaN; + + while (*dateString && *dateString != '-' && *dateString != ',' && !isASCIISpace(*dateString)) + dateString++; + + if (!*dateString) + return NaN; + + // '-99 23:12:40 GMT' + if (*dateString != '-' && *dateString != '/' && *dateString != ',' && !isASCIISpace(*dateString)) + return NaN; + dateString++; + } + } + + if (month < 0 || month > 11) + return NaN; + + // '99 23:12:40 GMT' + if (year <= 0 && *dateString) { + year = strtol(dateString, &newPosStr, 10); + if (errno) + return NaN; + } + + // Don't fail if the time is missing. + long hour = 0; + long minute = 0; + long second = 0; + if (!*newPosStr) + dateString = newPosStr; + else { + // ' 23:12:40 GMT' + if (!(isASCIISpace(*newPosStr) || *newPosStr == ',')) { + if (*newPosStr != ':') + return NaN; + // There was no year; the number was the hour. + year = -1; + } else { + // in the normal case (we parsed the year), advance to the next number + dateString = ++newPosStr; + skipSpacesAndComments(dateString); + } + + hour = strtol(dateString, &newPosStr, 10); + // Do not check for errno here since we want to continue + // even if errno was set becasue we are still looking + // for the timezone! + + // Read a number? If not, this might be a timezone name. + if (newPosStr != dateString) { + dateString = newPosStr; + + if (hour < 0 || hour > 23) + return NaN; + + if (!*dateString) + return NaN; + + // ':12:40 GMT' + if (*dateString++ != ':') + return NaN; + + minute = strtol(dateString, &newPosStr, 10); + if (errno) + return NaN; + dateString = newPosStr; + + if (minute < 0 || minute > 59) + return NaN; + + // ':40 GMT' + if (*dateString && *dateString != ':' && !isASCIISpace(*dateString)) + return NaN; + + // seconds are optional in rfc822 + rfc2822 + if (*dateString ==':') { + dateString++; + + second = strtol(dateString, &newPosStr, 10); + if (errno) + return NaN; + dateString = newPosStr; + + if (second < 0 || second > 59) + return NaN; + } + + skipSpacesAndComments(dateString); + + if (strncasecmp(dateString, "AM", 2) == 0) { + if (hour > 12) + return NaN; + if (hour == 12) + hour = 0; + dateString += 2; + skipSpacesAndComments(dateString); + } else if (strncasecmp(dateString, "PM", 2) == 0) { + if (hour > 12) + return NaN; + if (hour != 12) + hour += 12; + dateString += 2; + skipSpacesAndComments(dateString); + } + } + } + + bool haveTZ = false; + int offset = 0; + + // Don't fail if the time zone is missing. + // Some websites omit the time zone (4275206). + if (*dateString) { + if (strncasecmp(dateString, "GMT", 3) == 0 || strncasecmp(dateString, "UTC", 3) == 0) { + dateString += 3; + haveTZ = true; + } + + if (*dateString == '+' || *dateString == '-') { + long o = strtol(dateString, &newPosStr, 10); + if (errno) + return NaN; + dateString = newPosStr; + + if (o < -9959 || o > 9959) + return NaN; + + int sgn = (o < 0) ? -1 : 1; + o = abs(o); + if (*dateString != ':') { + offset = ((o / 100) * 60 + (o % 100)) * sgn; + } else { // GMT+05:00 + long o2 = strtol(dateString, &newPosStr, 10); + if (errno) + return NaN; + dateString = newPosStr; + offset = (o * 60 + o2) * sgn; + } + haveTZ = true; + } else { + for (int i = 0; i < int(sizeof(known_zones) / sizeof(KnownZone)); i++) { + if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) { + offset = known_zones[i].tzOffset; + dateString += strlen(known_zones[i].tzName); + haveTZ = true; + break; + } + } + } + } + + skipSpacesAndComments(dateString); + + if (*dateString && year == -1) { + year = strtol(dateString, &newPosStr, 10); + if (errno) + return NaN; + dateString = newPosStr; + } + + skipSpacesAndComments(dateString); + + // Trailing garbage + if (*dateString) + return NaN; + + // Y2K: Handle 2 digit years. + if (year >= 0 && year < 100) { + if (year < 50) + year += 2000; + else + year += 1900; + } + + // fall back to local timezone + if (!haveTZ) { + GregorianDateTime t; + t.monthDay = day; + t.month = month; + t.year = year - 1900; + t.isDST = -1; + t.second = second; + t.minute = minute; + t.hour = hour; + + // Use our gregorianDateTimeToMS() rather than mktime() as the latter can't handle the full year range. + return gregorianDateTimeToMS(t, 0, false); + } + + return (ymdhmsToSeconds(year, month + 1, day, hour, minute, second) - (offset * 60.0)) * msPerSecond; +} + +double timeClip(double t) +{ + if (!isfinite(t)) + return NaN; + if (fabs(t) > 8.64E15) + return NaN; + return trunc(t); +} + +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 tzname[70]; + struct tm gtm = t; + strftime(tzname, sizeof(tzname), "%Z", >m); + + if (tzname[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, tzname); + } 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/JavaScriptCore/runtime/DateMath.h b/JavaScriptCore/runtime/DateMath.h new file mode 100644 index 0000000..ab939a7 --- /dev/null +++ b/JavaScriptCore/runtime/DateMath.h @@ -0,0 +1,191 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2006, 2007 Apple 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 DateMath_h +#define DateMath_h + +#include <time.h> +#include <string.h> +#include <wtf/Noncopyable.h> + +namespace JSC { + +class UString; +struct GregorianDateTime; + +void initDateMath(); +void msToGregorianDateTime(double, bool outputIsUTC, GregorianDateTime&); +double gregorianDateTimeToMS(const GregorianDateTime&, double, bool inputIsUTC); +double getUTCOffset(); +int equivalentYearForDST(int year); +double getCurrentUTCTime(); +double getCurrentUTCTimeWithMicroseconds(); +void getLocalTime(const time_t*, tm*); + +// Not really math related, but this is currently the only shared place to put these. +double parseDate(const UString&); +double timeClip(double); +UString formatDate(const GregorianDateTime&); +UString formatDateUTCVariant(const GregorianDateTime&); +UString formatTime(const GregorianDateTime&, bool inputIsUTC); + + +const char * const weekdayName[7] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" }; +const char * const monthName[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + +const double hoursPerDay = 24.0; +const double minutesPerHour = 60.0; +const double secondsPerHour = 60.0 * 60.0; +const double secondsPerMinute = 60.0; +const double msPerSecond = 1000.0; +const double msPerMinute = 60.0 * 1000.0; +const double msPerHour = 60.0 * 60.0 * 1000.0; +const double msPerDay = 24.0 * 60.0 * 60.0 * 1000.0; + +// Intentionally overridding the default tm of the system +// Tee members of tm differ on various operating systems. +struct GregorianDateTime : Noncopyable { + GregorianDateTime() + : second(0) + , minute(0) + , hour(0) + , weekDay(0) + , monthDay(0) + , yearDay(0) + , month(0) + , year(0) + , isDST(0) + , utcOffset(0) + , timeZone(0) + { + } + + ~GregorianDateTime() + { + delete [] timeZone; + } + + GregorianDateTime(const tm& inTm) + : second(inTm.tm_sec) + , minute(inTm.tm_min) + , hour(inTm.tm_hour) + , weekDay(inTm.tm_wday) + , monthDay(inTm.tm_mday) + , yearDay(inTm.tm_yday) + , month(inTm.tm_mon) + , year(inTm.tm_year) + , isDST(inTm.tm_isdst) + { +#if !PLATFORM(WIN_OS) && !PLATFORM(SOLARIS) + utcOffset = static_cast<int>(inTm.tm_gmtoff); + + int inZoneSize = strlen(inTm.tm_zone) + 1; + timeZone = new char[inZoneSize]; + strncpy(timeZone, inTm.tm_zone, inZoneSize); +#else + utcOffset = static_cast<int>(getUTCOffset() / msPerSecond + (isDST ? secondsPerHour : 0)); + timeZone = 0; +#endif + } + + operator tm() const + { + tm ret; + memset(&ret, 0, sizeof(ret)); + + ret.tm_sec = second; + ret.tm_min = minute; + ret.tm_hour = hour; + ret.tm_wday = weekDay; + ret.tm_mday = monthDay; + ret.tm_yday = yearDay; + ret.tm_mon = month; + ret.tm_year = year; + ret.tm_isdst = isDST; + +#if !PLATFORM(WIN_OS) && !PLATFORM(SOLARIS) + ret.tm_gmtoff = static_cast<long>(utcOffset); + ret.tm_zone = timeZone; +#endif + + return ret; + } + + void copyFrom(const GregorianDateTime& rhs) + { + second = rhs.second; + minute = rhs.minute; + hour = rhs.hour; + weekDay = rhs.weekDay; + monthDay = rhs.monthDay; + yearDay = rhs.yearDay; + month = rhs.month; + year = rhs.year; + isDST = rhs.isDST; + utcOffset = rhs.utcOffset; + if (rhs.timeZone) { + int inZoneSize = strlen(rhs.timeZone) + 1; + timeZone = new char[inZoneSize]; + strncpy(timeZone, rhs.timeZone, inZoneSize); + } else + timeZone = 0; + } + + int second; + int minute; + int hour; + int weekDay; + int monthDay; + int yearDay; + int month; + int year; + int isDST; + int utcOffset; + char* timeZone; +}; + +static inline int gmtoffset(const GregorianDateTime& t) +{ + return t.utcOffset; +} + +} // namespace JSC + +#endif // DateMath_h diff --git a/JavaScriptCore/runtime/DatePrototype.cpp b/JavaScriptCore/runtime/DatePrototype.cpp new file mode 100644 index 0000000..a3e792e --- /dev/null +++ b/JavaScriptCore/runtime/DatePrototype.cpp @@ -0,0 +1,1056 @@ +/* + * 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 "DatePrototype.h" + +#include "DateMath.h" +#include "JSString.h" +#include "ObjectPrototype.h" +#include "DateInstance.h" +#include <float.h> +#include <limits.h> +#include <locale.h> +#include <math.h> +#include <time.h> +#include <wtf/Assertions.h> +#include <wtf/MathExtras.h> +#include <wtf/StringExtras.h> +#include <wtf/UnusedParam.h> + +#if HAVE(SYS_PARAM_H) +#include <sys/param.h> +#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 + +using namespace WTF; + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(DatePrototype); + +static JSValue* dateProtoFuncGetDate(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncGetDay(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncGetFullYear(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncGetHours(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncGetMilliSeconds(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncGetMinutes(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncGetMonth(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncGetSeconds(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncGetTime(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncGetTimezoneOffset(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncGetUTCDate(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncGetUTCDay(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncGetUTCFullYear(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncGetUTCHours(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncGetUTCMilliseconds(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncGetUTCMinutes(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncGetUTCMonth(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncGetUTCSeconds(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncGetYear(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncSetDate(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncSetFullYear(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncSetHours(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncSetMilliSeconds(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncSetMinutes(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncSetMonth(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncSetSeconds(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncSetTime(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncSetUTCDate(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncSetUTCFullYear(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncSetUTCHours(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncSetUTCMilliseconds(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncSetUTCMinutes(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncSetUTCMonth(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncSetUTCSeconds(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncSetYear(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncToDateString(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncToGMTString(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncToLocaleDateString(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncToLocaleString(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncToLocaleTimeString(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncToString(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncToTimeString(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncToUTCString(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* dateProtoFuncValueOf(ExecState*, JSObject*, JSValue*, const ArgList&); + +} + +#include "DatePrototype.lut.h" + +namespace JSC { + +#if PLATFORM(MAC) + +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 UString formatLocaleDate(ExecState* exec, double time, bool includeDate, bool includeTime, const ArgList& args) +{ + CFDateFormatterStyle dateStyle = (includeDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle); + CFDateFormatterStyle timeStyle = (includeTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle); + + bool useCustomFormat = false; + UString customFormatString; + + UString arg0String = args.at(exec, 0)->toString(exec); + if (arg0String == "custom" && !args.at(exec, 1)->isUndefined()) { + useCustomFormat = true; + customFormatString = args.at(exec, 1)->toString(exec); + } else if (includeDate && includeTime && !args.at(exec, 1)->isUndefined()) { + dateStyle = styleFromArgString(arg0String, dateStyle); + timeStyle = styleFromArgString(args.at(exec, 1)->toString(exec), timeStyle); + } else if (includeDate && !args.at(exec, 0)->isUndefined()) + dateStyle = styleFromArgString(arg0String, dateStyle); + else if (includeTime && !args.at(exec, 0)->isUndefined()) + timeStyle = styleFromArgString(arg0String, timeStyle); + + CFLocaleRef locale = CFLocaleCopyCurrent(); + CFDateFormatterRef formatter = CFDateFormatterCreate(0, locale, dateStyle, timeStyle); + CFRelease(locale); + + if (useCustomFormat) { + CFStringRef customFormatCFString = CFStringCreateWithCharacters(0, (UniChar *)customFormatString.data(), customFormatString.size()); + CFDateFormatterSetFormat(formatter, customFormatCFString); + CFRelease(customFormatCFString); + } + + CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(0, formatter, time - 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), reinterpret_cast<UniChar *>(buffer)); + + CFRelease(string); + + return UString(buffer, length); +} + +#else + +enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime }; + +static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, const LocaleDateTimeFormat format) +{ + static const char* formatStrings[] = {"%#c", "%#x", "%X"}; + + // 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; + + // Do the formatting + const int bufsize = 128; + char timebuffer[bufsize]; + size_t ret = strftime(timebuffer, bufsize, formatStrings[format], &localTM); + + 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); +} + +#endif // PLATFORM(WIN_OS) + +// 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(exec, idx++)->toInt32(exec, ok) * msPerHour; + } + + // minutes + if (maxArgs >= 3 && idx < numArgs && ok) { + t->minute = 0; + milliseconds += args.at(exec, idx++)->toInt32(exec, ok) * msPerMinute; + } + + // seconds + if (maxArgs >= 2 && idx < numArgs && ok) { + t->second = 0; + milliseconds += args.at(exec, idx++)->toInt32(exec, ok) * msPerSecond; + } + + if (!ok) + return false; + + // milliseconds + if (idx < numArgs) { + double millis = args.at(exec, 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(exec, idx++)->toInt32(exec, ok) - 1900; + + // months + if (maxArgs >= 2 && idx < numArgs && ok) + t->month = args.at(exec, idx++)->toInt32(exec, ok); + + // days + if (idx < numArgs && ok) { + t->monthDay = 0; + *ms += args.at(exec, idx)->toInt32(exec, ok) * msPerDay; + } + + return ok; +} + +const ClassInfo DatePrototype::info = {"Date", &DateInstance::info, 0, ExecState::dateTable}; + +/* Source for DatePrototype.lut.h + FIXME: We could use templates to simplify the UTC variants. +@begin dateTable + toString dateProtoFuncToString 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 dateProtoFuncValueOf 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 +@end +*/ +// ECMA 15.9.4 + +DatePrototype::DatePrototype(ExecState* exec, PassRefPtr<StructureID> 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* 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* 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* 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* 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* 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"); + +#if PLATFORM(MAC) + double secs = floor(milli / msPerSecond); + return jsNontrivialString(exec, formatLocaleDate(exec, secs, true, true, args)); +#else + UNUSED_PARAM(args); + + const bool utc = false; + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return formatLocaleDate(exec, t, LocaleDateAndTime); +#endif +} + +JSValue* 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"); + +#if PLATFORM(MAC) + double secs = floor(milli / msPerSecond); + return jsNontrivialString(exec, formatLocaleDate(exec, secs, true, false, args)); +#else + UNUSED_PARAM(args); + + const bool utc = false; + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return formatLocaleDate(exec, t, LocaleDate); +#endif +} + +JSValue* 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"); + +#if PLATFORM(MAC) + double secs = floor(milli / msPerSecond); + return jsNontrivialString(exec, formatLocaleDate(exec, secs, false, true, args)); +#else + UNUSED_PARAM(args); + + const bool utc = false; + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + return formatLocaleDate(exec, t, LocaleTime); +#endif +} + +JSValue* dateProtoFuncValueOf(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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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(exec, 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* dateProtoFuncSetMilliSeconds(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + const bool inputIsUTC = false; + return setNewValueFromTimeArgs(exec, thisValue, args, 1, inputIsUTC); +} + +JSValue* dateProtoFuncSetUTCMilliseconds(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + const bool inputIsUTC = true; + return setNewValueFromTimeArgs(exec, thisValue, args, 1, inputIsUTC); +} + +JSValue* dateProtoFuncSetSeconds(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + const bool inputIsUTC = false; + return setNewValueFromTimeArgs(exec, thisValue, args, 2, inputIsUTC); +} + +JSValue* dateProtoFuncSetUTCSeconds(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + const bool inputIsUTC = true; + return setNewValueFromTimeArgs(exec, thisValue, args, 2, inputIsUTC); +} + +JSValue* dateProtoFuncSetMinutes(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + const bool inputIsUTC = false; + return setNewValueFromTimeArgs(exec, thisValue, args, 3, inputIsUTC); +} + +JSValue* dateProtoFuncSetUTCMinutes(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + const bool inputIsUTC = true; + return setNewValueFromTimeArgs(exec, thisValue, args, 3, inputIsUTC); +} + +JSValue* dateProtoFuncSetHours(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + const bool inputIsUTC = false; + return setNewValueFromTimeArgs(exec, thisValue, args, 4, inputIsUTC); +} + +JSValue* dateProtoFuncSetUTCHours(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + const bool inputIsUTC = true; + return setNewValueFromTimeArgs(exec, thisValue, args, 4, inputIsUTC); +} + +JSValue* dateProtoFuncSetDate(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + const bool inputIsUTC = false; + return setNewValueFromDateArgs(exec, thisValue, args, 1, inputIsUTC); +} + +JSValue* dateProtoFuncSetUTCDate(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + const bool inputIsUTC = true; + return setNewValueFromDateArgs(exec, thisValue, args, 1, inputIsUTC); +} + +JSValue* dateProtoFuncSetMonth(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + const bool inputIsUTC = false; + return setNewValueFromDateArgs(exec, thisValue, args, 2, inputIsUTC); +} + +JSValue* dateProtoFuncSetUTCMonth(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + const bool inputIsUTC = true; + return setNewValueFromDateArgs(exec, thisValue, args, 2, inputIsUTC); +} + +JSValue* dateProtoFuncSetFullYear(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + const bool inputIsUTC = false; + return setNewValueFromDateArgs(exec, thisValue, args, 3, inputIsUTC); +} + +JSValue* dateProtoFuncSetUTCFullYear(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + const bool inputIsUTC = true; + return setNewValueFromDateArgs(exec, thisValue, args, 3, inputIsUTC); +} + +JSValue* 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(exec, 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* 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); +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/DatePrototype.h b/JavaScriptCore/runtime/DatePrototype.h new file mode 100644 index 0000000..500b40d --- /dev/null +++ b/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<StructureID>); + + virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + + static PassRefPtr<StructureID> createStructureID(JSValue* prototype) + { + return StructureID::create(prototype, TypeInfo(ObjectType)); + } + }; + +} // namespace JSC + +#endif // DatePrototype_h diff --git a/JavaScriptCore/runtime/Error.cpp b/JavaScriptCore/runtime/Error.cpp new file mode 100644 index 0000000..5e21c8e --- /dev/null +++ b/JavaScriptCore/runtime/Error.cpp @@ -0,0 +1,127 @@ +/* + * 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 "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; + } + + ArgList 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, "line"), 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, "sourceURL"), 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/JavaScriptCore/runtime/Error.h b/JavaScriptCore/runtime/Error.h new file mode 100644 index 0000000..adf7fdf --- /dev/null +++ b/JavaScriptCore/runtime/Error.h @@ -0,0 +1,65 @@ +/* + * 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); + +} // namespace JSC + +#endif // Error_h diff --git a/JavaScriptCore/runtime/ErrorConstructor.cpp b/JavaScriptCore/runtime/ErrorConstructor.cpp new file mode 100644 index 0000000..3c83fd4 --- /dev/null +++ b/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<StructureID> 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(exec, 0)->isUndefined()) + obj->putDirect(exec->propertyNames().message, jsString(exec, args.at(exec, 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* 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/JavaScriptCore/runtime/ErrorConstructor.h b/JavaScriptCore/runtime/ErrorConstructor.h new file mode 100644 index 0000000..45e4bb0 --- /dev/null +++ b/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<StructureID>, ErrorPrototype*); + + private: + virtual ConstructType getConstructData(ConstructData&); + virtual CallType getCallData(CallData&); + }; + + ErrorInstance* constructError(ExecState*, const ArgList&); + +} // namespace JSC + +#endif // ErrorConstructor_h diff --git a/JavaScriptCore/runtime/ErrorInstance.cpp b/JavaScriptCore/runtime/ErrorInstance.cpp new file mode 100644 index 0000000..1c55856 --- /dev/null +++ b/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<StructureID> structure) + : JSObject(structure) +{ +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/ErrorInstance.h b/JavaScriptCore/runtime/ErrorInstance.h new file mode 100644 index 0000000..8d86eec --- /dev/null +++ b/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<StructureID>); + + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + }; + +} // namespace JSC + +#endif // ErrorInstance_h diff --git a/JavaScriptCore/runtime/ErrorPrototype.cpp b/JavaScriptCore/runtime/ErrorPrototype.cpp new file mode 100644 index 0000000..69255c1 --- /dev/null +++ b/JavaScriptCore/runtime/ErrorPrototype.cpp @@ -0,0 +1,67 @@ +/* + * 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 "JSString.h" +#include "ObjectPrototype.h" +#include "PrototypeFunction.h" +#include "ustring.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(ErrorPrototype); + +static JSValue* errorProtoFuncToString(ExecState*, JSObject*, JSValue*, const ArgList&); + +// ECMA 15.9.4 +ErrorPrototype::ErrorPrototype(ExecState* exec, PassRefPtr<StructureID> structure, StructureID* 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) PrototypeFunction(exec, prototypeFunctionStructure, 0, exec->propertyNames().toString, errorProtoFuncToString), DontEnum); +} + +JSValue* 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/JavaScriptCore/runtime/ErrorPrototype.h b/JavaScriptCore/runtime/ErrorPrototype.h new file mode 100644 index 0000000..255ea11 --- /dev/null +++ b/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<StructureID>, StructureID* prototypeFunctionStructure); + }; + +} // namespace JSC + +#endif // ErrorPrototype_h diff --git a/JavaScriptCore/runtime/ExecState.cpp b/JavaScriptCore/runtime/ExecState.cpp new file mode 100644 index 0000000..0144c14 --- /dev/null +++ b/JavaScriptCore/runtime/ExecState.cpp @@ -0,0 +1,38 @@ +/* + * 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 "ExecState.h" + +#include "CodeBlock.h" + +namespace JSC { + +JSValue* CallFrame::thisValue() +{ + return this[codeBlock()->thisRegister].jsValue(this); +} + +} diff --git a/JavaScriptCore/runtime/ExecState.h b/JavaScriptCore/runtime/ExecState.h new file mode 100644 index 0000000..f1891bb --- /dev/null +++ b/JavaScriptCore/runtime/ExecState.h @@ -0,0 +1,148 @@ +/* + * 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. + * + */ + +#ifndef ExecState_h +#define ExecState_h + +// FIXME: Rename this file to CallFrame.h. + +#include "JSGlobalData.h" +#include "Machine.h" +#include "ScopeChain.h" + +namespace JSC { + + class Arguments; + class JSActivation; + + // Represents the current state of script execution. + // Passed as the first argument to most functions. + class ExecState : private Register { + public: + JSFunction* callee() const { return this[RegisterFile::Callee].function(); } + CodeBlock* codeBlock() const { return this[RegisterFile::CodeBlock].Register::codeBlock(); } + ScopeChainNode* scopeChain() const { return this[RegisterFile::ScopeChain].Register::scopeChain(); } + + JSValue* thisValue(); + + // Global object in which execution began. + JSGlobalObject* dynamicGlobalObject(); + + // Global object in which the currently executing code was defined. + // Differs from dynamicGlobalObject() during function calls across web browser frames. + JSGlobalObject* lexicalGlobalObject() const + { + return scopeChain()->globalObject(); + } + + // Differs from lexicalGlobalObject because this will have DOM window shell rather than + // the actual DOM window, which can't be "this" for security reasons. + JSObject* globalThisValue() const + { + return scopeChain()->globalThisObject(); + } + + // FIXME: Elsewhere, we use JSGlobalData* rather than JSGlobalData&. + // We should make this more uniform and either use a reference everywhere + // or a pointer everywhere. + JSGlobalData& globalData() const + { + return *scopeChain()->globalData; + } + + // Convenience functions for access to global data. + // It takes a few memory references to get from a call frame to the global data + // pointer, so these are inefficient, and should be used sparingly in new code. + // But they're used in many places in legacy code, so they're not going away any time soon. + + void setException(JSValue* exception) { globalData().exception = exception; } + void clearException() { globalData().exception = noValue(); } + JSValue* exception() const { return globalData().exception; } + JSValue** exceptionSlot() { return &globalData().exception; } + bool hadException() const { return !!globalData().exception; } + + const CommonIdentifiers& propertyNames() const { return *globalData().propertyNames; } + const ArgList& emptyList() const { return *globalData().emptyList; } + Machine* machine() { return globalData().machine; } + Heap* heap() { return &globalData().heap; } + + static const HashTable* arrayTable(CallFrame* callFrame) { return callFrame->globalData().arrayTable; } + static const HashTable* dateTable(CallFrame* callFrame) { return callFrame->globalData().dateTable; } + static const HashTable* mathTable(CallFrame* callFrame) { return callFrame->globalData().mathTable; } + static const HashTable* numberTable(CallFrame* callFrame) { return callFrame->globalData().numberTable; } + static const HashTable* regExpTable(CallFrame* callFrame) { return callFrame->globalData().regExpTable; } + static const HashTable* regExpConstructorTable(CallFrame* callFrame) { return callFrame->globalData().regExpConstructorTable; } + static const HashTable* stringTable(CallFrame* callFrame) { return callFrame->globalData().stringTable; } + + private: + friend class Arguments; + friend class JSActivation; + friend class JSGlobalObject; + friend class Machine; + + static CallFrame* create(Register* callFrameBase) { return static_cast<CallFrame*>(callFrameBase); } + Register* registers() { return this; } + + CallFrame& operator=(const Register& r) { *static_cast<Register*>(this) = r; return *this; } + + int argumentCount() const { return this[RegisterFile::ArgumentCount].i(); } + CallFrame* callerFrame() const { return this[RegisterFile::CallerFrame].callFrame(); } + Arguments* optionalCalleeArguments() const { return this[RegisterFile::OptionalCalleeArguments].arguments(); } + Instruction* returnPC() const { return this[RegisterFile::ReturnPC].vPC(); } + int returnValueRegister() const { return this[RegisterFile::ReturnValueRegister].i(); } + + void setArgumentCount(int count) { this[RegisterFile::ArgumentCount] = count; } + void setCallee(JSFunction* callee) { this[RegisterFile::Callee] = callee; } + void setCalleeArguments(Arguments* arguments) { this[RegisterFile::OptionalCalleeArguments] = arguments; } + void setCallerFrame(CallFrame* callerFrame) { this[RegisterFile::CallerFrame] = callerFrame; } + void setCodeBlock(CodeBlock* codeBlock) { this[RegisterFile::CodeBlock] = codeBlock; } + void setScopeChain(ScopeChainNode* scopeChain) { this[RegisterFile::ScopeChain] = scopeChain; } + + ALWAYS_INLINE void init(CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, + CallFrame* callerFrame, int returnValueRegister, int argc, JSFunction* function) + { + ASSERT(callerFrame); // Use noCaller() rather than 0 for the outer host call frame caller. + + setCodeBlock(codeBlock); + setScopeChain(scopeChain); + setCallerFrame(callerFrame); + this[RegisterFile::ReturnPC] = vPC; + this[RegisterFile::ReturnValueRegister] = returnValueRegister; + setArgumentCount(argc); // original argument count (for the sake of the "arguments" object) + setCallee(function); + setCalleeArguments(0); + } + + static const intptr_t HostCallFrameFlag = 1; + + static CallFrame* noCaller() { return reinterpret_cast<CallFrame*>(HostCallFrameFlag); } + bool hasHostCallFrameFlag() const { return reinterpret_cast<intptr_t>(this) & HostCallFrameFlag; } + CallFrame* addHostCallFrameFlag() const { return reinterpret_cast<CallFrame*>(reinterpret_cast<intptr_t>(this) | HostCallFrameFlag); } + CallFrame* removeHostCallFrameFlag() { return reinterpret_cast<CallFrame*>(reinterpret_cast<intptr_t>(this) & ~HostCallFrameFlag); } + + ExecState(); + ~ExecState(); + }; + +} // namespace JSC + +#endif // ExecState_h diff --git a/JavaScriptCore/runtime/FunctionConstructor.cpp b/JavaScriptCore/runtime/FunctionConstructor.cpp new file mode 100644 index 0000000..adc3d3c --- /dev/null +++ b/JavaScriptCore/runtime/FunctionConstructor.cpp @@ -0,0 +1,146 @@ +/* + * 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<StructureID> 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* 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; +} + +// ECMA 15.3.2 The Function Constructor +JSObject* constructFunction(ExecState* exec, const ArgList& args, const Identifier& functionName, const UString& sourceURL, int lineNumber) +{ + UString p(""); + UString body; + int argsSize = args.size(); + if (argsSize == 0) + body = ""; + else if (argsSize == 1) + body = args.at(exec, 0)->toString(exec); + else { + p = args.at(exec, 0)->toString(exec); + for (int k = 1; k < argsSize - 1; k++) + p += "," + args.at(exec, k)->toString(exec); + body = args.at(exec, argsSize - 1)->toString(exec); + } + + // parse the source code + int errLine; + UString errMsg; + SourceCode source = makeSource(body, sourceURL, lineNumber); + RefPtr<FunctionBodyNode> functionBody = exec->globalData().parser->parse<FunctionBodyNode>(exec, exec->dynamicGlobalObject()->debugger(), source, &errLine, &errMsg); + + // No program node == syntax error - throw a syntax error + if (!functionBody) + // We can't return a Completion(Throw) here, so just set the exception + // and return it + return throwError(exec, SyntaxError, errMsg, errLine, source.provider()->asID(), source.provider()->url()); + + // parse parameter list. throw syntax error on illegal identifiers + int len = p.size(); + const UChar* c = p.data(); + int i = 0; + UString param; + Vector<Identifier> parameters; + while (i < len) { + while (*c == ' ' && i < len) + c++, i++; + if (Lexer::isIdentStart(c[0])) { // else error + param = UString(c, 1); + c++, i++; + while (i < len && (Lexer::isIdentPart(c[0]))) { + param.append(*c); + c++, i++; + } + while (i < len && *c == ' ') + c++, i++; + if (i == len) { + parameters.append(Identifier(exec, param)); + break; + } else if (*c == ',') { + parameters.append(Identifier(exec, param)); + c++, i++; + continue; + } // else error + } + return throwError(exec, SyntaxError, "Syntax error in parameter list"); + } + size_t count = parameters.size(); + functionBody->finishParsing(parameters.releaseBuffer(), count); + + JSGlobalObject* globalObject = exec->lexicalGlobalObject(); + ScopeChain scopeChain(globalObject, globalObject->globalData(), exec->globalThisValue()); + JSFunction* function = new (exec) JSFunction(exec, functionName, functionBody.get(), scopeChain.node()); + + JSObject* prototype = constructEmptyObject(exec); + prototype->putDirect(exec->propertyNames().constructor, function, DontEnum); + function->putDirect(exec->propertyNames().prototype, prototype, DontDelete); + return function; +} + +// 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/JavaScriptCore/runtime/FunctionConstructor.h b/JavaScriptCore/runtime/FunctionConstructor.h new file mode 100644 index 0000000..c309c41 --- /dev/null +++ b/JavaScriptCore/runtime/FunctionConstructor.h @@ -0,0 +1,44 @@ +/* + * 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 FunctionConstructor : public InternalFunction { + public: + FunctionConstructor(ExecState*, PassRefPtr<StructureID>, 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&); + +} // namespace JSC + +#endif // FunctionConstructor_h diff --git a/JavaScriptCore/runtime/FunctionPrototype.cpp b/JavaScriptCore/runtime/FunctionPrototype.cpp new file mode 100644 index 0000000..8c3a260 --- /dev/null +++ b/JavaScriptCore/runtime/FunctionPrototype.cpp @@ -0,0 +1,136 @@ +/* + * 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 "Machine.h" +#include "PrototypeFunction.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(FunctionPrototype); + +static JSValue* functionProtoFuncToString(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* functionProtoFuncApply(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* functionProtoFuncCall(ExecState*, JSObject*, JSValue*, const ArgList&); + +FunctionPrototype::FunctionPrototype(ExecState* exec, PassRefPtr<StructureID> structure) + : InternalFunction(&exec->globalData(), structure, exec->propertyNames().nullIdentifier) +{ + putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 0), DontDelete | ReadOnly | DontEnum); +} + +void FunctionPrototype::addFunctionProperties(ExecState* exec, StructureID* prototypeFunctionStructure) +{ + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 0, exec->propertyNames().toString, functionProtoFuncToString), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 2, exec->propertyNames().apply, functionProtoFuncApply), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 1, exec->propertyNames().call, functionProtoFuncCall), DontEnum); +} + +static JSValue* callFunctionPrototype(ExecState*, JSObject*, JSValue*, const ArgList&) +{ + return jsUndefined(); +} + +// ECMA 15.3.4 +CallType FunctionPrototype::getCallData(CallData& callData) +{ + callData.native.function = callFunctionPrototype; + return CallTypeHost; +} + +// Functions + +JSValue* functionProtoFuncToString(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&) +{ + if (thisValue->isObject(&JSFunction::info)) { + JSFunction* function = asFunction(thisValue); + return jsString(exec, "function " + function->name(&exec->globalData()) + "(" + function->m_body->paramString() + ") " + function->m_body->toSourceString()); + } + + if (thisValue->isObject(&InternalFunction::info)) { + InternalFunction* function = asInternalFunction(thisValue); + return jsString(exec, "function " + function->name(&exec->globalData()) + "() {\n [native code]\n}"); + } + + return throwError(exec, TypeError); +} + +JSValue* functionProtoFuncApply(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + CallData callData; + CallType callType = thisValue->getCallData(callData); + if (callType == CallTypeNone) + return throwError(exec, TypeError); + + JSValue* thisArg = args.at(exec, 0); + JSValue* argArray = args.at(exec, 1); + + JSValue* applyThis; + if (thisArg->isUndefinedOrNull()) + applyThis = exec->globalThisValue(); + else + applyThis = thisArg->toObject(exec); + + ArgList applyArgs; + if (!argArray->isUndefinedOrNull()) { + if (!argArray->isObject()) + return throwError(exec, TypeError); + if (asObject(argArray)->classInfo() == &Arguments::info) + asArguments(argArray)->fillArgList(exec, applyArgs); + else if (exec->machine()->isJSArray(argArray)) + asArray(argArray)->fillArgList(exec, applyArgs); + else if (asObject(argArray)->inherits(&JSArray::info)) { + unsigned length = asArray(argArray)->get(exec, exec->propertyNames().length)->toUInt32(exec); + for (unsigned i = 0; i < length; ++i) + applyArgs.append(asArray(argArray)->get(exec, i)); + } else + return throwError(exec, TypeError); + } + + return call(exec, thisValue, callType, callData, applyThis, applyArgs); +} + +JSValue* functionProtoFuncCall(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + CallData callData; + CallType callType = thisValue->getCallData(callData); + if (callType == CallTypeNone) + return throwError(exec, TypeError); + + JSValue* thisArg = args.at(exec, 0); + + JSObject* callThis; + if (thisArg->isUndefinedOrNull()) + callThis = exec->globalThisValue(); + else + callThis = thisArg->toObject(exec); + + ArgList argsTail; + args.getSlice(1, argsTail); + return call(exec, thisValue, callType, callData, callThis, argsTail); +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/FunctionPrototype.h b/JavaScriptCore/runtime/FunctionPrototype.h new file mode 100644 index 0000000..f493642 --- /dev/null +++ b/JavaScriptCore/runtime/FunctionPrototype.h @@ -0,0 +1,44 @@ +/* + * 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 FunctionPrototype : public InternalFunction { + public: + FunctionPrototype(ExecState*, PassRefPtr<StructureID>); + void addFunctionProperties(ExecState*, StructureID* prototypeFunctionStructure); + + static PassRefPtr<StructureID> createStructureID(JSValue* proto) + { + return StructureID::create(proto, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot)); + } + + private: + virtual CallType getCallData(CallData&); + }; + +} // namespace JSC + +#endif // FunctionPrototype_h diff --git a/JavaScriptCore/runtime/GetterSetter.cpp b/JavaScriptCore/runtime/GetterSetter.cpp new file mode 100644 index 0000000..c3d089f --- /dev/null +++ b/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 = noValue(); + 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/JavaScriptCore/runtime/GetterSetter.h b/JavaScriptCore/runtime/GetterSetter.h new file mode 100644 index 0000000..da968b2 --- /dev/null +++ b/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/JavaScriptCore/runtime/GlobalEvalFunction.cpp b/JavaScriptCore/runtime/GlobalEvalFunction.cpp new file mode 100644 index 0000000..10b3a2f --- /dev/null +++ b/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<StructureID> 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/JavaScriptCore/runtime/GlobalEvalFunction.h b/JavaScriptCore/runtime/GlobalEvalFunction.h new file mode 100644 index 0000000..2d207c4 --- /dev/null +++ b/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<StructureID>, 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/JavaScriptCore/runtime/InitializeThreading.cpp b/JavaScriptCore/runtime/InitializeThreading.cpp new file mode 100644 index 0000000..9e14768 --- /dev/null +++ b/JavaScriptCore/runtime/InitializeThreading.cpp @@ -0,0 +1,69 @@ +/* + * 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 "collector.h" +#include "DateMath.h" +#include "dtoa.h" +#include "identifier.h" +#include "JSGlobalObject.h" +#include "ustring.h" +#include <wtf/Threading.h> + +namespace JSC { + +#if PLATFORM(DARWIN) && ENABLE(JSC_MULTIPLE_THREADS) +static pthread_once_t initializeThreadingKeyOnce = PTHREAD_ONCE_INIT; +#endif + +static void initializeThreadingOnce() +{ + WTF::initializeThreading(); +#if ENABLE(JSC_MULTIPLE_THREADS) + s_dtoaP5Mutex = new Mutex; + UString::null(); + initDateMath(); +#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/JavaScriptCore/runtime/InitializeThreading.h b/JavaScriptCore/runtime/InitializeThreading.h new file mode 100644 index 0000000..1a93ccb --- /dev/null +++ b/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/JavaScriptCore/runtime/InternalFunction.cpp b/JavaScriptCore/runtime/InternalFunction.cpp new file mode 100644 index 0000000..ee81a58 --- /dev/null +++ b/JavaScriptCore/runtime/InternalFunction.cpp @@ -0,0 +1,51 @@ +/* + * 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<StructureID> 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(); +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/InternalFunction.h b/JavaScriptCore/runtime/InternalFunction.h new file mode 100644 index 0000000..54d90ae --- /dev/null +++ b/JavaScriptCore/runtime/InternalFunction.h @@ -0,0 +1,64 @@ +/* + * 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 const ClassInfo info; + + const UString& name(JSGlobalData*); + + static PassRefPtr<StructureID> createStructureID(JSValue* proto) + { + return StructureID::create(proto, TypeInfo(ObjectType, ImplementsHasInstance | HasStandardGetOwnPropertySlot)); + } + + protected: + InternalFunction(PassRefPtr<StructureID> structure) : JSObject(structure) { } + InternalFunction(JSGlobalData*, PassRefPtr<StructureID>, 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/JavaScriptCore/runtime/JSActivation.cpp b/JavaScriptCore/runtime/JSActivation.cpp new file mode 100644 index 0000000..9cb77e8 --- /dev/null +++ b/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 "Machine.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().activationStructureID, new JSActivationData(functionBody, callFrame)) +{ +} + +JSActivation::~JSActivation() +{ + delete d(); +} + +void JSActivation::mark() +{ + Base::mark(); + + Register* registerArray = d()->registerArray.get(); + if (!registerArray) + return; + + size_t numParametersMinusThis = d()->functionBody->generatedByteCode().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().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.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*, 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; + putDirect(propertyName, value, attributes, true, slot); +} + +bool JSActivation::deleteProperty(ExecState* exec, const Identifier& propertyName) +{ + if (propertyName == exec->propertyNames().arguments) + return false; + + return Base::deleteProperty(exec, propertyName); +} + +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/JavaScriptCore/runtime/JSActivation.h b/JavaScriptCore/runtime/JSActivation.h new file mode 100644 index 0000000..16d131b --- /dev/null +++ b/JavaScriptCore/runtime/JSActivation.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 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 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); + + virtual JSObject* toThisObject(ExecState*) const; + + void copyRegisters(Arguments* arguments); + + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + + static PassRefPtr<StructureID> createStructureID(JSValue* proto) { return StructureID::create(proto, TypeInfo(ObjectType, NeedsThisConversion)); } + + private: + struct JSActivationData : public JSVariableObjectData { + JSActivationData(PassRefPtr<FunctionBodyNode> functionBody, Register* registers) + : JSVariableObjectData(&functionBody->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/JavaScriptCore/runtime/JSArray.cpp b/JavaScriptCore/runtime/JSArray.cpp new file mode 100644 index 0000000..d2d38a4 --- /dev/null +++ b/JavaScriptCore/runtime/JSArray.cpp @@ -0,0 +1,1002 @@ +/* + * 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 "PropertyNameArray.h" +#include <wtf/AVLTree.h> +#include <wtf/Assertions.h> +#include <operations.h> + +#define CHECK_ARRAY_CONSISTENCY 0 + +using namespace std; + +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<StructureID> structureID) + : JSObject(structureID) +{ + 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<StructureID> 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(ExecState* exec, PassRefPtr<StructureID> 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).jsValue(exec); + + m_storage = storage; + + // When the array is created non-empty, its cells are filled, so it's really no worse than + // a property map. Therefore don't report extra memory cost. + + 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; + if (newNumValuesInVector == storage->m_numValuesInVector + 1) { + for (unsigned j = vectorLength; j < newVectorLength; ++j) + storage->m_vector[j] = noValue(); + 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] = noValue(); + 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 isArrayIndex; + unsigned i = propertyName.toArrayIndex(&isArrayIndex); + if (isArrayIndex) + return deleteProperty(exec, i); + + if (propertyName == exec->propertyNames().length) + return false; + + return JSObject::deleteProperty(exec, propertyName); +} + +bool JSArray::deleteProperty(ExecState* exec, unsigned i) +{ + checkConsistency(); + + ArrayStorage* storage = m_storage; + + if (i < storage->m_vectorLength) { + JSValue*& valueSlot = storage->m_vector[i]; + if (!valueSlot) { + checkConsistency(); + return false; + } + valueSlot = noValue(); + --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)); + + return false; +} + +void JSArray::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) +{ + // 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); +} + +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; + + storage->m_vectorLength = newVectorLength; + + for (unsigned i = vectorLength; i < newVectorLength; ++i) + storage->m_vector[i] = noValue(); + + 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 = noValue(); + 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 = noValue(); + --m_storage->m_numValuesInVector; + m_fastAccessCutoff = length; + } else if (length < m_storage->m_vectorLength) { + JSValue*& valueSlot = m_storage->m_vector[length]; + result = valueSlot; + valueSlot = noValue(); + 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(); + } + } +} + +typedef std::pair<JSValue*, UString> ArrayQSortPair; + +static int compareByStringPairForQSort(const void* a, const void* b) +{ + const ArrayQSortPair* va = static_cast<const ArrayQSortPair*>(a); + const ArrayQSortPair* vb = static_cast<const ArrayQSortPair*>(b); + return compare(va->second, vb->second); +} + +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<ArrayQSortPair> 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(ArrayQSortPair), 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(ArrayQSortPair), 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; + + 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; + + ArgList arguments; + arguments.append(va); + arguments.append(vb); + double 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 (!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) { + if (JSValue* v = m_storage->m_vector[i]) { + 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] = noValue(); + + m_fastAccessCutoff = newUsedVectorLength; + m_storage->m_numValuesInVector = newUsedVectorLength; + + checkConsistency(SortConsistencyCheck); +} + +void JSArray::fillArgList(ExecState* exec, ArgList& 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)); +} + +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) { + if (JSValue* v = storage->m_vector[i]) { + 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] = noValue(); + + 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) +{ + ArgList values; + values.append(singleItemValue); + return new (exec) JSArray(exec, exec->lexicalGlobalObject()->arrayStructure(), values); +} + +JSArray* constructArray(ExecState* exec, const ArgList& values) +{ + return new (exec) JSArray(exec, exec->lexicalGlobalObject()->arrayStructure(), values); +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/JSArray.h b/JavaScriptCore/runtime/JSArray.h new file mode 100644 index 0000000..165fafd --- /dev/null +++ b/JavaScriptCore/runtime/JSArray.h @@ -0,0 +1,126 @@ +/* + * 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 CTI; + + public: + explicit JSArray(PassRefPtr<StructureID>); + JSArray(PassRefPtr<StructureID>, unsigned initialLength); + JSArray(ExecState*, PassRefPtr<StructureID>, 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 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 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*, ArgList&); + + static PassRefPtr<StructureID> createStructureID(JSValue* prototype) + { + return StructureID::create(prototype, TypeInfo(ObjectType)); + } + + protected: + virtual void put(ExecState*, const Identifier& propertyName, JSValue*, PutPropertySlot&); + virtual bool deleteProperty(ExecState*, const Identifier& propertyName); + virtual bool deleteProperty(ExecState*, unsigned propertyName); + virtual void getPropertyNames(ExecState*, PropertyNameArray&); + 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)); + } + +} // namespace JSC + +#endif // JSArray_h diff --git a/JavaScriptCore/runtime/JSCell.cpp b/JavaScriptCore/runtime/JSCell.cpp new file mode 100644 index 0000000..cfe2f72 --- /dev/null +++ b/JavaScriptCore/runtime/JSCell.cpp @@ -0,0 +1,223 @@ +/* + * 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::getNumber(double& numericValue) const +{ + if (!isNumber()) + return false; + numericValue = static_cast<const JSNumberCell*>(this)->value(); + return true; +} + +double JSCell::getNumber() const +{ + return isNumber() ? static_cast<const JSNumberCell*>(this)->value() : NaN; +} + +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) +{ + return toObject(exec)->deleteProperty(exec, identifier); +} + +bool JSCell::deleteProperty(ExecState* exec, unsigned identifier) +{ + return toObject(exec)->deleteProperty(exec, identifier); +} + +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 noValue(); +} + +bool JSCell::isGetterSetter() const +{ + return false; +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/JSCell.h b/JavaScriptCore/runtime/JSCell.h new file mode 100644 index 0000000..108dab6 --- /dev/null +++ b/JavaScriptCore/runtime/JSCell.h @@ -0,0 +1,311 @@ +/* + * 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 "StructureID.h" +#include "JSValue.h" +#include "collector.h" + +namespace JSC { + + class JSCell : public JSValue { + friend class CTI; + friend class GetterSetter; + friend class Heap; + friend class JSNumberCell; + friend class JSObject; + friend class JSPropertyNameIterator; + friend class JSString; + friend class JSValue; + friend class Machine; + + private: + explicit JSCell(StructureID*); + 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; + + StructureID* structureID() const; + + // Extracting the value. + bool getNumber(double&) const; + double getNumber() const; // NaN if not a number + 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. + 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); + virtual bool deleteProperty(ExecState*, unsigned propertyName); + + 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&); + + StructureID* m_structureID; + }; + + JSCell* asCell(JSValue*); + + inline JSCell* asCell(JSValue* value) + { + ASSERT(!JSImmediate::isImmediate(value)); + return static_cast<JSCell*>(value); + } + + inline JSCell::JSCell(StructureID* structureID) + : m_structureID(structureID) + { + } + + inline JSCell::~JSCell() + { + } + + inline bool JSCell::isNumber() const + { + return Heap::isNumber(const_cast<JSCell*>(this)); + } + + inline bool JSCell::isObject() const + { + return m_structureID->typeInfo().type() == ObjectType; + } + + inline bool JSCell::isString() const + { + return m_structureID->typeInfo().type() == StringType; + } + + inline StructureID* JSCell::structureID() const + { + return m_structureID; + } + + inline bool JSCell::marked() const + { + return Heap::isCellMarked(this); + } + + inline void JSCell::mark() + { + return Heap::markCell(this); + } + + ALWAYS_INLINE JSCell* JSValue::asCell() const + { + ASSERT(!JSImmediate::isImmediate(asValue())); + return reinterpret_cast<JSCell*>(const_cast<JSValue*>(this)); + } + + 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::isNumber() const + { + return JSImmediate::isNumber(asValue()) || (!JSImmediate::isImmediate(asValue()) && asCell()->isNumber()); + } + + 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 double JSValue::getNumber() const + { + return JSImmediate::isImmediate(asValue()) ? JSImmediate::toDouble(asValue()) : asCell()->getNumber(); + } + + 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::toObject(asValue(), exec); + return asCell()->toThisObject(exec); + } + + inline bool JSValue::needsThisConversion() const + { + if (UNLIKELY(JSImmediate::isImmediate(asValue()))) + return true; + return asCell()->structureID()->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()) ? noValue() : asCell()->getJSNumber(); + } + +} // namespace JSC + +#endif // JSCell_h diff --git a/JavaScriptCore/runtime/JSFunction.cpp b/JavaScriptCore/runtime/JSFunction.cpp new file mode 100644 index 0000000..2973d2d --- /dev/null +++ b/JavaScriptCore/runtime/JSFunction.cpp @@ -0,0 +1,200 @@ +/* + * 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 "ExecState.h" +#include "FunctionPrototype.h" +#include "JSGlobalObject.h" +#include "Machine.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", 0, 0, 0 }; + +JSFunction::JSFunction(ExecState* exec, const Identifier& name, FunctionBodyNode* body, ScopeChainNode* scopeChainNode) + : Base(&exec->globalData(), exec->lexicalGlobalObject()->functionStructure(), name) + , m_body(body) + , m_scopeChain(scopeChainNode) +{ +} + +JSFunction::~JSFunction() +{ +#if ENABLE(CTI) + // 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.get() && m_body->isGenerated()) + m_body->generatedByteCode().unlinkCallers(); +#endif +} + +void JSFunction::mark() +{ + Base::mark(); + m_body->mark(); + m_scopeChain.mark(); +} + +CallType JSFunction::getCallData(CallData& callData) +{ + callData.js.functionBody = m_body.get(); + callData.js.scopeChain = m_scopeChain.node(); + return CallTypeJS; +} + +JSValue* JSFunction::call(ExecState* exec, JSValue* thisValue, const ArgList& args) +{ + return exec->machine()->execute(m_body.get(), exec, this, thisValue->toThisObject(exec), args, m_scopeChain.node(), exec->exceptionSlot()); +} + +JSValue* JSFunction::argumentsGetter(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + JSFunction* thisObj = asFunction(slot.slotBase()); + return exec->machine()->retrieveArguments(exec, thisObj); +} + +JSValue* JSFunction::callerGetter(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + JSFunction* thisObj = asFunction(slot.slotBase()); + return exec->machine()->retrieveCaller(exec, thisObj); +} + +JSValue* JSFunction::lengthGetter(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + JSFunction* thisObj = asFunction(slot.slotBase()); + return jsNumber(exec, thisObj->m_body->parameterCount()); +} + +bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +{ + if (propertyName == exec->propertyNames().prototype) { + JSValue** location = getDirectLocation(propertyName); + + if (!location) { + JSObject* prototype = new (exec) JSObject(m_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 (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length) + return; + Base::put(exec, propertyName, value, slot); +} + +bool JSFunction::deleteProperty(ExecState* exec, const Identifier& propertyName) +{ + if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length) + return false; + return Base::deleteProperty(exec, propertyName); +} + +/* Returns the parameter name corresponding to the given index. eg: + * function f1(x, y, z): getParameterName(0) --> x + * + * If a name appears more than once, only the last index at which + * it appears associates with it. eg: + * function f2(x, x): getParameterName(0) --> null + */ +const Identifier& JSFunction::getParameterName(int index) +{ + const Identifier* parameters = m_body->parameters(); + + if (static_cast<size_t>(index) >= m_body->parameterCount()) + return m_scopeChain.globalObject()->globalData()->propertyNames->nullIdentifier; + + const Identifier& name = parameters[index]; + + // Are there any subsequent parameters with the same name? + size_t size = m_body->parameterCount(); + for (size_t i = index + 1; i < size; ++i) { + if (parameters[i] == name) + return m_scopeChain.globalObject()->globalData()->propertyNames->nullIdentifier; + } + + return name; +} + +// ECMA 13.2.2 [[Construct]] +ConstructType JSFunction::getConstructData(ConstructData& constructData) +{ + constructData.js.functionBody = m_body.get(); + constructData.js.scopeChain = m_scopeChain.node(); + return ConstructTypeJS; +} + +JSObject* JSFunction::construct(ExecState* exec, const ArgList& args) +{ + StructureID* 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->machine()->execute(m_body.get(), exec, this, thisObj, args, m_scopeChain.node(), exec->exceptionSlot()); + if (exec->hadException() || !result->isObject()) + return thisObj; + return asObject(result); +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/JSFunction.h b/JavaScriptCore/runtime/JSFunction.h new file mode 100644 index 0000000..694a0f4 --- /dev/null +++ b/JavaScriptCore/runtime/JSFunction.h @@ -0,0 +1,99 @@ +/* + * 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 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 CTI; + friend class Machine; + + typedef InternalFunction Base; + JSFunction(PassRefPtr<JSC::StructureID> st) : InternalFunction(st), m_scopeChain(NoScopeChain()) {} + public: + 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); + + JSObject* construct(ExecState*, const ArgList&); + JSValue* call(ExecState*, JSValue* thisValue, const ArgList&); + + // Note: Returns a null identifier for any parameters that will never get set + // due to a later parameter with the same name. + const Identifier& getParameterName(int index); + + void setScope(const ScopeChain& scopeChain) { m_scopeChain = scopeChain; } + ScopeChain& scope() { return m_scopeChain; } + + virtual void mark(); + + static const ClassInfo info; + + // FIXME: This should be private + RefPtr<FunctionBodyNode> m_body; + + static PassRefPtr<StructureID> createStructureID(JSValue* prototype) + { + return StructureID::create(prototype, TypeInfo(ObjectType, ImplementsHasInstance)); + } + + private: + virtual const ClassInfo* classInfo() const { return &info; } + + virtual ConstructType getConstructData(ConstructData&); + virtual CallType getCallData(CallData&); + + static JSValue* argumentsGetter(ExecState*, const Identifier&, const PropertySlot&); + static JSValue* callerGetter(ExecState*, const Identifier&, const PropertySlot&); + static JSValue* lengthGetter(ExecState*, const Identifier&, const PropertySlot&); + + ScopeChain m_scopeChain; + }; + + JSFunction* asFunction(JSValue*); + + inline JSFunction* asFunction(JSValue* value) + { + ASSERT(asObject(value)->inherits(&JSFunction::info)); + return static_cast<JSFunction*>(asObject(value)); + } + +} // namespace kJS + +#endif // JSFunction_h diff --git a/JavaScriptCore/runtime/JSGlobalData.cpp b/JavaScriptCore/runtime/JSGlobalData.cpp new file mode 100644 index 0000000..8910679 --- /dev/null +++ b/JavaScriptCore/runtime/JSGlobalData.cpp @@ -0,0 +1,183 @@ +/* + * 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 "CommonIdentifiers.h" +#include "JSActivation.h" +#include "JSClassRef.h" +#include "JSLock.h" +#include "JSNotAnObject.h" +#include "JSStaticScopeObject.h" +#include "Machine.h" +#include "Parser.h" +#include "collector.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 const HashTable arrayTable; +extern const HashTable dateTable; +extern const HashTable mathTable; +extern const HashTable numberTable; +extern const HashTable regExpTable; +extern const HashTable regExpConstructorTable; +extern const HashTable stringTable; + +JSGlobalData::JSGlobalData(bool isShared) + : machine(new Machine) + , exception(noValue()) + , arrayTable(new HashTable(JSC::arrayTable)) + , dateTable(new HashTable(JSC::dateTable)) + , mathTable(new HashTable(JSC::mathTable)) + , numberTable(new HashTable(JSC::numberTable)) + , regExpTable(new HashTable(JSC::regExpTable)) + , regExpConstructorTable(new HashTable(JSC::regExpConstructorTable)) + , stringTable(new HashTable(JSC::stringTable)) + , activationStructureID(JSActivation::createStructureID(jsNull())) + , interruptedExecutionErrorStructure(JSObject::createStructureID(jsNull())) + , staticScopeStructureID(JSStaticScopeObject::createStructureID(jsNull())) + , stringStructureID(JSString::createStructureID(jsNull())) + , notAnObjectErrorStubStructure(JSNotAnObjectErrorStub::createStructureID(jsNull())) + , notAnObjectStructure(JSNotAnObject::createStructureID(jsNull())) + , numberStructureID(JSNumberCell::createStructureID(jsNull())) + , identifierTable(createIdentifierTable()) + , propertyNames(new CommonIdentifiers(this)) + , emptyList(new ArgList) + , newParserObjects(0) + , parserObjectExtraRefCounts(0) + , lexer(new Lexer(this)) + , parser(new Parser) + , head(0) + , dynamicGlobalObject(0) + , isSharedInstance(isShared) + , clientData(0) + , heap(this) +{ +#if PLATFORM(MAC) + startProfilerServerIfNeeded(); +#endif +} + +JSGlobalData::~JSGlobalData() +{ + // By the time this is destroyed, heap.destroy() must already have been called. + + delete machine; +#ifndef NDEBUG + // Zeroing out to make the behavior more predictable when someone attempts to use a deleted instance. + machine = 0; +#endif + + arrayTable->deleteTable(); + dateTable->deleteTable(); + mathTable->deleteTable(); + numberTable->deleteTable(); + regExpTable->deleteTable(); + regExpConstructorTable->deleteTable(); + stringTable->deleteTable(); + delete arrayTable; + delete dateTable; + delete mathTable; + delete numberTable; + delete regExpTable; + delete regExpConstructorTable; + delete stringTable; + + delete parser; + delete lexer; + + deleteAllValues(opaqueJSClassData); + + delete emptyList; + + delete propertyNames; + deleteIdentifierTable(identifierTable); + + delete newParserObjects; + delete parserObjectExtraRefCounts; + + delete clientData; +} + +PassRefPtr<JSGlobalData> JSGlobalData::create() +{ + return adoptRef(new JSGlobalData); +} + +PassRefPtr<JSGlobalData> JSGlobalData::createLeaked() +{ +#ifndef NDEBUG + StructureID::startIgnoringLeaks(); + RefPtr<JSGlobalData> data = create(); + StructureID::stopIgnoringLeaks(); + return data.release(); +#else + return create(); +#endif +} + +bool JSGlobalData::sharedInstanceExists() +{ + return sharedInstanceInternal(); +} + +JSGlobalData& JSGlobalData::sharedInstance() +{ + JSGlobalData*& instance = sharedInstanceInternal(); + if (!instance) + instance = new JSGlobalData(true); + return *instance; +} + +JSGlobalData*& JSGlobalData::sharedInstanceInternal() +{ + ASSERT(JSLock::currentThreadIsHoldingLock()); + static JSGlobalData* sharedInstance; + return sharedInstance; +} + +JSGlobalData::ClientData::~ClientData() +{ +} + +} diff --git a/JavaScriptCore/runtime/JSGlobalData.h b/JavaScriptCore/runtime/JSGlobalData.h new file mode 100644 index 0000000..3210149 --- /dev/null +++ b/JavaScriptCore/runtime/JSGlobalData.h @@ -0,0 +1,126 @@ +/* + * 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 JSGlobalData_h +#define JSGlobalData_h + +#include <wtf/Forward.h> +#include <wtf/HashMap.h> +#include <wtf/RefCounted.h> +#include "collector.h" +#include "SmallStrings.h" + +struct OpaqueJSClass; +struct OpaqueJSClassContextData; + +namespace JSC { + + class ArgList; + class CommonIdentifiers; + class Heap; + class IdentifierTable; + class JSGlobalObject; + class JSObject; + class Lexer; + class Machine; + class Parser; + class ParserRefCounted; + class StructureID; + class UString; + struct HashTable; + + class JSGlobalData : public RefCounted<JSGlobalData> { + public: + static bool sharedInstanceExists(); + static JSGlobalData& sharedInstance(); + + static PassRefPtr<JSGlobalData> create(); + static PassRefPtr<JSGlobalData> createLeaked(); + ~JSGlobalData(); + + Machine* machine; + + JSValue* exception; +#if ENABLE(CTI) + void* throwReturnAddress; +#endif + + const HashTable* arrayTable; + const HashTable* dateTable; + const HashTable* mathTable; + const HashTable* numberTable; + const HashTable* regExpTable; + const HashTable* regExpConstructorTable; + const HashTable* stringTable; + + RefPtr<StructureID> activationStructureID; + RefPtr<StructureID> interruptedExecutionErrorStructure; + RefPtr<StructureID> staticScopeStructureID; + RefPtr<StructureID> stringStructureID; + RefPtr<StructureID> notAnObjectErrorStubStructure; + RefPtr<StructureID> notAnObjectStructure; + RefPtr<StructureID> numberStructureID; + + IdentifierTable* identifierTable; + CommonIdentifiers* propertyNames; + const ArgList* 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; + + HashMap<OpaqueJSClass*, OpaqueJSClassContextData*> opaqueJSClassData; + + HashSet<ParserRefCounted*>* newParserObjects; + HashCountedSet<ParserRefCounted*>* parserObjectExtraRefCounts; + + Lexer* lexer; + Parser* parser; + + JSGlobalObject* head; + JSGlobalObject* dynamicGlobalObject; + + bool isSharedInstance; + + struct ClientData { + virtual ~ClientData() = 0; + }; + + ClientData* clientData; + + HashSet<JSObject*> arrayVisitedElements; + + Heap heap; + + private: + JSGlobalData(bool isShared = false); + + static JSGlobalData*& sharedInstanceInternal(); + }; + +} + +#endif diff --git a/JavaScriptCore/runtime/JSGlobalObject.cpp b/JavaScriptCore/runtime/JSGlobalObject.cpp new file mode 100644 index 0000000..89c32fd --- /dev/null +++ b/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -0,0 +1,469 @@ +/* + * Copyright (C) 2007, 2008 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 "JSGlobalObjectFunctions.h" +#include "JSLock.h" +#include "Machine.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<StructureID>& 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)->globalObject = 0; + + RegisterFile& registerFile = globalData()->machine->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) { + if (JSValue* valueAfter = getDirect(propertyName)) + putDirect(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::createStructureID(jsNull())); // The real prototype will be set once ObjectPrototype is created. + d()->prototypeFunctionStructure = PrototypeFunction::createStructureID(d()->functionPrototype); + d()->functionPrototype->addFunctionProperties(exec, d()->prototypeFunctionStructure.get()); + d()->objectPrototype = new (exec) ObjectPrototype(exec, ObjectPrototype::createStructureID(jsNull()), d()->prototypeFunctionStructure.get()); + d()->functionPrototype->structureID()->setPrototypeWithoutTransition(d()->objectPrototype); + + d()->emptyObjectStructure = d()->objectPrototype->inheritorID(); + + d()->functionStructure = JSFunction::createStructureID(d()->functionPrototype); + d()->callbackFunctionStructure = JSCallbackFunction::createStructureID(d()->functionPrototype); + d()->argumentsStructure = Arguments::createStructureID(d()->objectPrototype); + d()->callbackConstructorStructure = JSCallbackConstructor::createStructureID(d()->objectPrototype); + d()->callbackObjectStructure = JSCallbackObject<JSObject>::createStructureID(d()->objectPrototype); + + d()->arrayPrototype = new (exec) ArrayPrototype(ArrayPrototype::createStructureID(d()->objectPrototype)); + d()->arrayStructure = JSArray::createStructureID(d()->arrayPrototype); + d()->regExpMatchesArrayStructure = RegExpMatchesArray::createStructureID(d()->arrayPrototype); + + d()->stringPrototype = new (exec) StringPrototype(exec, StringPrototype::createStructureID(d()->objectPrototype)); + d()->stringObjectStructure = StringObject::createStructureID(d()->stringPrototype); + + d()->booleanPrototype = new (exec) BooleanPrototype(exec, BooleanPrototype::createStructureID(d()->objectPrototype), d()->prototypeFunctionStructure.get()); + d()->booleanObjectStructure = BooleanObject::createStructureID(d()->booleanPrototype); + + d()->numberPrototype = new (exec) NumberPrototype(exec, NumberPrototype::createStructureID(d()->objectPrototype), d()->prototypeFunctionStructure.get()); + d()->numberObjectStructure = NumberObject::createStructureID(d()->numberPrototype); + + d()->datePrototype = new (exec) DatePrototype(exec, DatePrototype::createStructureID(d()->objectPrototype)); + d()->dateStructure = DateInstance::createStructureID(d()->datePrototype); + + d()->regExpPrototype = new (exec) RegExpPrototype(exec, RegExpPrototype::createStructureID(d()->objectPrototype), d()->prototypeFunctionStructure.get()); + d()->regExpStructure = RegExpObject::createStructureID(d()->regExpPrototype); + + ErrorPrototype* errorPrototype = new (exec) ErrorPrototype(exec, ErrorPrototype::createStructureID(d()->objectPrototype), d()->prototypeFunctionStructure.get()); + d()->errorStructure = ErrorInstance::createStructureID(errorPrototype); + + RefPtr<StructureID> nativeErrorPrototypeStructure = NativeErrorPrototype::createStructureID(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 + + JSValue* objectConstructor = new (exec) ObjectConstructor(exec, ObjectConstructor::createStructureID(d()->functionPrototype), d()->objectPrototype); + JSValue* functionConstructor = new (exec) FunctionConstructor(exec, FunctionConstructor::createStructureID(d()->functionPrototype), d()->functionPrototype); + JSValue* arrayConstructor = new (exec) ArrayConstructor(exec, ArrayConstructor::createStructureID(d()->functionPrototype), d()->arrayPrototype); + JSValue* stringConstructor = new (exec) StringConstructor(exec, StringConstructor::createStructureID(d()->functionPrototype), d()->prototypeFunctionStructure.get(), d()->stringPrototype); + JSValue* booleanConstructor = new (exec) BooleanConstructor(exec, BooleanConstructor::createStructureID(d()->functionPrototype), d()->booleanPrototype); + JSValue* numberConstructor = new (exec) NumberConstructor(exec, NumberConstructor::createStructureID(d()->functionPrototype), d()->numberPrototype); + JSValue* dateConstructor = new (exec) DateConstructor(exec, DateConstructor::createStructureID(d()->functionPrototype), d()->prototypeFunctionStructure.get(), d()->datePrototype); + + d()->regExpConstructor = new (exec) RegExpConstructor(exec, RegExpConstructor::createStructureID(d()->functionPrototype), d()->regExpPrototype); + + d()->errorConstructor = new (exec) ErrorConstructor(exec, ErrorConstructor::createStructureID(d()->functionPrototype), errorPrototype); + + RefPtr<StructureID> nativeErrorStructure = NativeErrorConstructor::createStructureID(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->putDirectWithoutTransition(exec->propertyNames().constructor, objectConstructor, DontEnum); + d()->functionPrototype->putDirectWithoutTransition(exec->propertyNames().constructor, functionConstructor, DontEnum); + d()->arrayPrototype->putDirectWithoutTransition(exec->propertyNames().constructor, arrayConstructor, DontEnum); + d()->booleanPrototype->putDirectWithoutTransition(exec->propertyNames().constructor, booleanConstructor, DontEnum); + d()->stringPrototype->putDirectWithoutTransition(exec->propertyNames().constructor, stringConstructor, DontEnum); + d()->numberPrototype->putDirectWithoutTransition(exec->propertyNames().constructor, numberConstructor, DontEnum); + d()->datePrototype->putDirectWithoutTransition(exec->propertyNames().constructor, dateConstructor, DontEnum); + d()->regExpPrototype->putDirectWithoutTransition(exec->propertyNames().constructor, d()->regExpConstructor, DontEnum); + errorPrototype->putDirectWithoutTransition(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. + + putDirectWithoutTransition(Identifier(exec, "Object"), objectConstructor, DontEnum); + putDirectWithoutTransition(Identifier(exec, "Function"), functionConstructor, DontEnum); + putDirectWithoutTransition(Identifier(exec, "Array"), arrayConstructor, DontEnum); + putDirectWithoutTransition(Identifier(exec, "Boolean"), booleanConstructor, DontEnum); + putDirectWithoutTransition(Identifier(exec, "String"), stringConstructor, DontEnum); + putDirectWithoutTransition(Identifier(exec, "Number"), numberConstructor, DontEnum); + putDirectWithoutTransition(Identifier(exec, "Date"), dateConstructor, DontEnum); + putDirectWithoutTransition(Identifier(exec, "RegExp"), d()->regExpConstructor, DontEnum); + putDirectWithoutTransition(Identifier(exec, "Error"), d()->errorConstructor, DontEnum); + putDirectWithoutTransition(Identifier(exec, "EvalError"), d()->evalErrorConstructor); + putDirectWithoutTransition(Identifier(exec, "RangeError"), d()->rangeErrorConstructor); + putDirectWithoutTransition(Identifier(exec, "ReferenceError"), d()->referenceErrorConstructor); + putDirectWithoutTransition(Identifier(exec, "SyntaxError"), d()->syntaxErrorConstructor); + putDirectWithoutTransition(Identifier(exec, "TypeError"), d()->typeErrorConstructor); + putDirectWithoutTransition(Identifier(exec, "URIError"), d()->URIErrorConstructor); + + // Set global values. + GlobalPropertyInfo staticGlobals[] = { + GlobalPropertyInfo(Identifier(exec, "Math"), new (exec) MathObject(exec, MathObject::createStructureID(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) + }; + + addStaticGlobals(staticGlobals, sizeof(staticGlobals) / sizeof(GlobalPropertyInfo)); + + // Set global functions. + + d()->evalFunction = new (exec) GlobalEvalFunction(exec, GlobalEvalFunction::createStructureID(d()->functionPrototype), 1, exec->propertyNames().eval, globalFuncEval, this); + putDirectFunctionWithoutTransition(exec, d()->evalFunction, DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, d()->prototypeFunctionStructure.get(), 2, Identifier(exec, "parseInt"), globalFuncParseInt), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "parseFloat"), globalFuncParseFloat), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "isNaN"), globalFuncIsNaN), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "isFinite"), globalFuncIsFinite), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "escape"), globalFuncEscape), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "unescape"), globalFuncUnescape), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "decodeURI"), globalFuncDecodeURI), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "decodeURIComponent"), globalFuncDecodeURIComponent), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "encodeURI"), globalFuncEncodeURI), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "encodeURIComponent"), globalFuncEncodeURIComponent), DontEnum); +#ifndef NDEBUG + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, d()->prototypeFunctionStructure.get(), 1, Identifier(exec, "kjsprint"), globalFuncKJSPrint), DontEnum); +#endif + + resetPrototype(prototype); +} + +// Set prototype, and also insert the object prototype at the end of the chain. +void JSGlobalObject::resetPrototype(JSValue* prototype) +{ + setPrototype(prototype); + lastInPrototypeChain(this)->setPrototype(d()->objectPrototype); +} + +void JSGlobalObject::setTimeoutTime(unsigned timeoutTime) +{ + globalData()->machine->setTimeoutTime(timeoutTime); +} + +void JSGlobalObject::startTimeoutCheck() +{ + globalData()->machine->startTimeoutCheck(); +} + +void JSGlobalObject::stopTimeoutCheck() +{ + globalData()->machine->stopTimeoutCheck(); +} + +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()->machine->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()->objectPrototype); + markIfNeeded(d()->functionPrototype); + markIfNeeded(d()->arrayPrototype); + markIfNeeded(d()->booleanPrototype); + markIfNeeded(d()->stringPrototype); + markIfNeeded(d()->numberPrototype); + markIfNeeded(d()->datePrototype); + markIfNeeded(d()->regExpPrototype); + + 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(); + } +} + +void JSGlobalObject::markCrossHeapDependentObjects() +{ + // Overridden by subclasses. +} + +JSGlobalObject* JSGlobalObject::toGlobalObject(ExecState*) const +{ + return const_cast<JSGlobalObject*>(this); +} + +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/JavaScriptCore/runtime/JSGlobalObject.h b/JavaScriptCore/runtime/JSGlobalObject.h new file mode 100644 index 0000000..d8a072a --- /dev/null +++ b/JavaScriptCore/runtime/JSGlobalObject.h @@ -0,0 +1,363 @@ +/* + * 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 "NumberPrototype.h" +#include "StringPrototype.h" +#include <wtf/HashSet.h> +#include <wtf/OwnPtr.h> + +namespace JSC { + + class ArrayPrototype; + class BooleanPrototype; + class DatePrototype; + class Debugger; + class ErrorConstructor; + class FunctionPrototype; + class GlobalEvalFunction; + class NativeErrorConstructor; + class ProgramCodeBlock; + 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) + , objectPrototype(0) + , functionPrototype(0) + , arrayPrototype(0) + , booleanPrototype(0) + , stringPrototype(0) + , numberPrototype(0) + , datePrototype(0) + , regExpPrototype(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; + + ObjectPrototype* objectPrototype; + FunctionPrototype* functionPrototype; + ArrayPrototype* arrayPrototype; + BooleanPrototype* booleanPrototype; + StringPrototype* stringPrototype; + NumberPrototype* numberPrototype; + DatePrototype* datePrototype; + RegExpPrototype* regExpPrototype; + + RefPtr<StructureID> argumentsStructure; + RefPtr<StructureID> arrayStructure; + RefPtr<StructureID> booleanObjectStructure; + RefPtr<StructureID> callbackConstructorStructure; + RefPtr<StructureID> callbackFunctionStructure; + RefPtr<StructureID> callbackObjectStructure; + RefPtr<StructureID> dateStructure; + RefPtr<StructureID> emptyObjectStructure; + RefPtr<StructureID> errorStructure; + RefPtr<StructureID> functionStructure; + RefPtr<StructureID> numberObjectStructure; + RefPtr<StructureID> prototypeFunctionStructure; + RefPtr<StructureID> regExpMatchesArrayStructure; + RefPtr<StructureID> regExpStructure; + RefPtr<StructureID> stringObjectStructure; + + SymbolTable symbolTable; + unsigned profileGroup; + + RefPtr<JSGlobalData> globalData; + + HashSet<ProgramCodeBlock*> codeBlocks; + }; + + public: + void* operator new(size_t, JSGlobalData*); + + explicit JSGlobalObject() + : JSVariableObject(JSGlobalObject::createStructureID(jsNull()), new JSGlobalObjectData) + { + init(this); + } + + protected: + JSGlobalObject(PassRefPtr<StructureID> structure, JSGlobalObjectData* data, JSObject* thisValue) + : JSVariableObject(structure, data) + { + init(thisValue); + } + + public: + virtual ~JSGlobalObject(); + + virtual void mark(); + virtual void markCrossHeapDependentObjects(); + + virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&, bool& slotIsWriteable); + 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; } + + StructureID* argumentsStructure() const { return d()->argumentsStructure.get(); } + StructureID* arrayStructure() const { return d()->arrayStructure.get(); } + StructureID* booleanObjectStructure() const { return d()->booleanObjectStructure.get(); } + StructureID* callbackConstructorStructure() const { return d()->callbackConstructorStructure.get(); } + StructureID* callbackFunctionStructure() const { return d()->callbackFunctionStructure.get(); } + StructureID* callbackObjectStructure() const { return d()->callbackObjectStructure.get(); } + StructureID* dateStructure() const { return d()->dateStructure.get(); } + StructureID* emptyObjectStructure() const { return d()->emptyObjectStructure.get(); } + StructureID* errorStructure() const { return d()->errorStructure.get(); } + StructureID* functionStructure() const { return d()->functionStructure.get(); } + StructureID* numberObjectStructure() const { return d()->numberObjectStructure.get(); } + StructureID* prototypeFunctionStructure() const { return d()->prototypeFunctionStructure.get(); } + StructureID* regExpMatchesArrayStructure() const { return d()->regExpMatchesArrayStructure.get(); } + StructureID* regExpStructure() const { return d()->regExpStructure.get(); } + StructureID* stringObjectStructure() const { return d()->stringObjectStructure.get(); } + + void setProfileGroup(unsigned value) { d()->profileGroup = value; } + unsigned profileGroup() const { return d()->profileGroup; } + + void setTimeoutTime(unsigned timeoutTime); + void startTimeoutCheck(); + void stopTimeoutCheck(); + + Debugger* debugger() const { return d()->debugger; } + void setDebugger(Debugger* debugger) { 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 JSGlobalObject* toGlobalObject(ExecState*) const; + + 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<StructureID> createStructureID(JSValue* prototype) + { + return StructureID::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::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot, bool& slotIsWriteable) + { + if (JSVariableObject::getOwnPropertySlotForWrite(exec, propertyName, slot, slotIsWriteable)) + return true; + 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* StructureID::prototypeForLookup(ExecState* exec) + { + if (typeInfo().type() == ObjectType) + return m_prototype; + + if (typeInfo().type() == StringType) + return exec->lexicalGlobalObject()->stringPrototype(); + + ASSERT(typeInfo().type() == NumberType); + return exec->lexicalGlobalObject()->numberPrototype(); + } + + 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; + } + +} // namespace JSC + +#endif // JSGlobalObject_h diff --git a/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp new file mode 100644 index 0000000..8bb1c6b --- /dev/null +++ b/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp @@ -0,0 +1,433 @@ +/* + * 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 "JSGlobalObjectFunctions.h" + +#include "ExecState.h" +#include "GlobalEvalFunction.h" +#include "JSGlobalObject.h" +#include "JSString.h" +#include "Machine.h" +#include "Parser.h" +#include "dtoa.h" +#include "lexer.h" +#include "nodes.h" +#include <errno.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(exec, 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(exec, 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 = 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* globalFuncEval(ExecState* exec, JSObject* function, JSValue* thisValue, const ArgList& args) +{ + JSObject* thisObject = thisValue->toThisObject(exec); + JSGlobalObject* globalObject = thisObject->toGlobalObject(exec); + if (!globalObject || globalObject->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(exec, 0); + if (!x->isString()) + return x; + + UString s = x->toString(exec); + + 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->machine()->execute(evalNode.get(), exec, thisObject, globalObject->globalScopeChain().node(), exec->exceptionSlot()); +} + +JSValue* globalFuncParseInt(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + JSValue* value = args.at(exec, 0); + int32_t radix = args.at(exec, 1)->toInt32(exec); + + if (value->isNumber() && (radix == 0 || radix == 10)) { + if (JSImmediate::isImmediate(value)) + return value; + double d = value->uncheckedGetNumber(); + if (!isfinite(d)) + return JSImmediate::zeroImmediate(); + return jsNumber(exec, floor(d)); + } + + return jsNumber(exec, parseInt(value->toString(exec), radix)); +} + +JSValue* globalFuncParseFloat(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + return jsNumber(exec, parseFloat(args.at(exec, 0)->toString(exec))); +} + +JSValue* globalFuncIsNaN(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + return jsBoolean(isnan(args.at(exec, 0)->toNumber(exec))); +} + +JSValue* globalFuncIsFinite(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + double n = args.at(exec, 0)->toNumber(exec); + return jsBoolean(!isnan(n) && !isinf(n)); +} + +JSValue* 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* globalFuncDecodeURIComponent(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + return decode(exec, args, "", true); +} + +JSValue* 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* 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* 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(exec, 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* globalFuncUnescape(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + UString result = ""; + UString str = args.at(exec, 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 (Lexer::isHexDigit(c[2]) && Lexer::isHexDigit(c[3]) && Lexer::isHexDigit(c[4]) && Lexer::isHexDigit(c[5])) { + u = Lexer::convertUnicode(c[2], c[3], c[4], c[5]); + c = &u; + k += 5; + } + } else if (c[0] == '%' && k <= len - 3 && Lexer::isHexDigit(c[1]) && Lexer::isHexDigit(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* globalFuncKJSPrint(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + CStringBuffer string; + args.at(exec, 0)->toString(exec).getCString(string); + puts(string.data()); + return jsUndefined(); +} +#endif + +} // namespace JSC diff --git a/JavaScriptCore/runtime/JSGlobalObjectFunctions.h b/JavaScriptCore/runtime/JSGlobalObjectFunctions.h new file mode 100644 index 0000000..8df700d --- /dev/null +++ b/JavaScriptCore/runtime/JSGlobalObjectFunctions.h @@ -0,0 +1,58 @@ +/* + * 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 JSGlobalObjectFunctions_h +#define JSGlobalObjectFunctions_h + +#include "JSImmediate.h" // temporary until JSValue* becomes a class we can forward-declare + +namespace JSC { + + class ArgList; + class ExecState; + class JSObject; + + // FIXME: These functions should really be in JSGlobalObject.cpp, but putting them there + // is a 0.5% reduction. + + JSValue* globalFuncEval(ExecState*, JSObject*, JSValue*, const ArgList&); + JSValue* globalFuncParseInt(ExecState*, JSObject*, JSValue*, const ArgList&); + JSValue* globalFuncParseFloat(ExecState*, JSObject*, JSValue*, const ArgList&); + JSValue* globalFuncIsNaN(ExecState*, JSObject*, JSValue*, const ArgList&); + JSValue* globalFuncIsFinite(ExecState*, JSObject*, JSValue*, const ArgList&); + JSValue* globalFuncDecodeURI(ExecState*, JSObject*, JSValue*, const ArgList&); + JSValue* globalFuncDecodeURIComponent(ExecState*, JSObject*, JSValue*, const ArgList&); + JSValue* globalFuncEncodeURI(ExecState*, JSObject*, JSValue*, const ArgList&); + JSValue* globalFuncEncodeURIComponent(ExecState*, JSObject*, JSValue*, const ArgList&); + JSValue* globalFuncEscape(ExecState*, JSObject*, JSValue*, const ArgList&); + JSValue* globalFuncUnescape(ExecState*, JSObject*, JSValue*, const ArgList&); +#ifndef NDEBUG + JSValue* globalFuncKJSPrint(ExecState*, JSObject*, JSValue*, const ArgList&); +#endif + + static const double mantissaOverflowLowerBound = 9007199254740992.0; + double parseIntOverflow(const char*, int length, int radix); + +} // namespace JSC + +#endif // JSGlobalObjectFunctions_h diff --git a/JavaScriptCore/runtime/JSImmediate.cpp b/JavaScriptCore/runtime/JSImmediate.cpp new file mode 100644 index 0000000..e70d66a --- /dev/null +++ b/JavaScriptCore/runtime/JSImmediate.cpp @@ -0,0 +1,81 @@ +/* + * 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::toObject(JSValue* v, ExecState* exec) +{ + ASSERT(isImmediate(v)); + if (isNumber(v)) + return constructNumberFromImmediateNumber(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 (isNumber(v)) + return UString::from(getTruncatedInt32(v)); + if (v == jsBoolean(false)) + return "false"; + if (v == jsBoolean(true)) + return "true"; + if (v->isNull()) + return "null"; + ASSERT(v == jsUndefined()); + return "undefined"; +} + +NEVER_INLINE double JSImmediate::nonInlineNaN() +{ + return std::numeric_limits<double>::quiet_NaN(); +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/JSImmediate.h b/JavaScriptCore/runtime/JSImmediate.h new file mode 100644 index 0000000..5214df5 --- /dev/null +++ b/JavaScriptCore/runtime/JSImmediate.h @@ -0,0 +1,468 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 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 KJS_JS_IMMEDIATE_H +#define KJS_JS_IMMEDIATE_H + +#include <wtf/Assertions.h> +#include <wtf/AlwaysInline.h> +#include <wtf/MathExtras.h> +#include <limits> +#include <limits.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdlib.h> + +namespace JSC { + + class ExecState; + class JSCell; + class JSObject; + class JSValue; + class UString; + + inline JSValue* noValue() { return 0; } + inline void* asPointer(JSValue* value) { return value; } + + /* + * A JSValue* is either a pointer to a cell (a heap-allocated object) or an immediate (a type-tagged + * value masquerading as a pointer). The low two bits in a JSValue* are available for type tagging + * because allocator alignment guarantees they will be 00 in cell pointers. + * + * For example, on a 32 bit system: + * + * JSCell*: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 00 + * [ high 30 bits: pointer address ] [ low 2 bits -- always 0 ] + * JSImmediate: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX TT + * [ high 30 bits: 'payload' ] [ low 2 bits -- tag ] + * + * Where the bottom two bits are non-zero they either indicate that the immediate is a 31 bit signed + * integer, or they mark the value as being an immediate of a type other than integer, with a secondary + * tag used to indicate the exact type. + * + * Where the lowest bit is set (TT is equal to 01 or 11) the high 31 bits form a 31 bit signed int value. + * Where TT is equal to 10 this indicates this is a type of immediate other than an integer, and the next + * two bits will form an extended tag. + * + * 31 bit signed int: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X1 + * [ high 30 bits of the value ] [ high bit part of value ] + * Other: YYYYYYYYYYYYYYYYYYYYYYYYYYYY ZZ 10 + * [ extended 'payload' ] [ extended tag ] [ tag 'other' ] + * + * Where the first bit of the extended tag is set this flags the value as being a boolean, and the following + * bit would flag the value as undefined. If neither bits are set, the value is null. + * + * Other: YYYYYYYYYYYYYYYYYYYYYYYYYYYY UB 10 + * [ extended 'payload' ] [ undefined | bool ] [ tag 'other' ] + * + * For boolean value the lowest bit in the payload holds the value of the bool, all remaining bits are zero. + * For undefined or null immediates the payload is zero. + * + * Boolean: 000000000000000000000000000V 01 10 + * [ boolean value ] [ bool ] [ tag 'other' ] + * Undefined: 0000000000000000000000000000 10 10 + * [ zero ] [ undefined ] [ tag 'other' ] + * Null: 0000000000000000000000000000 00 10 + * [ zero ] [ zero ] [ tag 'other' ] + */ + + class JSImmediate { + private: + friend class CTI; // Whooo! + + static const uintptr_t TagMask = 0x3u; // primary tag is 2 bits long + static const uintptr_t TagBitTypeInteger = 0x1u; // bottom bit set indicates integer, this dominates the following bit + static const uintptr_t TagBitTypeOther = 0x2u; // second bit set indicates immediate other than an integer + + static const uintptr_t ExtendedTagMask = 0xCu; // extended tag holds a further two bits + static const uintptr_t ExtendedTagBitBool = 0x4u; + static const uintptr_t ExtendedTagBitUndefined = 0x8u; + + static const uintptr_t FullTagTypeMask = TagMask | ExtendedTagMask; + static const uintptr_t FullTagTypeBool = TagBitTypeOther | ExtendedTagBitBool; + static const uintptr_t FullTagTypeUndefined = TagBitTypeOther | ExtendedTagBitUndefined; + static const uintptr_t FullTagTypeNull = TagBitTypeOther; + + static const uint32_t IntegerPayloadShift = 1u; + static const uint32_t ExtendedPayloadShift = 4u; + + static const uintptr_t ExtendedPayloadBitBoolValue = 1 << ExtendedPayloadShift; + + public: + static ALWAYS_INLINE bool isImmediate(JSValue* v) + { + return rawValue(v) & TagMask; + } + + static ALWAYS_INLINE bool isNumber(JSValue* v) + { + return rawValue(v) & TagBitTypeInteger; + } + + static ALWAYS_INLINE bool isPositiveNumber(JSValue* v) + { + // A single mask to check for the sign bit and the number tag all at once. + return (rawValue(v) & (0x80000000 | TagBitTypeInteger)) == TagBitTypeInteger; + } + + 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 bool isNegative(JSValue* v) + { + ASSERT(isNumber(v)); + return rawValue(v) & 0x80000000; + } + + 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 isAnyImmediate(JSValue* v1, JSValue* v2, JSValue* v3) + { + return (rawValue(v1) | rawValue(v2) | rawValue(v3)) & TagMask; + } + + static ALWAYS_INLINE bool areBothImmediate(JSValue* v1, JSValue* v2) + { + return isImmediate(v1) & isImmediate(v2); + } + + static ALWAYS_INLINE bool areBothImmediateNumbers(JSValue* v1, JSValue* v2) + { + return rawValue(v1) & rawValue(v2) & TagBitTypeInteger; + } + + static ALWAYS_INLINE JSValue* andImmediateNumbers(JSValue* v1, JSValue* v2) + { + ASSERT(areBothImmediateNumbers(v1, v2)); + return makeValue(rawValue(v1) & rawValue(v2)); + } + + static ALWAYS_INLINE JSValue* xorImmediateNumbers(JSValue* v1, JSValue* v2) + { + ASSERT(areBothImmediateNumbers(v1, v2)); + return makeValue((rawValue(v1) ^ rawValue(v2)) | TagBitTypeInteger); + } + + static ALWAYS_INLINE JSValue* orImmediateNumbers(JSValue* v1, JSValue* v2) + { + ASSERT(areBothImmediateNumbers(v1, v2)); + return makeValue(rawValue(v1) | rawValue(v2)); + } + + static ALWAYS_INLINE JSValue* rightShiftImmediateNumbers(JSValue* val, JSValue* shift) + { + ASSERT(areBothImmediateNumbers(val, shift)); + return makeValue((static_cast<intptr_t>(rawValue(val)) >> ((rawValue(shift) >> IntegerPayloadShift) & 0x1f)) | TagBitTypeInteger); + } + + 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 (rawValue(v) & (TagBitTypeInteger + (3u << 30))) == TagBitTypeInteger; + } + + static ALWAYS_INLINE JSValue* addImmediateNumbers(JSValue* v1, JSValue* v2) + { + ASSERT(canDoFastAdditiveOperations(v1)); + ASSERT(canDoFastAdditiveOperations(v2)); + return makeValue(rawValue(v1) + rawValue(v2) - TagBitTypeInteger); + } + + static ALWAYS_INLINE JSValue* subImmediateNumbers(JSValue* v1, JSValue* v2) + { + ASSERT(canDoFastAdditiveOperations(v1)); + ASSERT(canDoFastAdditiveOperations(v2)); + return makeValue(rawValue(v1) - rawValue(v2) + TagBitTypeInteger); + } + + static ALWAYS_INLINE JSValue* incImmediateNumber(JSValue* v) + { + ASSERT(canDoFastAdditiveOperations(v)); + return makeValue(rawValue(v) + (1 << IntegerPayloadShift)); + } + + static ALWAYS_INLINE JSValue* decImmediateNumber(JSValue* v) + { + ASSERT(canDoFastAdditiveOperations(v)); + return makeValue(rawValue(v) - (1 << IntegerPayloadShift)); + } + + static double toDouble(JSValue*); + static bool toBoolean(JSValue*); + static JSObject* toObject(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 JSValue* impossibleValue(); + + static JSObject* prototype(JSValue*, ExecState*); + + private: + static const int minImmediateInt = ((-INT_MAX) - 1) >> IntegerPayloadShift; + static const int maxImmediateInt = INT_MAX >> IntegerPayloadShift; + static const unsigned maxImmediateUInt = maxImmediateInt; + + static ALWAYS_INLINE JSValue* makeValue(uintptr_t integer) + { + return reinterpret_cast<JSValue*>(integer); + } + + static ALWAYS_INLINE JSValue* makeInt(int32_t value) + { + return makeValue((value << IntegerPayloadShift) | TagBitTypeInteger); + } + + static ALWAYS_INLINE JSValue* makeBool(bool b) + { + return makeValue((static_cast<uintptr_t>(b) << ExtendedPayloadShift) | FullTagTypeBool); + } + + static ALWAYS_INLINE JSValue* makeUndefined() + { + return makeValue(FullTagTypeUndefined); + } + + static ALWAYS_INLINE JSValue* makeNull() + { + return makeValue(FullTagTypeNull); + } + + static ALWAYS_INLINE int32_t intValue(JSValue* v) + { + return static_cast<int32_t>(static_cast<intptr_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 uintptr_t rawValue(JSValue* v) + { + return reinterpret_cast<uintptr_t>(v); + } + + 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); } + + // This value is impossible because 0x4 is not a valid pointer but a tag of 0 would indicate non-immediate + ALWAYS_INLINE JSValue* JSImmediate::impossibleValue() { return makeValue(0x4); } + + ALWAYS_INLINE bool JSImmediate::toBoolean(JSValue* v) + { + ASSERT(isImmediate(v)); + uintptr_t bits = rawValue(v); + return (bits & TagBitTypeInteger) + ? bits != TagBitTypeInteger // !0 ints + : bits == (FullTagTypeBool | ExtendedPayloadBitBoolValue); // bool true + } + + ALWAYS_INLINE uint32_t JSImmediate::getTruncatedUInt32(JSValue* v) + { + ASSERT(isNumber(v)); + return intValue(v); + } + + 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 ((i < minImmediateInt) | (i > maxImmediateInt)) + return noValue(); + return makeInt(i); + } + + ALWAYS_INLINE JSValue* JSImmediate::from(unsigned i) + { + if (i > maxImmediateUInt) + return noValue(); + return makeInt(i); + } + + ALWAYS_INLINE JSValue* JSImmediate::from(long i) + { + if ((i < minImmediateInt) | (i > maxImmediateInt)) + return noValue(); + return makeInt(i); + } + + ALWAYS_INLINE JSValue* JSImmediate::from(unsigned long i) + { + if (i > maxImmediateUInt) + return noValue(); + return makeInt(i); + } + + ALWAYS_INLINE JSValue* JSImmediate::from(long long i) + { + if ((i < minImmediateInt) | (i > maxImmediateInt)) + return noValue(); + return makeInt(static_cast<uintptr_t>(i)); + } + + ALWAYS_INLINE JSValue* JSImmediate::from(unsigned long long i) + { + if (i > maxImmediateUInt) + return noValue(); + return makeInt(static_cast<uintptr_t>(i)); + } + + ALWAYS_INLINE JSValue* JSImmediate::from(double d) + { + const int intVal = static_cast<int>(d); + + if ((intVal < minImmediateInt) | (intVal > maxImmediateInt)) + return noValue(); + + // Check for data loss from conversion to int. + if (intVal != d || (!intVal && signbit(d))) + return noValue(); + + return makeInt(intVal); + } + + ALWAYS_INLINE int32_t JSImmediate::getTruncatedInt32(JSValue* v) + { + ASSERT(isNumber(v)); + return intValue(v); + } + + ALWAYS_INLINE double JSImmediate::toDouble(JSValue* v) + { + ASSERT(isImmediate(v)); + int i; + if (isNumber(v)) + i = intValue(v); + else if (rawValue(v) == FullTagTypeUndefined) + return nonInlineNaN(); + else + i = rawValue(v) >> ExtendedPayloadShift; + return i; + } + + ALWAYS_INLINE bool JSImmediate::getUInt32(JSValue* v, uint32_t& i) + { + i = uintValue(v); + return isPositiveNumber(v); + } + + ALWAYS_INLINE bool JSImmediate::getTruncatedInt32(JSValue* v, int32_t& i) + { + i = intValue(v); + return isNumber(v); + } + + ALWAYS_INLINE bool JSImmediate::getTruncatedUInt32(JSValue* v, uint32_t& i) + { + return getUInt32(v, i); + } + + ALWAYS_INLINE JSValue* jsUndefined() + { + return JSImmediate::undefinedImmediate(); + } + + inline JSValue* jsNull() + { + return JSImmediate::nullImmediate(); + } + + inline JSValue* jsBoolean(bool b) + { + return b ? JSImmediate::trueImmediate() : JSImmediate::falseImmediate(); + } + +} // namespace JSC + +#endif diff --git a/JavaScriptCore/runtime/JSLock.cpp b/JavaScriptCore/runtime/JSLock.cpp new file mode 100644 index 0000000..ee7fb3b --- /dev/null +++ b/JavaScriptCore/runtime/JSLock.cpp @@ -0,0 +1,200 @@ +/* + * 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 "ExecState.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_lockingForReal(exec->globalData().isSharedInstance) +{ + lock(m_lockingForReal); +} + +void JSLock::lock(bool lockForReal) +{ +#ifdef NDEBUG + // Locking "not for real" is a debug-only feature. + if (!lockForReal) + return; +#endif + + pthread_once(&createJSLockCountOnce, createJSLockCount); + + intptr_t currentLockCount = lockCount(); + if (!currentLockCount && lockForReal) { + int result; + result = pthread_mutex_lock(&JSMutex); + ASSERT(!result); + } + setLockCount(currentLockCount + 1); +} + +void JSLock::unlock(bool lockForReal) +{ + ASSERT(lockCount()); + +#ifdef NDEBUG + // Locking "not for real" is a debug-only feature. + if (!lockForReal) + return; +#endif + + intptr_t newLockCount = lockCount() - 1; + setLockCount(newLockCount); + if (!newLockCount && lockForReal) { + int result; + result = pthread_mutex_unlock(&JSMutex); + ASSERT(!result); + } +} + +void JSLock::lock(ExecState* exec) +{ + lock(exec->globalData().isSharedInstance); +} + +void JSLock::unlock(ExecState* exec) +{ + unlock(exec->globalData().isSharedInstance); +} + +bool JSLock::currentThreadIsHoldingLock() +{ + pthread_once(&createJSLockCountOnce, createJSLockCount); + return !!pthread_getspecific(JSLockCount); +} + +JSLock::DropAllLocks::DropAllLocks(ExecState* exec) + : m_lockingForReal(exec->globalData().isSharedInstance) +{ + pthread_once(&createJSLockCountOnce, createJSLockCount); + + m_lockCount = JSLock::lockCount(); + for (intptr_t i = 0; i < m_lockCount; i++) + JSLock::unlock(m_lockingForReal); +} + +JSLock::DropAllLocks::DropAllLocks(bool lockingForReal) + : m_lockingForReal(lockingForReal) +{ + pthread_once(&createJSLockCountOnce, createJSLockCount); + + // 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_lockingForReal); +} + +JSLock::DropAllLocks::~DropAllLocks() +{ + for (intptr_t i = 0; i < m_lockCount; i++) + JSLock::lock(m_lockingForReal); +} + +#else + +JSLock::JSLock(ExecState*) + : m_lockingForReal(false) +{ +} + +// 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(bool) +{ +} + +void JSLock::unlock(bool) +{ +} + +void JSLock::lock(ExecState*) +{ +} + +void JSLock::unlock(ExecState*) +{ +} + +JSLock::DropAllLocks::DropAllLocks(ExecState*) +{ +} + +JSLock::DropAllLocks::DropAllLocks(bool) +{ +} + +JSLock::DropAllLocks::~DropAllLocks() +{ +} + +#endif // USE(MULTIPLE_THREADS) + +} // namespace JSC diff --git a/JavaScriptCore/runtime/JSLock.h b/JavaScriptCore/runtime/JSLock.h new file mode 100644 index 0000000..0c22ff8 --- /dev/null +++ b/JavaScriptCore/runtime/JSLock.h @@ -0,0 +1,102 @@ +/* + * 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. + * + */ + +#ifndef KJS_JSLock_h +#define KJS_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; + + class JSLock : Noncopyable { + public: + JSLock(ExecState*); + + JSLock(bool lockingForReal) + : m_lockingForReal(lockingForReal) + { +#ifdef NDEBUG + // Locking "not for real" is a debug-only feature. + if (!lockingForReal) + return; +#endif + lock(lockingForReal); + } + + ~JSLock() + { +#ifdef NDEBUG + // Locking "not for real" is a debug-only feature. + if (!m_lockingForReal) + return; +#endif + unlock(m_lockingForReal); + } + + static void lock(bool); + static void unlock(bool); + static void lock(ExecState*); + static void unlock(ExecState*); + + static intptr_t lockCount(); + static bool currentThreadIsHoldingLock(); + + bool m_lockingForReal; + + class DropAllLocks : Noncopyable { + public: + DropAllLocks(ExecState* exec); + DropAllLocks(bool); + ~DropAllLocks(); + + private: + intptr_t m_lockCount; + bool m_lockingForReal; + }; + }; + +} // namespace + +#endif // KJS_JSLock_h diff --git a/JavaScriptCore/runtime/JSNotAnObject.cpp b/JavaScriptCore/runtime/JSNotAnObject.cpp new file mode 100644 index 0000000..c4ca8fd --- /dev/null +++ b/JavaScriptCore/runtime/JSNotAnObject.cpp @@ -0,0 +1,137 @@ +/* + * 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 +{ + UNUSED_PARAM(exec); + ASSERT(exec->hadException() && exec->exception() == m_exception); + return m_exception; +} + +bool JSNotAnObject::getPrimitiveNumber(ExecState* exec, double&, JSValue*&) +{ + UNUSED_PARAM(exec); + ASSERT(exec->hadException() && exec->exception() == m_exception); + return false; +} + +bool JSNotAnObject::toBoolean(ExecState* exec) const +{ + UNUSED_PARAM(exec); + ASSERT(exec->hadException() && exec->exception() == m_exception); + return false; +} + +double JSNotAnObject::toNumber(ExecState* exec) const +{ + UNUSED_PARAM(exec); + ASSERT(exec->hadException() && exec->exception() == m_exception); + return NaN; +} + +UString JSNotAnObject::toString(ExecState* exec) const +{ + UNUSED_PARAM(exec); + ASSERT(exec->hadException() && exec->exception() == m_exception); + return ""; +} + +JSObject* JSNotAnObject::toObject(ExecState* exec) const +{ + UNUSED_PARAM(exec); + ASSERT(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&) +{ + UNUSED_PARAM(exec); + ASSERT(exec->hadException() && exec->exception() == m_exception); + return false; +} + +bool JSNotAnObject::getOwnPropertySlot(ExecState* exec, unsigned, PropertySlot&) +{ + UNUSED_PARAM(exec); + ASSERT(exec->hadException() && exec->exception() == m_exception); + return false; +} + +void JSNotAnObject::put(ExecState* exec, const Identifier& , JSValue*, PutPropertySlot&) +{ + UNUSED_PARAM(exec); + ASSERT(exec->hadException() && exec->exception() == m_exception); +} + +void JSNotAnObject::put(ExecState* exec, unsigned, JSValue*) +{ + UNUSED_PARAM(exec); + ASSERT(exec->hadException() && exec->exception() == m_exception); +} + +bool JSNotAnObject::deleteProperty(ExecState* exec, const Identifier&) +{ + UNUSED_PARAM(exec); + ASSERT(exec->hadException() && exec->exception() == m_exception); + return false; +} + +bool JSNotAnObject::deleteProperty(ExecState* exec, unsigned) +{ + UNUSED_PARAM(exec); + ASSERT(exec->hadException() && exec->exception() == m_exception); + return false; +} + +void JSNotAnObject::getPropertyNames(ExecState* exec, PropertyNameArray&) +{ + UNUSED_PARAM(exec); + ASSERT(exec->hadException() && exec->exception() == m_exception); +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/JSNotAnObject.h b/JavaScriptCore/runtime/JSNotAnObject.h new file mode 100644 index 0000000..b6e2931 --- /dev/null +++ b/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 opcodes -- 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<StructureID> createStructureID(JSValue* prototype) + { + return StructureID::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&); + + JSNotAnObjectErrorStub* m_exception; + }; + +} // namespace JSC + +#endif // JSNotAnObject_h diff --git a/JavaScriptCore/runtime/JSNumberCell.cpp b/JavaScriptCore/runtime/JSNumberCell.cpp new file mode 100644 index 0000000..5b3f3bd --- /dev/null +++ b/JavaScriptCore/runtime/JSNumberCell.cpp @@ -0,0 +1,124 @@ +/* + * 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 { + +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; +} + +NEVER_INLINE JSValue* jsNumberCell(ExecState* exec, double d) +{ + return new (exec) JSNumberCell(exec, d); +} + +NEVER_INLINE JSValue* jsNaN(ExecState* exec) +{ + return new (exec) JSNumberCell(exec, NaN); +} + +NEVER_INLINE JSValue* jsNumberCell(JSGlobalData* globalData, double d) +{ + return new (globalData) JSNumberCell(globalData, d); +} + +NEVER_INLINE JSValue* jsNaN(JSGlobalData* globalData) +{ + return new (globalData) JSNumberCell(globalData, NaN); +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/JSNumberCell.h b/JavaScriptCore/runtime/JSNumberCell.h new file mode 100644 index 0000000..e2f6990 --- /dev/null +++ b/JavaScriptCore/runtime/JSNumberCell.h @@ -0,0 +1,267 @@ +/* + * 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 "ExecState.h" +#include "JSCell.h" +#include "JSImmediate.h" +#include "collector.h" +#include "ustring.h" +#include <stddef.h> // for size_t + +namespace JSC { + + class Identifier; + class JSCell; + class JSObject; + class JSString; + class PropertySlot; + + struct ClassInfo; + struct Instruction; + + class JSNumberCell : public JSCell { + friend class CTI; + friend JSValue* jsNumberCell(JSGlobalData*, double); + friend JSValue* jsNaN(JSGlobalData*); + friend JSValue* jsNumberCell(ExecState*, double); + friend JSValue* jsNaN(ExecState*); + 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(); + + int32_t toInt32() const; + uint32_t toUInt32() const; + + 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<StructureID> createStructureID(JSValue* proto) { return StructureID::create(proto, TypeInfo(NumberType, NeedsThisConversion)); } + + JSNumberCell(JSGlobalData* globalData) + : JSCell(globalData->numberStructureID.get()) + { + } + + private: + JSNumberCell(JSGlobalData* globalData, double value) + : JSCell(globalData->numberStructureID.get()) + , m_value(value) + { + } + + JSNumberCell(ExecState* exec, double value) + : JSCell(exec->globalData().numberStructureID.get()) + , m_value(value) + { + } + + virtual bool getUInt32(uint32_t&) const; + virtual bool getTruncatedInt32(int32_t&) const; + virtual bool getTruncatedUInt32(uint32_t&) const; + + double m_value; + }; + + extern const double NaN; + extern const double Inf; + + JSNumberCell* asNumberCell(JSValue*); + + JSValue* jsNumberCell(JSGlobalData*, double); + JSValue* jsNaN(JSGlobalData*); + JSValue* jsNumberCell(ExecState*, double); + JSValue* jsNaN(ExecState*); + + inline JSNumberCell* asNumberCell(JSValue* value) + { + ASSERT(asCell(value)->isNumber()); + return static_cast<JSNumberCell*>(asCell(value)); + } + + ALWAYS_INLINE JSValue* jsNumber(ExecState* exec, double d) + { + JSValue* v = JSImmediate::from(d); + return v ? v : jsNumberCell(exec, d); + } + + ALWAYS_INLINE JSValue* jsNumber(ExecState* exec, short i) + { + JSValue* v = JSImmediate::from(i); + return v ? v : jsNumberCell(exec, i); + } + + ALWAYS_INLINE JSValue* jsNumber(ExecState* exec, unsigned short i) + { + JSValue* v = JSImmediate::from(i); + return v ? v : jsNumberCell(exec, i); + } + + ALWAYS_INLINE JSValue* jsNumber(ExecState* exec, int i) + { + JSValue* v = JSImmediate::from(i); + return v ? v : jsNumberCell(exec, i); + } + + ALWAYS_INLINE JSValue* jsNumber(ExecState* exec, unsigned i) + { + JSValue* v = JSImmediate::from(i); + return v ? v : jsNumberCell(exec, i); + } + + ALWAYS_INLINE JSValue* jsNumber(ExecState* exec, long i) + { + JSValue* v = JSImmediate::from(i); + return v ? v : jsNumberCell(exec, i); + } + + ALWAYS_INLINE JSValue* jsNumber(ExecState* exec, unsigned long i) + { + JSValue* v = JSImmediate::from(i); + return v ? v : jsNumberCell(exec, i); + } + + ALWAYS_INLINE JSValue* jsNumber(ExecState* exec, long long i) + { + JSValue* v = JSImmediate::from(i); + return v ? v : jsNumberCell(exec, static_cast<double>(i)); + } + + ALWAYS_INLINE JSValue* jsNumber(ExecState* exec, unsigned long long i) + { + JSValue* v = JSImmediate::from(i); + return v ? v : jsNumberCell(exec, static_cast<double>(i)); + } + + ALWAYS_INLINE JSValue* jsNumber(JSGlobalData* globalData, double d) + { + JSValue* v = JSImmediate::from(d); + return v ? v : jsNumberCell(globalData, d); + } + + ALWAYS_INLINE JSValue* jsNumber(JSGlobalData* globalData, short i) + { + JSValue* v = JSImmediate::from(i); + return v ? v : jsNumberCell(globalData, i); + } + + ALWAYS_INLINE JSValue* jsNumber(JSGlobalData* globalData, unsigned short i) + { + JSValue* v = JSImmediate::from(i); + return v ? v : jsNumberCell(globalData, i); + } + + ALWAYS_INLINE JSValue* jsNumber(JSGlobalData* globalData, int i) + { + JSValue* v = JSImmediate::from(i); + return v ? v : jsNumberCell(globalData, i); + } + + ALWAYS_INLINE JSValue* jsNumber(JSGlobalData* globalData, unsigned i) + { + JSValue* v = JSImmediate::from(i); + return v ? v : jsNumberCell(globalData, i); + } + + ALWAYS_INLINE JSValue* jsNumber(JSGlobalData* globalData, long i) + { + JSValue* v = JSImmediate::from(i); + return v ? v : jsNumberCell(globalData, i); + } + + ALWAYS_INLINE JSValue* jsNumber(JSGlobalData* globalData, unsigned long i) + { + JSValue* v = JSImmediate::from(i); + return v ? v : jsNumberCell(globalData, i); + } + + ALWAYS_INLINE JSValue* jsNumber(JSGlobalData* globalData, long long i) + { + JSValue* v = JSImmediate::from(i); + return v ? v : jsNumberCell(globalData, static_cast<double>(i)); + } + + ALWAYS_INLINE JSValue* jsNumber(JSGlobalData* globalData, unsigned long long i) + { + JSValue* v = JSImmediate::from(i); + return v ? v : jsNumberCell(globalData, static_cast<double>(i)); + } + + // --- JSValue inlines ---------------------------- + + inline double JSValue::uncheckedGetNumber() const + { + ASSERT(JSImmediate::isImmediate(asValue()) || asCell()->isNumber()); + return JSImmediate::isImmediate(asValue()) ? JSImmediate::toDouble(asValue()) : asNumberCell(asValue())->value(); + } + + inline int32_t JSNumberCell::toInt32() const + { + if (m_value >= -2147483648.0 && m_value < 2147483648.0) + return static_cast<int32_t>(m_value); + bool scratch; + return JSC::toInt32SlowCase(m_value, scratch); + } + + inline uint32_t JSNumberCell::toUInt32() const + { + if (m_value >= 0.0 && m_value < 4294967296.0) + return static_cast<uint32_t>(m_value); + bool scratch; + return JSC::toUInt32SlowCase(m_value, scratch); + } + + ALWAYS_INLINE JSValue* JSValue::toJSNumber(ExecState* exec) const + { + return JSImmediate::isNumber(asValue()) ? asValue() : jsNumber(exec, this->toNumber(exec)); + } + +} // namespace JSC + +#endif // JSNumberCell_h diff --git a/JavaScriptCore/runtime/JSObject.cpp b/JavaScriptCore/runtime/JSObject.cpp new file mode 100644 index 0000000..82c1c63 --- /dev/null +++ b/JavaScriptCore/runtime/JSObject.cpp @@ -0,0 +1,516 @@ +/* + * 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_structureID->mark(); + + size_t storageSize = m_structureID->propertyStorageSize(); + for (size_t i = 0; i < storageSize; ++i) { + JSValue* v = m_propertyStorage[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) { + JSObject* proto = value->getObject(); + + // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla. + if (!proto && !value->isNull()) + return; + + while (proto) { + if (proto == this) { + throwError(exec, GeneralError, "cyclic __proto__ value"); + return; + } + proto = proto->prototype() ? proto->prototype()->getObject() : 0; + } + + setPrototype(value); + return; + } + + // Check if there are any setters or getters in the prototype chain + JSValue* prototype; + for (JSObject* obj = this; !obj->structureID()->hasGetterSetterProperties(); obj = asObject(prototype)) { + prototype = obj->prototype(); + if (prototype->isNull()) { + putDirect(propertyName, value, 0, true, slot); + return; + } + } + + unsigned attributes; + if ((m_structureID->get(propertyName, attributes) != 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); + ArgList 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; + } + + putDirect(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*, const Identifier& propertyName, JSValue* value, unsigned attributes) +{ + putDirect(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) +{ + unsigned attributes; + if (m_structureID->get(propertyName, attributes) != WTF::notFound) { + if ((attributes & DontDelete)) + return false; + removeDirect(propertyName); + return true; + } + + // Look in the static hashtable of properties + const HashEntry* entry = findPropertyHashEntry(exec, propertyName); + if (entry && entry->attributes() & DontDelete) + 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) +{ + return deleteProperty(exec, Identifier::from(exec, propertyName)); +} + +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 noValue(); + 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())) { + if (JSValue* value = callDefaultValueFunction(exec, this, exec->propertyNames().toString)) + return value; + if (JSValue* value = callDefaultValueFunction(exec, this, exec->propertyNames().valueOf)) + return value; + } else { + if (JSValue* value = callDefaultValueFunction(exec, this, exec->propertyNames().valueOf)) + return value; + if (JSValue* value = callDefaultValueFunction(exec, this, exec->propertyNames().toString)) + 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_structureID->hasGetterSetterProperties()); + asGetterSetter(object)->setGetter(getterFunction); + return; + } + + PutPropertySlot slot; + GetterSetter* getterSetter = new (exec) GetterSetter; + putDirect(propertyName, getterSetter, None, true, slot); + + // putDirect will change our StructureID if we add a new property. For + // getters and setters, though, we also need to change our StructureID + // if we override an existing non-getter or non-setter. + if (slot.type() != PutPropertySlot::NewProperty) { + if (!m_structureID->isDictionary()) { + RefPtr<StructureID> structureID = StructureID::getterSetterTransition(m_structureID); + setStructureID(structureID.release()); + } + } + + m_structureID->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_structureID->hasGetterSetterProperties()); + asGetterSetter(object)->setSetter(setterFunction); + return; + } + + PutPropertySlot slot; + GetterSetter* getterSetter = new (exec) GetterSetter; + putDirect(propertyName, getterSetter, None, true, slot); + + // putDirect will change our StructureID if we add a new property. For + // getters and setters, though, we also need to change our StructureID + // if we override an existing non-getter or non-setter. + if (slot.type() != PutPropertySlot::NewProperty) { + if (!m_structureID->isDictionary()) { + RefPtr<StructureID> structureID = StructureID::getterSetterTransition(m_structureID); + setStructureID(structureID.release()); + } + } + + m_structureID->setHasGetterSetterProperties(true); + getterSetter->setSetter(setterFunction); +} + +JSValue* JSObject::lookupGetter(ExecState*, const Identifier& propertyName) +{ + JSObject* object = this; + while (true) { + JSValue* value = object->getDirect(propertyName); + if (value) { + 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) { + JSValue* value = object->getDirect(propertyName); + if (value) { + 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 (!proto->isObject()) { + throwError(exec, TypeError, "instanceof called on an object with an invalid prototype property."); + return false; + } + + if (!value->isObject()) + return false; + + JSObject* object = asObject(value); + while ((object = object->prototype()->getObject())) { + if (object == proto) + 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 +{ + if (m_structureID->get(propertyName, attributes) != 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; +} + +void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) +{ + m_structureID->getEnumerablePropertyNames(exec, propertyNames, this); +} + +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); +} + +JSGlobalObject* JSObject::toGlobalObject(ExecState*) const +{ + return 0; +} + +void JSObject::removeDirect(const Identifier& propertyName) +{ + size_t offset; + if (m_structureID->isDictionary()) { + offset = m_structureID->removePropertyWithoutTransition(propertyName); + if (offset != WTF::notFound) + m_propertyStorage[offset] = jsUndefined(); + return; + } + + RefPtr<StructureID> structureID = StructureID::removePropertyTransition(m_structureID, propertyName, offset); + if (offset != WTF::notFound) + m_propertyStorage[offset] = jsUndefined(); + setStructureID(structureID.release()); +} + +void JSObject::putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr) +{ + putDirect(Identifier(exec, function->name(&exec->globalData())), function, attr); +} + +void JSObject::putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr) +{ + putDirectWithoutTransition(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(); +} + +StructureID* JSObject::createInheritorID() +{ + m_inheritorID = JSObject::createStructureID(this); + 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/JavaScriptCore/runtime/JSObject.h b/JavaScriptCore/runtime/JSObject.h new file mode 100644 index 0000000..d280b64 --- /dev/null +++ b/JavaScriptCore/runtime/JSObject.h @@ -0,0 +1,541 @@ +/* + * 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 "ExecState.h" +#include "JSNumberCell.h" +#include "PropertySlot.h" +#include "PutPropertySlot.h" +#include "ScopeChain.h" +#include "StructureID.h" + +namespace JSC { + + class InternalFunction; + class PropertyNameArray; + class StructureID; + 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 + }; + + typedef JSValue** PropertyStorage; + + class JSObject : public JSCell { + friend class BatchedTransitionOptimizer; + friend class CTI; + friend class JSCell; + + public: + explicit JSObject(PassRefPtr<StructureID>); + + 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 setStructureID(PassRefPtr<StructureID>); + StructureID* inheritorID(); + + PropertyStorage& propertyStorage() { return m_propertyStorage; } + + 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); + 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); + virtual bool deleteProperty(ExecState*, unsigned propertyName); + + virtual JSValue* defaultValue(ExecState*, PreferredPrimitiveType) const; + + virtual bool hasInstance(ExecState*, JSValue*, JSValue* prototypeProperty); + + virtual void getPropertyNames(ExecState*, PropertyNameArray&); + + 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 JSGlobalObject* toGlobalObject(ExecState*) const; + + virtual bool getPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned& attributes) const; + + // This get function only looks at the property map. + JSValue* getDirect(const Identifier& propertyName) const + { + size_t offset = m_structureID->get(propertyName); + return offset != WTF::notFound ? m_propertyStorage[offset] : noValue(); + } + + JSValue** getDirectLocation(const Identifier& propertyName) + { + size_t offset = m_structureID->get(propertyName); + return offset != WTF::notFound ? locationForOffset(offset) : 0; + } + + JSValue** getDirectLocation(const Identifier& propertyName, unsigned& attributes) + { + size_t offset = m_structureID->get(propertyName, attributes); + return offset != WTF::notFound ? locationForOffset(offset) : 0; + } + + size_t offsetForLocation(JSValue** location) + { + return location - m_propertyStorage; + } + + JSValue** locationForOffset(size_t offset) + { + return &m_propertyStorage[offset]; + } + + void transitionTo(StructureID*); + + void removeDirect(const Identifier& propertyName); + bool hasCustomProperties() { return !m_structureID->isEmpty(); } + bool hasGetterSetterProperties() { return m_structureID->hasGetterSetterProperties(); } + + void putDirect(const Identifier& propertyName, JSValue* value, unsigned attr = 0); + void putDirect(const Identifier& propertyName, JSValue* 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(ExecState* exec, InternalFunction* function, unsigned attr = 0); + + // Fast access to known property offsets. + JSValue* getDirectOffset(size_t offset) { return m_propertyStorage[offset]; } + void putDirectOffset(size_t offset, JSValue* value) { m_propertyStorage[offset] = 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 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 usingInlineStorage() const { return m_propertyStorage == m_inlineStorage; } + + static const size_t inlineStorageCapacity = 2; + static const size_t nonInlineBaseStorageCapacity = 16; + + static PassRefPtr<StructureID> createStructureID(JSValue* prototype) + { + return StructureID::create(prototype, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot)); + } + + protected: + bool getOwnPropertySlotForWrite(ExecState*, const Identifier&, PropertySlot&, bool& slotIsWriteable); + + private: + bool inlineGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); + + const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const; + StructureID* createInheritorID(); + + RefPtr<StructureID> m_inheritorID; + + PropertyStorage m_propertyStorage; + JSValue* 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<StructureID> structureID) + : JSCell(structureID.releaseRef()) // ~JSObject balances this ref() + , m_propertyStorage(m_inlineStorage) +{ + ASSERT(m_structureID); + ASSERT(m_structureID->propertyStorageCapacity() == inlineStorageCapacity); + ASSERT(m_structureID->isEmpty()); + ASSERT(prototype()->isNull() || Heap::heap(this) == Heap::heap(prototype())); +} + +inline JSObject::~JSObject() +{ + ASSERT(m_structureID); + if (m_propertyStorage != m_inlineStorage) + delete [] m_propertyStorage; + m_structureID->deref(); +} + +inline JSValue* JSObject::prototype() const +{ + return m_structureID->storedPrototype(); +} + +inline void JSObject::setPrototype(JSValue* prototype) +{ + ASSERT(prototype); + RefPtr<StructureID> newStructureID = StructureID::changePrototypeTransition(m_structureID, prototype); + setStructureID(newStructureID.release()); +} + +inline void JSObject::setStructureID(PassRefPtr<StructureID> structureID) +{ + m_structureID->deref(); + m_structureID = structureID.releaseRef(); // ~JSObject balances this ref() +} + +inline StructureID* JSObject::inheritorID() +{ + if (m_inheritorID) + return m_inheritorID.get(); + return createInheritorID(); +} + +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 !JSImmediate::isImmediate(asValue()) && asCell()->isObject(classInfo); +} + +ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +{ + if (JSValue** location = getDirectLocation(propertyName)) { + if (m_structureID->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; +} + +ALWAYS_INLINE bool JSObject::getOwnPropertySlotForWrite(ExecState* exec, const Identifier& propertyName, PropertySlot& slot, bool& slotIsWriteable) +{ + unsigned attributes; + if (JSValue** location = getDirectLocation(propertyName, attributes)) { + if (m_structureID->hasGetterSetterProperties() && location[0]->isGetterSetter()) { + slotIsWriteable = false; + fillGetterPropertySlot(slot, location); + } else { + slotIsWriteable = !(attributes & ReadOnly); + slot.setValueSlot(this, location, offsetForLocation(location)); + } + return true; + } + + // non-standard Netscape extension + if (propertyName == exec->propertyNames().underscoreProto) { + slot.setValue(prototype()); + slotIsWriteable = false; + 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 (structureID()->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::putDirect(const Identifier& propertyName, JSValue* value, unsigned attr) +{ + PutPropertySlot slot; + putDirect(propertyName, value, attr, false, slot); +} + +inline void JSObject::putDirect(const Identifier& propertyName, JSValue* value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot) +{ + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); + + if (m_structureID->isDictionary()) { + unsigned currentAttributes; + size_t offset = m_structureID->get(propertyName, currentAttributes); + if (offset != WTF::notFound) { + if (checkReadOnly && currentAttributes & ReadOnly) + return; + m_propertyStorage[offset] = value; + slot.setExistingProperty(this, offset); + return; + } + + size_t currentCapacity = m_structureID->propertyStorageCapacity(); + offset = m_structureID->addPropertyWithoutTransition(propertyName, attributes); + if (currentCapacity != m_structureID->propertyStorageCapacity()) + allocatePropertyStorage(currentCapacity, m_structureID->propertyStorageCapacity()); + + ASSERT(offset < m_structureID->propertyStorageCapacity()); + m_propertyStorage[offset] = value; + slot.setNewProperty(this, offset); + return; + } + + unsigned currentAttributes; + size_t offset = m_structureID->get(propertyName, currentAttributes); + if (offset != WTF::notFound) { + if (checkReadOnly && currentAttributes & ReadOnly) + return; + m_propertyStorage[offset] = value; + slot.setExistingProperty(this, offset); + return; + } + + size_t currentCapacity = m_structureID->propertyStorageCapacity(); + RefPtr<StructureID> structureID = StructureID::addPropertyTransition(m_structureID, propertyName, attributes, offset); + if (currentCapacity != structureID->propertyStorageCapacity()) + allocatePropertyStorage(currentCapacity, structureID->propertyStorageCapacity()); + + ASSERT(offset < structureID->propertyStorageCapacity()); + m_propertyStorage[offset] = value; + slot.setNewProperty(this, offset); + slot.setWasTransition(true); + setStructureID(structureID.release()); +} + +inline void JSObject::putDirectWithoutTransition(const Identifier& propertyName, JSValue* value, unsigned attributes) +{ + size_t currentCapacity = m_structureID->propertyStorageCapacity(); + size_t offset = m_structureID->addPropertyWithoutTransition(propertyName, attributes); + if (currentCapacity != m_structureID->propertyStorageCapacity()) + allocatePropertyStorage(currentCapacity, m_structureID->propertyStorageCapacity()); + m_propertyStorage[offset] = value; +} + +inline void JSObject::transitionTo(StructureID* newStructureID) +{ + if (m_structureID->propertyStorageCapacity() != newStructureID->propertyStorageCapacity()) + allocatePropertyStorage(m_structureID->propertyStorageCapacity(), newStructureID->propertyStorageCapacity()); + setStructureID(newStructureID); +} + +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(this); + return get(exec, propertyName, slot); +} + +inline JSValue* JSValue::get(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) const +{ + if (UNLIKELY(JSImmediate::isImmediate(asValue()))) { + JSObject* prototype = JSImmediate::prototype(asValue(), exec); + if (!prototype->getPropertySlot(exec, propertyName, slot)) + return jsUndefined(); + return slot.getValue(exec, propertyName); + } + JSCell* cell = asCell(); + while (true) { + if (cell->fastGetOwnPropertySlot(exec, propertyName, slot)) + return slot.getValue(exec, propertyName); + 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(this); + return get(exec, propertyName, slot); +} + +inline JSValue* JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const +{ + if (UNLIKELY(JSImmediate::isImmediate(asValue()))) { + 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(JSImmediate::isImmediate(asValue()))) { + 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(JSImmediate::isImmediate(asValue()))) { + 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); + + JSValue** oldPropertyStorage = m_propertyStorage; + m_propertyStorage = new JSValue*[newSize]; + + for (unsigned i = 0; i < oldSize; ++i) + m_propertyStorage[i] = oldPropertyStorage[i]; + + if (oldPropertyStorage != m_inlineStorage) + delete [] oldPropertyStorage; +} + +} // namespace JSC + +#endif // JSObject_h diff --git a/JavaScriptCore/runtime/JSPropertyNameIterator.cpp b/JavaScriptCore/runtime/JSPropertyNameIterator.cpp new file mode 100644 index 0000000..55f4ced --- /dev/null +++ b/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 noValue(); +} + +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/JavaScriptCore/runtime/JSPropertyNameIterator.h b/JavaScriptCore/runtime/JSPropertyNameIterator.h new file mode 100644 index 0000000..1853999 --- /dev/null +++ b/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 noValue(); + + if (m_data->cachedStructureID() == m_object->structureID() && structureIDChainsAreEqual(m_data->cachedPrototypeChain(), m_object->structureID()->cachedPrototypeChain())) + 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 noValue(); +} + +} // namespace JSC + +#endif // JSPropertyNameIterator_h diff --git a/JavaScriptCore/runtime/JSStaticScopeObject.cpp b/JavaScriptCore/runtime/JSStaticScopeObject.cpp new file mode 100644 index 0000000..0698250 --- /dev/null +++ b/JavaScriptCore/runtime/JSStaticScopeObject.cpp @@ -0,0 +1,84 @@ +/* + * 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); +} + +inline bool JSStaticScopeObject::getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot& slot, bool& slotIsWriteable) +{ + return symbolTableGet(propertyName, slot, slotIsWriteable); +} + +} diff --git a/JavaScriptCore/runtime/JSStaticScopeObject.h b/JavaScriptCore/runtime/JSStaticScopeObject.h new file mode 100644 index 0000000..b152862 --- /dev/null +++ b/JavaScriptCore/runtime/JSStaticScopeObject.h @@ -0,0 +1,69 @@ +/* + * 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().staticScopeStructureID, 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 bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&, bool& slotIsWriteable); + virtual void put(ExecState*, const Identifier&, JSValue*, PutPropertySlot&); + void putWithAttributes(ExecState*, const Identifier&, JSValue*, unsigned attributes); + + static PassRefPtr<StructureID> createStructureID(JSValue* proto) { return StructureID::create(proto, TypeInfo(ObjectType, NeedsThisConversion)); } + + private: + JSStaticScopeObjectData* d() { return static_cast<JSStaticScopeObjectData*>(JSVariableObject::d); } + }; + +} + +#endif // JSStaticScopeObject_h diff --git a/JavaScriptCore/runtime/JSString.cpp b/JavaScriptCore/runtime/JSString.cpp new file mode 100644 index 0000000..49503d5 --- /dev/null +++ b/JavaScriptCore/runtime/JSString.cpp @@ -0,0 +1,152 @@ +/* + * 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; + 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); +} + +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/JavaScriptCore/runtime/JSString.h b/JavaScriptCore/runtime/JSString.h new file mode 100644 index 0000000..b6275e7 --- /dev/null +++ b/JavaScriptCore/runtime/JSString.h @@ -0,0 +1,214 @@ +/* + * 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 "ExecState.h" +#include "JSNumberCell.h" +#include "PropertySlot.h" +#include "identifier.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 CTI; + friend class Machine; + + public: + JSString(JSGlobalData* globalData, const UString& value) + : JSCell(globalData->stringStructureID.get()) + , m_value(value) + { + Heap::heap(this)->reportExtraMemoryCost(value.cost()); + } + + enum HasOtherOwnerType { HasOtherOwner }; + JSString(JSGlobalData* globalData, const UString& value, HasOtherOwnerType) + : JSCell(globalData->stringStructureID.get()) + , m_value(value) + { + } + JSString(JSGlobalData* globalData, PassRefPtr<UString::Rep> value, HasOtherOwnerType) + : JSCell(globalData->stringStructureID.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 canGetIndex(unsigned i) { return i < static_cast<unsigned>(m_value.size()); } + JSString* getIndex(JSGlobalData*, unsigned); + + static PassRefPtr<StructureID> createStructureID(JSValue* proto) { return StructureID::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; + } + + // --- 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/JavaScriptCore/runtime/JSType.h b/JavaScriptCore/runtime/JSType.h new file mode 100644 index 0000000..f0fa28f --- /dev/null +++ b/JavaScriptCore/runtime/JSType.h @@ -0,0 +1,43 @@ +/* + * This file is part of the KDE libraries + * 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. + * + */ + +#ifndef KJS_JSTYPE_H +#define KJS_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/JavaScriptCore/runtime/JSValue.cpp b/JavaScriptCore/runtime/JSValue.cpp new file mode 100644 index 0000000..73580b0 --- /dev/null +++ b/JavaScriptCore/runtime/JSValue.cpp @@ -0,0 +1,104 @@ +/* + * 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 +{ + int32_t i; + if (getTruncatedInt32(i)) + return i; + double d = toNumber(exec); + return isnan(d) ? 0.0 : trunc(d); +} + +double JSValue::toIntegerPreserveNaN(ExecState* exec) const +{ + int32_t i; + if (getTruncatedInt32(i)) + return i; + 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); +} + +int32_t JSValue::toInt32SlowCase(ExecState* exec, bool& ok) const +{ + return JSC::toInt32SlowCase(toNumber(exec), ok); +} + +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); +} + +uint32_t JSValue::toUInt32SlowCase(ExecState* exec, bool& ok) const +{ + return JSC::toUInt32SlowCase(toNumber(exec), ok); +} + +float JSValue::toFloat(ExecState* exec) const +{ + return static_cast<float>(toNumber(exec)); +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/JSValue.h b/JavaScriptCore/runtime/JSValue.h new file mode 100644 index 0000000..059a5e6 --- /dev/null +++ b/JavaScriptCore/runtime/JSValue.h @@ -0,0 +1,243 @@ +/* + * 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 JSValue_h +#define JSValue_h + +#include "CallData.h" +#include "ConstructData.h" +#include "JSImmediate.h" +#include "ustring.h" +#include <stddef.h> // for size_t + +// The magic number 0x4000 is not important here, it is being subtracted back out (avoiding using zero since this +// can have unexpected effects in this type of macro, particularly where multiple-inheritance is involved). +#define OBJECT_OFFSET(class, member) (reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<class*>(0x4000)->member)) - 0x4000) + +namespace JSC { + + class Identifier; + class JSString; + class PropertySlot; + class PutPropertySlot; + + struct ClassInfo; + struct Instruction; + + enum PreferredPrimitiveType { NoPreference, PreferNumber, PreferString }; + + class JSValue : Noncopyable { + protected: + JSValue() { } + virtual ~JSValue() { } + + public: + // 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 + double getNumber() const; // NaN if not a number + 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. + double toInteger(ExecState*) const; + double toIntegerPreserveNaN(ExecState*) const; + int32_t toInt32(ExecState*) const; + int32_t toInt32(ExecState*, bool& ok) const; + uint32_t toUInt32(ExecState*) const; + uint32_t toUInt32(ExecState*, bool& ok) const; + + // Floating point conversions. + float toFloat(ExecState*) const; + + // 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 deleteProperty(ExecState*, const Identifier& propertyName); + bool deleteProperty(ExecState*, unsigned propertyName); + + bool needsThisConversion() const; + JSObject* toThisObject(ExecState*) const; + UString toThisString(ExecState*) const; + JSString* toThisJSString(ExecState*); + + JSValue* getJSNumber(); // 0 if this is not a JSNumber or number object + + JSValue* asValue() const; + + JSCell* asCell() const; + + private: + bool getPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); + bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); + int32_t toInt32SlowCase(ExecState*, bool& ok) const; + uint32_t toUInt32SlowCase(ExecState*, bool& ok) const; + }; + + // 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::asValue() const + { + return const_cast<JSValue*>(this); + } + + inline bool JSValue::isUndefined() const + { + return asValue() == jsUndefined(); + } + + inline bool JSValue::isNull() const + { + return asValue() == jsNull(); + } + + 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 ok; + return toInt32SlowCase(exec, ok); + } + + inline uint32_t JSValue::toUInt32(ExecState* exec) const + { + uint32_t i; + if (getTruncatedUInt32(i)) + return i; + bool ok; + return toUInt32SlowCase(exec, ok); + } + + 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(exec, ok); + } + + inline uint32_t JSValue::toUInt32(ExecState* exec, bool& ok) const + { + uint32_t i; + if (getTruncatedUInt32(i)) { + ok = true; + return i; + } + return toUInt32SlowCase(exec, ok); + } + +} // namespace JSC + +#endif // JSValue_h diff --git a/JavaScriptCore/runtime/JSVariableObject.cpp b/JavaScriptCore/runtime/JSVariableObject.cpp new file mode 100644 index 0000000..a36cefa --- /dev/null +++ b/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) +{ + if (symbolTable().contains(propertyName.ustring().rep())) + return false; + + return JSObject::deleteProperty(exec, propertyName); +} + +void JSVariableObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) +{ + SymbolTable::const_iterator end = symbolTable().end(); + for (SymbolTable::const_iterator it = symbolTable().begin(); it != end; ++it) { + if (!(it->second.getAttributes() & DontEnum)) + propertyNames.add(Identifier(exec, it->first.get())); + } + + JSObject::getPropertyNames(exec, propertyNames); +} + +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/JavaScriptCore/runtime/JSVariableObject.h b/JavaScriptCore/runtime/JSVariableObject.h new file mode 100644 index 0000000..1194517 --- /dev/null +++ b/JavaScriptCore/runtime/JSVariableObject.h @@ -0,0 +1,178 @@ +/* + * 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 { + public: + SymbolTable& symbolTable() const { return *d->symbolTable; } + + virtual void putWithAttributes(ExecState*, const Identifier&, JSValue*, unsigned attributes) = 0; + + virtual bool deleteProperty(ExecState*, const Identifier&); + virtual void getPropertyNames(ExecState*, PropertyNameArray&); + + 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. + + static inline ptrdiff_t offsetOf_registers() + { + return OBJECT_OFFSET(JSVariableObjectData, registers); + } + + private: + JSVariableObjectData(const JSVariableObjectData&); + JSVariableObjectData& operator=(const JSVariableObjectData&); + }; + + JSVariableObject(PassRefPtr<StructureID> structureID, JSVariableObjectData* data) + : JSObject(structureID) + , 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; + + public: + static inline ptrdiff_t offsetOf_d() + { + return OBJECT_OFFSET(JSVariableObject, d); + } + + static inline ptrdiff_t offsetOf_Data_registers() + { + return JSVariableObjectData::offsetOf_registers(); + } + }; + + 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/JavaScriptCore/runtime/JSWrapperObject.cpp b/JavaScriptCore/runtime/JSWrapperObject.cpp new file mode 100644 index 0000000..c791d93 --- /dev/null +++ b/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/JavaScriptCore/runtime/JSWrapperObject.h b/JavaScriptCore/runtime/JSWrapperObject.h new file mode 100644 index 0000000..5e4ba17 --- /dev/null +++ b/JavaScriptCore/runtime/JSWrapperObject.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2006 Maks Orlovich + * 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 KJS_JSWrapperObject_h +#define KJS_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<StructureID>); + + public: + JSValue* internalValue() const { return m_internalValue; } + void setInternalValue(JSValue*); + + virtual void mark(); + + private: + JSValue* m_internalValue; + }; + + inline JSWrapperObject::JSWrapperObject(PassRefPtr<StructureID> structure) + : JSObject(structure) + , m_internalValue(noValue()) + { + } + + inline void JSWrapperObject::setInternalValue(JSValue* value) + { + ASSERT(value); + ASSERT(!value->isObject()); + m_internalValue = value; + } + +} // namespace JSC + +#endif // KJS_JSWrapperObject_h diff --git a/JavaScriptCore/runtime/MathObject.cpp b/JavaScriptCore/runtime/MathObject.cpp new file mode 100644 index 0000000..8b972d3 --- /dev/null +++ b/JavaScriptCore/runtime/MathObject.cpp @@ -0,0 +1,247 @@ +/* + * 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> + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(MathObject); + +static JSValue* mathProtoFuncAbs(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* mathProtoFuncACos(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* mathProtoFuncASin(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* mathProtoFuncATan(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* mathProtoFuncATan2(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* mathProtoFuncCeil(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* mathProtoFuncCos(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* mathProtoFuncExp(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* mathProtoFuncFloor(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* mathProtoFuncLog(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* mathProtoFuncMax(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* mathProtoFuncMin(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* mathProtoFuncPow(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* mathProtoFuncRandom(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* mathProtoFuncRound(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* mathProtoFuncSin(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* mathProtoFuncSqrt(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* 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<StructureID> 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); +} + +// 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* mathProtoFuncAbs(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + return jsNumber(exec, fabs(args.at(exec, 0)->toNumber(exec))); +} + +JSValue* mathProtoFuncACos(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + return jsNumber(exec, acos(args.at(exec, 0)->toNumber(exec))); +} + +JSValue* mathProtoFuncASin(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + return jsNumber(exec, asin(args.at(exec, 0)->toNumber(exec))); +} + +JSValue* mathProtoFuncATan(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + return jsNumber(exec, atan(args.at(exec, 0)->toNumber(exec))); +} + +JSValue* mathProtoFuncATan2(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + return jsNumber(exec, atan2(args.at(exec, 0)->toNumber(exec), args.at(exec, 1)->toNumber(exec))); +} + +JSValue* mathProtoFuncCeil(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + return jsNumber(exec, ceil(args.at(exec, 0)->toNumber(exec))); +} + +JSValue* mathProtoFuncCos(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + return jsNumber(exec, cos(args.at(exec, 0)->toNumber(exec))); +} + +JSValue* mathProtoFuncExp(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + return jsNumber(exec, exp(args.at(exec, 0)->toNumber(exec))); +} + +JSValue* mathProtoFuncFloor(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + return jsNumber(exec, floor(args.at(exec, 0)->toNumber(exec))); +} + +JSValue* mathProtoFuncLog(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + return jsNumber(exec, log(args.at(exec, 0)->toNumber(exec))); +} + +JSValue* 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(exec, 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* 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(exec, 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* mathProtoFuncPow(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + // ECMA 15.8.2.1.13 + + double arg = args.at(exec, 0)->toNumber(exec); + double arg2 = args.at(exec, 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* mathProtoFuncRandom(ExecState* exec, JSObject*, JSValue*, const ArgList&) +{ +#if !ENABLE(JSC_MULTIPLE_THREADS) + static bool didInitRandom; + if (!didInitRandom) { + wtf_random_init(); + didInitRandom = true; + } +#endif + + return jsNumber(exec, wtf_random()); +} + +JSValue* mathProtoFuncRound(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + double arg = args.at(exec, 0)->toNumber(exec); + if (signbit(arg) && arg >= -0.5) + return jsNumber(exec, -0.0); + return jsNumber(exec, floor(arg + 0.5)); +} + +JSValue* mathProtoFuncSin(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + return jsNumber(exec, sin(args.at(exec, 0)->toNumber(exec))); +} + +JSValue* mathProtoFuncSqrt(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + return jsNumber(exec, sqrt(args.at(exec, 0)->toNumber(exec))); +} + +JSValue* mathProtoFuncTan(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + return jsNumber(exec, tan(args.at(exec, 0)->toNumber(exec))); +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/MathObject.h b/JavaScriptCore/runtime/MathObject.h new file mode 100644 index 0000000..704b10e --- /dev/null +++ b/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<StructureID>); + + virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + + static PassRefPtr<StructureID> createStructureID(JSValue* prototype) + { + return StructureID::create(prototype, TypeInfo(ObjectType)); + } + }; + +} // namespace JSC + +#endif // MathObject_h diff --git a/JavaScriptCore/runtime/NativeErrorConstructor.cpp b/JavaScriptCore/runtime/NativeErrorConstructor.cpp new file mode 100644 index 0000000..05159f0 --- /dev/null +++ b/JavaScriptCore/runtime/NativeErrorConstructor.cpp @@ -0,0 +1,72 @@ +/* + * 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 "NativeErrorPrototype.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(NativeErrorConstructor); + +const ClassInfo NativeErrorConstructor::info = { "Function", &InternalFunction::info, 0, 0 }; + +NativeErrorConstructor::NativeErrorConstructor(ExecState* exec, PassRefPtr<StructureID> structure, NativeErrorPrototype* nativeErrorPrototype) + : InternalFunction(&exec->globalData(), structure, Identifier(exec, nativeErrorPrototype->getDirect(exec->propertyNames().name)->getString())) + , m_errorStructure(ErrorInstance::createStructureID(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(exec, 0)->isUndefined()) + object->putDirect(exec->propertyNames().message, jsString(exec, args.at(exec, 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* 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/JavaScriptCore/runtime/NativeErrorConstructor.h b/JavaScriptCore/runtime/NativeErrorConstructor.h new file mode 100644 index 0000000..85acbb9 --- /dev/null +++ b/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<StructureID>, 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<StructureID> m_errorStructure; + }; + +} // namespace JSC + +#endif // NativeErrorConstructor_h diff --git a/JavaScriptCore/runtime/NativeErrorPrototype.cpp b/JavaScriptCore/runtime/NativeErrorPrototype.cpp new file mode 100644 index 0000000..9403aa9 --- /dev/null +++ b/JavaScriptCore/runtime/NativeErrorPrototype.cpp @@ -0,0 +1,39 @@ +/* + * 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<StructureID> structure, const UString& name, const UString& message) + : JSObject(structure) +{ + putDirect(exec->propertyNames().name, jsString(exec, name), 0); + putDirect(exec->propertyNames().message, jsString(exec, message), 0); +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/NativeErrorPrototype.h b/JavaScriptCore/runtime/NativeErrorPrototype.h new file mode 100644 index 0000000..719cb90 --- /dev/null +++ b/JavaScriptCore/runtime/NativeErrorPrototype.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 NativeErrorPrototype_h +#define NativeErrorPrototype_h + +#include "JSObject.h" + +namespace JSC { + + class NativeErrorPrototype : public JSObject { + public: + NativeErrorPrototype(ExecState*, PassRefPtr<StructureID>, const UString& name, const UString& message); + }; + +} // namespace JSC + +#endif // NativeErrorPrototype_h diff --git a/JavaScriptCore/runtime/NumberConstructor.cpp b/JavaScriptCore/runtime/NumberConstructor.cpp new file mode 100644 index 0000000..5b6ccf8 --- /dev/null +++ b/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<StructureID> 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); +} + +JSValue* numberConstructorNaNValue(ExecState* exec, const Identifier&, const PropertySlot&) +{ + return jsNaN(exec); +} + +JSValue* numberConstructorNegInfinity(ExecState* exec, const Identifier&, const PropertySlot&) +{ + return jsNumberCell(exec, -Inf); +} + +JSValue* numberConstructorPosInfinity(ExecState* exec, const Identifier&, const PropertySlot&) +{ + return jsNumberCell(exec, Inf); +} + +JSValue* numberConstructorMaxValue(ExecState* exec, const Identifier&, const PropertySlot&) +{ + return jsNumberCell(exec, 1.7976931348623157E+308); +} + +JSValue* numberConstructorMinValue(ExecState* exec, const Identifier&, const PropertySlot&) +{ + return jsNumberCell(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(exec, 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* callNumberConstructor(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + return jsNumber(exec, args.isEmpty() ? 0 : args.at(exec, 0)->toNumber(exec)); +} + +CallType NumberConstructor::getCallData(CallData& callData) +{ + callData.native.function = callNumberConstructor; + return CallTypeHost; +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/NumberConstructor.h b/JavaScriptCore/runtime/NumberConstructor.h new file mode 100644 index 0000000..8da23c4 --- /dev/null +++ b/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<StructureID>, NumberPrototype*); + + virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + JSValue* getValueProperty(ExecState*, int token) const; + + static const ClassInfo info; + + static PassRefPtr<StructureID> createStructureID(JSValue* proto) + { + return StructureID::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/JavaScriptCore/runtime/NumberObject.cpp b/JavaScriptCore/runtime/NumberObject.cpp new file mode 100644 index 0000000..252671b --- /dev/null +++ b/JavaScriptCore/runtime/NumberObject.cpp @@ -0,0 +1,58 @@ +/* + * 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<StructureID> structure) + : JSWrapperObject(structure) +{ +} + +JSValue* NumberObject::getJSNumber() +{ + return internalValue(); +} + +NumberObject* constructNumber(ExecState* exec, JSNumberCell* number) +{ + NumberObject* object = new (exec) NumberObject(exec->lexicalGlobalObject()->numberObjectStructure()); + object->setInternalValue(number); + return object; +} + +NumberObject* constructNumberFromImmediateNumber(ExecState* exec, JSValue* value) +{ + NumberObject* object = new (exec) NumberObject(exec->lexicalGlobalObject()->numberObjectStructure()); + object->setInternalValue(value); + return object; +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/NumberObject.h b/JavaScriptCore/runtime/NumberObject.h new file mode 100644 index 0000000..eddecd1 --- /dev/null +++ b/JavaScriptCore/runtime/NumberObject.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 NumberObject_h +#define NumberObject_h + +#include "JSWrapperObject.h" + +namespace JSC { + + class JSNumberCell; + + class NumberObject : public JSWrapperObject { + public: + explicit NumberObject(PassRefPtr<StructureID>); + + static const ClassInfo info; + + private: + virtual const ClassInfo* classInfo() const { return &info; } + + virtual JSValue* getJSNumber(); + }; + + NumberObject* constructNumber(ExecState*, JSNumberCell*); + NumberObject* constructNumberFromImmediateNumber(ExecState*, JSValue*); + +} // namespace JSC + +#endif // NumberObject_h diff --git a/JavaScriptCore/runtime/NumberPrototype.cpp b/JavaScriptCore/runtime/NumberPrototype.cpp new file mode 100644 index 0000000..d203e3f --- /dev/null +++ b/JavaScriptCore/runtime/NumberPrototype.cpp @@ -0,0 +1,441 @@ +/* + * 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 "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* numberProtoFuncToString(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* numberProtoFuncToLocaleString(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* numberProtoFuncValueOf(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* numberProtoFuncToFixed(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* numberProtoFuncToExponential(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* numberProtoFuncToPrecision(ExecState*, JSObject*, JSValue*, const ArgList&); + +// ECMA 15.7.4 + +NumberPrototype::NumberPrototype(ExecState* exec, PassRefPtr<StructureID> structure, StructureID* prototypeFunctionStructure) + : NumberObject(structure) +{ + setInternalValue(jsNumber(exec, 0)); + + // The constructor will be added later, after NumberConstructor has been constructed + + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 1, exec->propertyNames().toString, numberProtoFuncToString), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 0, exec->propertyNames().toLocaleString, numberProtoFuncToLocaleString), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 0, exec->propertyNames().valueOf, numberProtoFuncValueOf), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 1, exec->propertyNames().toFixed, numberProtoFuncToFixed), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 1, exec->propertyNames().toExponential, numberProtoFuncToExponential), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(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 = dtoa(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) { + strcpy(buf.data(), result); + memset(buf.data() + length, '0', decimalPoint - length); + } else + strncpy(buf.data(), result, decimalPoint); + + buf[decimalPoint] = '\0'; + str.append(buf.data()); + } + + freedtoa(result); + + 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* numberProtoFuncToString(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + JSValue* v = thisValue->getJSNumber(); + if (!v) + return throwError(exec, TypeError); + + double radixAsDouble = args.at(exec, 0)->toInteger(exec); // nan -> 0 + if (radixAsDouble == 10 || args.at(exec, 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* 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* numberProtoFuncValueOf(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&) +{ + JSValue* v = thisValue->getJSNumber(); + if (!v) + return throwError(exec, TypeError); + + return v; +} + +JSValue* numberProtoFuncToFixed(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + JSValue* v = thisValue->getJSNumber(); + if (!v) + return throwError(exec, TypeError); + + JSValue* fractionDigits = args.at(exec, 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 { + strcpy(buf + i, result + 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* 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(exec, 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 = dtoa(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++] = '-'; + + if (decimalPoint == 999) // ? 9999 is the magical "result is Inf or NaN" value. what's 999?? + strcpy(buf + i, result); + 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); + + freedtoa(result); + + return jsString(exec, buf); +} + +JSValue* numberProtoFuncToPrecision(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + JSValue* v = thisValue->getJSNumber(); + if (!v) + return throwError(exec, TypeError); + + double doublePrecision = args.at(exec, 0)->toIntegerPreserveNaN(exec); + double x = v->uncheckedGetNumber(); + if (args.at(exec, 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/JavaScriptCore/runtime/NumberPrototype.h b/JavaScriptCore/runtime/NumberPrototype.h new file mode 100644 index 0000000..d70f260 --- /dev/null +++ b/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<StructureID>, StructureID* prototypeFunctionStructure); + }; + +} // namespace JSC + +#endif // NumberPrototype_h diff --git a/JavaScriptCore/runtime/ObjectConstructor.cpp b/JavaScriptCore/runtime/ObjectConstructor.cpp new file mode 100644 index 0000000..329816f --- /dev/null +++ b/JavaScriptCore/runtime/ObjectConstructor.cpp @@ -0,0 +1,72 @@ +/* + * 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 "JSGlobalObject.h" +#include "ObjectPrototype.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(ObjectConstructor); + +ObjectConstructor::ObjectConstructor(ExecState* exec, PassRefPtr<StructureID> 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(exec, 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* 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/JavaScriptCore/runtime/ObjectConstructor.h b/JavaScriptCore/runtime/ObjectConstructor.h new file mode 100644 index 0000000..c100424 --- /dev/null +++ b/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<StructureID>, ObjectPrototype*); + + private: + virtual ConstructType getConstructData(ConstructData&); + virtual CallType getCallData(CallData&); + }; + +} // namespace JSC + +#endif // ObjectConstructor_h diff --git a/JavaScriptCore/runtime/ObjectPrototype.cpp b/JavaScriptCore/runtime/ObjectPrototype.cpp new file mode 100644 index 0000000..42a8063 --- /dev/null +++ b/JavaScriptCore/runtime/ObjectPrototype.cpp @@ -0,0 +1,134 @@ +/* + * 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 "JSString.h" +#include "PrototypeFunction.h" + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(ObjectPrototype); + +static JSValue* objectProtoFuncValueOf(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* objectProtoFuncHasOwnProperty(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* objectProtoFuncIsPrototypeOf(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* objectProtoFuncDefineGetter(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* objectProtoFuncDefineSetter(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* objectProtoFuncLookupGetter(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* objectProtoFuncLookupSetter(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* objectProtoFuncPropertyIsEnumerable(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* objectProtoFuncToLocaleString(ExecState*, JSObject*, JSValue*, const ArgList&); + +ObjectPrototype::ObjectPrototype(ExecState* exec, PassRefPtr<StructureID> stucture, StructureID* prototypeFunctionStructure) + : JSObject(stucture) +{ + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 0, exec->propertyNames().toString, objectProtoFuncToString), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 0, exec->propertyNames().toLocaleString, objectProtoFuncToLocaleString), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 0, exec->propertyNames().valueOf, objectProtoFuncValueOf), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 1, exec->propertyNames().hasOwnProperty, objectProtoFuncHasOwnProperty), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 1, exec->propertyNames().propertyIsEnumerable, objectProtoFuncPropertyIsEnumerable), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 1, exec->propertyNames().isPrototypeOf, objectProtoFuncIsPrototypeOf), DontEnum); + + // Mozilla extensions + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 2, exec->propertyNames().__defineGetter__, objectProtoFuncDefineGetter), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 2, exec->propertyNames().__defineSetter__, objectProtoFuncDefineSetter), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 1, exec->propertyNames().__lookupGetter__, objectProtoFuncLookupGetter), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(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* objectProtoFuncValueOf(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&) +{ + return thisValue->toThisObject(exec); +} + +JSValue* objectProtoFuncHasOwnProperty(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + return jsBoolean(thisValue->toThisObject(exec)->hasOwnProperty(exec, Identifier(exec, args.at(exec, 0)->toString(exec)))); +} + +JSValue* objectProtoFuncIsPrototypeOf(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + JSObject* thisObj = thisValue->toThisObject(exec); + + if (!args.at(exec, 0)->isObject()) + return jsBoolean(false); + + JSValue* v = asObject(args.at(exec, 0))->prototype(); + + while (true) { + if (!v->isObject()) + return jsBoolean(false); + if (thisObj == v) + return jsBoolean(true); + v = asObject(v)->prototype(); + } +} + +JSValue* objectProtoFuncDefineGetter(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + CallData callData; + if (args.at(exec, 1)->getCallData(callData) == CallTypeNone) + return throwError(exec, SyntaxError, "invalid getter usage"); + thisValue->toThisObject(exec)->defineGetter(exec, Identifier(exec, args.at(exec, 0)->toString(exec)), asObject(args.at(exec, 1))); + return jsUndefined(); +} + +JSValue* objectProtoFuncDefineSetter(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + CallData callData; + if (args.at(exec, 1)->getCallData(callData) == CallTypeNone) + return throwError(exec, SyntaxError, "invalid setter usage"); + thisValue->toThisObject(exec)->defineSetter(exec, Identifier(exec, args.at(exec, 0)->toString(exec)), asObject(args.at(exec, 1))); + return jsUndefined(); +} + +JSValue* objectProtoFuncLookupGetter(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + return thisValue->toThisObject(exec)->lookupGetter(exec, Identifier(exec, args.at(exec, 0)->toString(exec))); +} + +JSValue* objectProtoFuncLookupSetter(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + return thisValue->toThisObject(exec)->lookupSetter(exec, Identifier(exec, args.at(exec, 0)->toString(exec))); +} + +JSValue* objectProtoFuncPropertyIsEnumerable(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + return jsBoolean(thisValue->toThisObject(exec)->propertyIsEnumerable(exec, Identifier(exec, args.at(exec, 0)->toString(exec)))); +} + +JSValue* objectProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&) +{ + return thisValue->toThisJSString(exec); +} + +JSValue* objectProtoFuncToString(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&) +{ + return jsNontrivialString(exec, "[object " + thisValue->toThisObject(exec)->className() + "]"); +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/ObjectPrototype.h b/JavaScriptCore/runtime/ObjectPrototype.h new file mode 100644 index 0000000..aefdf95 --- /dev/null +++ b/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<StructureID>, StructureID* prototypeFunctionStructure); + }; + + JSValue* objectProtoFuncToString(ExecState*, JSObject*, JSValue*, const ArgList&); + +} // namespace JSC + +#endif // ObjectPrototype_h diff --git a/JavaScriptCore/runtime/PropertyMapHashTable.h b/JavaScriptCore/runtime/PropertyMapHashTable.h new file mode 100644 index 0000000..98b0727 --- /dev/null +++ b/JavaScriptCore/runtime/PropertyMapHashTable.h @@ -0,0 +1,77 @@ +/* + * 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" + +namespace JSC { + + struct PropertyMapEntry { + UString::Rep* key; + unsigned offset; + unsigned attributes; + unsigned index; + + PropertyMapEntry(UString::Rep* k, int a) + : key(k) + , offset(0) + , attributes(a) + , index(0) + { + } + }; + + // 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; + 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/JavaScriptCore/runtime/PropertyNameArray.cpp b/JavaScriptCore/runtime/PropertyNameArray.cpp new file mode 100644 index 0000000..47e9d84 --- /dev/null +++ b/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/JavaScriptCore/runtime/PropertyNameArray.h b/JavaScriptCore/runtime/PropertyNameArray.h new file mode 100644 index 0000000..d19c2e5 --- /dev/null +++ b/JavaScriptCore/runtime/PropertyNameArray.h @@ -0,0 +1,112 @@ +/* + * 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 "ExecState.h" +#include "StructureID.h" +#include "identifier.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 setCachedStructureID(StructureID* structureID) { m_cachedStructureID = structureID; } + StructureID* cachedStructureID() const { return m_cachedStructureID; } + + void setCachedPrototypeChain(PassRefPtr<StructureIDChain> cachedPrototypeChain) { m_cachedPrototypeChain = cachedPrototypeChain; } + StructureIDChain* cachedPrototypeChain() { return m_cachedPrototypeChain.get(); } + + private: + PropertyNameArrayData() + : m_cachedStructureID(0) + { + } + + PropertyNameVector m_propertyNameVector; + StructureID* m_cachedStructureID; + RefPtr<StructureIDChain> m_cachedPrototypeChain; + }; + + class PropertyNameArray { + public: + typedef PropertyNameArrayData::const_iterator const_iterator; + + PropertyNameArray(JSGlobalData* globalData) + : m_data(PropertyNameArrayData::create()) + , m_globalData(globalData) + , m_cacheable(true) + { + } + + PropertyNameArray(ExecState* exec) + : m_data(PropertyNameArrayData::create()) + , m_globalData(&exec->globalData()) + , m_cacheable(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 setCacheable(bool cacheable) { m_cacheable = cacheable; } + bool cacheable() const { return m_cacheable; } + + private: + typedef HashSet<UString::Rep*, PtrHash<UString::Rep*> > IdentifierSet; + + RefPtr<PropertyNameArrayData> m_data; + IdentifierSet m_set; + JSGlobalData* m_globalData; + bool m_cacheable; + }; + +} // namespace JSC + +#endif // PropertyNameArray_h diff --git a/JavaScriptCore/runtime/PropertySlot.cpp b/JavaScriptCore/runtime/PropertySlot.cpp new file mode 100644 index 0000000..37df83a --- /dev/null +++ b/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/JavaScriptCore/runtime/PropertySlot.h b/JavaScriptCore/runtime/PropertySlot.h new file mode 100644 index 0000000..29c19d4 --- /dev/null +++ b/JavaScriptCore/runtime/PropertySlot.h @@ -0,0 +1,212 @@ +/* + * 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 "Register.h" +#include "JSValue.h" +#include "identifier.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(const_cast<JSValue*>(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(exec); + 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(exec); + 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 putValue(JSValue* value) + { + if (m_getValue == JSC_VALUE_SLOT_MARKER) { + *m_data.valueSlot = value; + return; + } + ASSERT(m_getValue == JSC_REGISTER_SLOT_MARKER); + *m_data.registerSlot = value; + } + + 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 = noValue(); +#endif + } + + void clearValue() + { +#ifndef NDEBUG + m_value = noValue(); +#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/JavaScriptCore/runtime/PrototypeFunction.cpp b/JavaScriptCore/runtime/PrototypeFunction.cpp new file mode 100644 index 0000000..8afe6a4 --- /dev/null +++ b/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<StructureID> 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/JavaScriptCore/runtime/PrototypeFunction.h b/JavaScriptCore/runtime/PrototypeFunction.h new file mode 100644 index 0000000..1592995 --- /dev/null +++ b/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<StructureID>, int length, const Identifier&, NativeFunction); + + private: + virtual CallType getCallData(CallData&); + + const NativeFunction m_function; + }; + +} // namespace JSC + +#endif // PrototypeFunction_h diff --git a/JavaScriptCore/runtime/PutPropertySlot.h b/JavaScriptCore/runtime/PutPropertySlot.h new file mode 100644 index 0000000..1e2dfe9 --- /dev/null +++ b/JavaScriptCore/runtime/PutPropertySlot.h @@ -0,0 +1,81 @@ +// -*- 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 PutPropertySlot { + public: + enum Type { Invalid, ExistingProperty, NewProperty }; + + PutPropertySlot() + : m_type(Invalid) + , m_base(0) + , m_wasTransition(false) + { + } + + 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 != Invalid; } + size_t cachedOffset() const { + ASSERT(isCacheable()); + return m_offset; + } + + bool wasTransition() const { return m_wasTransition; } + void setWasTransition(bool wasTransition) { m_wasTransition = wasTransition; } + private: + Type m_type; + JSObject* m_base; + bool m_wasTransition; + size_t m_offset; + }; + +} // namespace JSC + +#endif // PutPropertySlot_h diff --git a/JavaScriptCore/runtime/RegExpConstructor.cpp b/JavaScriptCore/runtime/RegExpConstructor.cpp new file mode 100644 index 0000000..4c4db39 --- /dev/null +++ b/JavaScriptCore/runtime/RegExpConstructor.cpp @@ -0,0 +1,385 @@ +/* + * 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 "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) + { + } + + UString input; + UString lastInput; + OwnArrayPtr<int> lastOvector; + unsigned lastNumSubPatterns : 31; + bool multiline : 1; +}; + +RegExpConstructor::RegExpConstructor(ExecState* exec, PassRefPtr<StructureID> 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) +{ + OwnArrayPtr<int> tmpOvector; + position = r->match(s, startOffset, &tmpOvector); + + if (ovector) + *ovector = tmpOvector.get(); + + if (position != -1) { + ASSERT(tmpOvector); + + length = tmpOvector[1] - tmpOvector[0]; + + d->input = s; + d->lastInput = s; + d->lastOvector.set(tmpOvector.release()); + 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.set(new int[offsetVectorSize]); + memcpy(d->lastOvector.get(), data->lastOvector.get(), 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 && 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); + 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) + return jsSubstring(exec, d->lastInput, 0, d->lastOvector[0]); + return jsEmptyString(exec); +} + +JSValue* RegExpConstructor::getRightContext(ExecState* exec) const +{ + if (d->lastOvector) + 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(exec, 0); + JSValue* arg1 = args.at(exec, 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* 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/JavaScriptCore/runtime/RegExpConstructor.h b/JavaScriptCore/runtime/RegExpConstructor.h new file mode 100644 index 0000000..c5a94a5 --- /dev/null +++ b/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<StructureID>, RegExpPrototype*); + + static PassRefPtr<StructureID> createStructureID(JSValue* prototype) + { + return StructureID::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/JavaScriptCore/runtime/RegExpMatchesArray.h b/JavaScriptCore/runtime/RegExpMatchesArray.h new file mode 100644 index 0000000..6a4279e --- /dev/null +++ b/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) + { + if (lazyCreationData()) + fillArrayInstance(exec); + return JSArray::deleteProperty(exec, propertyName); + } + + virtual bool deleteProperty(ExecState* exec, unsigned propertyName) + { + if (lazyCreationData()) + fillArrayInstance(exec); + return JSArray::deleteProperty(exec, propertyName); + } + + virtual void getPropertyNames(ExecState* exec, PropertyNameArray& arr) + { + if (lazyCreationData()) + fillArrayInstance(exec); + JSArray::getPropertyNames(exec, arr); + } + + void fillArrayInstance(ExecState*); +}; + +} + +#endif // RegExpMatchesArray_h diff --git a/JavaScriptCore/runtime/RegExpObject.cpp b/JavaScriptCore/runtime/RegExpObject.cpp new file mode 100644 index 0000000..127a71e --- /dev/null +++ b/JavaScriptCore/runtime/RegExpObject.cpp @@ -0,0 +1,169 @@ +/* + * 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 "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<StructureID> 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)); +} + +bool RegExpObject::match(ExecState* exec, const ArgList& args) +{ + RegExpConstructor* regExpObj = exec->lexicalGlobalObject()->regExpConstructor(); + + UString input; + if (!args.isEmpty()) + input = args.at(exec, 0)->toString(exec); + else { + input = regExpObj->input(); + if (input.isNull()) { + throwError(exec, GeneralError, "No input."); + return false; + } + } + + bool global = get(exec, exec->propertyNames().global)->toBoolean(exec); + int lastIndex = 0; + if (global) { + if (d->lastIndex < 0 || d->lastIndex > input.size()) { + d->lastIndex = 0; + return false; + } + lastIndex = static_cast<int>(d->lastIndex); + } + + int foundIndex; + int foundLength; + regExpObj->performMatch(d->regExp.get(), input, lastIndex, foundIndex, foundLength); + + if (global) { + lastIndex = foundIndex < 0 ? 0 : foundIndex + foundLength; + d->lastIndex = lastIndex; + } + + return foundIndex >= 0; +} + +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* 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; +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/RegExpObject.h b/JavaScriptCore/runtime/RegExpObject.h new file mode 100644 index 0000000..d80b47c --- /dev/null +++ b/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<StructureID>, 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<StructureID> createStructureID(JSValue* prototype) + { + return StructureID::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/JavaScriptCore/runtime/RegExpPrototype.cpp b/JavaScriptCore/runtime/RegExpPrototype.cpp new file mode 100644 index 0000000..ceee32a --- /dev/null +++ b/JavaScriptCore/runtime/RegExpPrototype.cpp @@ -0,0 +1,118 @@ +/* + * 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 "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* regExpProtoFuncTest(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* regExpProtoFuncExec(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* regExpProtoFuncCompile(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* regExpProtoFuncToString(ExecState*, JSObject*, JSValue*, const ArgList&); + +// ECMA 15.10.5 + +const ClassInfo RegExpPrototype::info = { "RegExpPrototype", 0, 0, 0 }; + +RegExpPrototype::RegExpPrototype(ExecState* exec, PassRefPtr<StructureID> structure, StructureID* prototypeFunctionStructure) + : JSObject(structure) +{ + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 0, exec->propertyNames().compile, regExpProtoFuncCompile), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 0, exec->propertyNames().exec, regExpProtoFuncExec), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 0, exec->propertyNames().test, regExpProtoFuncTest), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) PrototypeFunction(exec, prototypeFunctionStructure, 0, exec->propertyNames().toString, regExpProtoFuncToString), DontEnum); +} + +// ------------------------------ Functions --------------------------- + +JSValue* 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* 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* 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(exec, 0); + JSValue* arg1 = args.at(exec, 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* 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); + 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/JavaScriptCore/runtime/RegExpPrototype.h b/JavaScriptCore/runtime/RegExpPrototype.h new file mode 100644 index 0000000..44a0f32 --- /dev/null +++ b/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<StructureID>, StructureID* prototypeFunctionStructure); + + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + }; + +} // namespace JSC + +#endif // RegExpPrototype_h diff --git a/JavaScriptCore/runtime/ScopeChain.cpp b/JavaScriptCore/runtime/ScopeChain.cpp new file mode 100644 index 0000000..e90b565 --- /dev/null +++ b/JavaScriptCore/runtime/ScopeChain.cpp @@ -0,0 +1,53 @@ +/* + * 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 "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 + +} // namespace JSC diff --git a/JavaScriptCore/runtime/ScopeChain.h b/JavaScriptCore/runtime/ScopeChain.h new file mode 100644 index 0000000..834217c --- /dev/null +++ b/JavaScriptCore/runtime/ScopeChain.h @@ -0,0 +1,218 @@ +/* + * 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 <wtf/Assertions.h> + +namespace JSC { + + class JSGlobalData; + class JSGlobalObject; + class JSObject; + class ScopeChainIterator; + + class ScopeChainNode { + public: + ScopeChainNode(ScopeChainNode* next, JSObject* object, JSGlobalData* globalData, JSObject* globalThis) + : next(next) + , object(object) + , globalData(globalData) + , globalThis(globalThis) + , refCount(1) + { + ASSERT(globalData); + } + + ScopeChainNode* next; + JSObject* object; + JSGlobalData* globalData; + JSObject* globalThis; + int refCount; + + void deref() { if (--refCount == 0) release(); } + void ref() { ++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 CTI; + 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(); + } + + 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; + +#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/JavaScriptCore/runtime/ScopeChainMark.h b/JavaScriptCore/runtime/ScopeChainMark.h new file mode 100644 index 0000000..b80b8ef --- /dev/null +++ b/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/JavaScriptCore/runtime/SmallStrings.cpp b/JavaScriptCore/runtime/SmallStrings.cpp new file mode 100644 index 0000000..06811b9 --- /dev/null +++ b/JavaScriptCore/runtime/SmallStrings.cpp @@ -0,0 +1,112 @@ +/* + * 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" + +namespace JSC { + +class SmallStringsStorage { +public: + SmallStringsStorage(); + ~SmallStringsStorage(); + + UString::Rep* rep(unsigned char character) { return &reps[character]; } + +private: + UChar characters[0x100]; + UString::Rep* reps; +}; + +SmallStringsStorage::SmallStringsStorage() + : reps(static_cast<UString::Rep*>(fastZeroedMalloc(sizeof(UString::Rep) * 0x100))) +{ + for (unsigned i = 0; i < 0x100; ++i) { + characters[i] = i; + reps[i].offset = i; + reps[i].len = 1; + reps[i].rc = 1; + reps[i].baseString = &reps[0]; + } + reps[0].rc = 0x101; + reps[0].buf = characters; + + // make sure UString doesn't try to reuse the buffer by pretending we have one more character in it + reps[0].usedCapacity = 0x101; + reps[0].capacity = 0x101; +} + +SmallStringsStorage::~SmallStringsStorage() +{ + fastFree(reps); +} + +SmallStrings::SmallStrings() + : m_emptyString(0) + , m_storage(0) +{ + for (unsigned i = 0; i < 0x100; ++i) + m_singleCharacterStrings[i] = 0; +} + +SmallStrings::~SmallStrings() +{ +} + +void SmallStrings::mark() +{ + if (m_emptyString && !m_emptyString->marked()) + m_emptyString->mark(); + for (unsigned i = 0; i < 0x100; ++i) { + if (m_singleCharacterStrings[i] && !m_singleCharacterStrings[i]->marked()) + m_singleCharacterStrings[i]->mark(); + } +} + +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); +} + +} diff --git a/JavaScriptCore/runtime/SmallStrings.h b/JavaScriptCore/runtime/SmallStrings.h new file mode 100644 index 0000000..7c71208 --- /dev/null +++ b/JavaScriptCore/runtime/SmallStrings.h @@ -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. + * + * 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 : 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(); + + private: + void createEmptyString(JSGlobalData*); + void createSingleCharacterString(JSGlobalData*, unsigned char); + + JSString* m_emptyString; + JSString* m_singleCharacterStrings[0x100]; + OwnPtr<SmallStringsStorage> m_storage; + }; + +} + +#endif diff --git a/JavaScriptCore/runtime/StringConstructor.cpp b/JavaScriptCore/runtime/StringConstructor.cpp new file mode 100644 index 0000000..850310e --- /dev/null +++ b/JavaScriptCore/runtime/StringConstructor.cpp @@ -0,0 +1,90 @@ +/* + * 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 "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).jsValue(exec)->toUInt32(exec)); + return jsString(exec, UString(buf, p - buf, false)); +} + +static JSValue* stringFromCharCode(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + if (LIKELY(args.size() == 1)) + return jsSingleCharacterString(exec, args.at(exec, 0)->toUInt32(exec)); + return stringFromCharCodeSlowCase(exec, args); +} + +ASSERT_CLASS_FITS_IN_CELL(StringConstructor); + +StringConstructor::StringConstructor(ExecState* exec, PassRefPtr<StructureID> structure, StructureID* 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) PrototypeFunction(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(exec, 0)->toString(exec)); +} + +ConstructType StringConstructor::getConstructData(ConstructData& constructData) +{ + constructData.native.function = constructWithStringConstructor; + return ConstructTypeHost; +} + +// ECMA 15.5.1 +static JSValue* callStringConstructor(ExecState* exec, JSObject*, JSValue*, const ArgList& args) +{ + if (args.isEmpty()) + return jsEmptyString(exec); + return jsString(exec, args.at(exec, 0)->toString(exec)); +} + +CallType StringConstructor::getCallData(CallData& callData) +{ + callData.native.function = callStringConstructor; + return CallTypeHost; +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/StringConstructor.h b/JavaScriptCore/runtime/StringConstructor.h new file mode 100644 index 0000000..3376134 --- /dev/null +++ b/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<StructureID>, StructureID* prototypeFunctionStructure, StringPrototype*); + + virtual ConstructType getConstructData(ConstructData&); + virtual CallType getCallData(CallData&); + }; + +} // namespace JSC + +#endif // StringConstructor_h diff --git a/JavaScriptCore/runtime/StringObject.cpp b/JavaScriptCore/runtime/StringObject.cpp new file mode 100644 index 0000000..5959395 --- /dev/null +++ b/JavaScriptCore/runtime/StringObject.cpp @@ -0,0 +1,101 @@ +/* + * 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<StructureID> structure) + : JSWrapperObject(structure) +{ + setInternalValue(jsEmptyString(exec)); +} + +StringObject::StringObject(PassRefPtr<StructureID> structure, JSString* string) + : JSWrapperObject(structure) +{ + setInternalValue(string); +} + +StringObject::StringObject(ExecState* exec, PassRefPtr<StructureID> 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) +{ + if (propertyName == exec->propertyNames().length) + return false; + return JSObject::deleteProperty(exec, propertyName); +} + +void StringObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) +{ + int size = internalValue()->value().size(); + for (int i = 0; i < size; ++i) + propertyNames.add(Identifier(exec, UString::from(i))); + return JSObject::getPropertyNames(exec, propertyNames); +} + +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/JavaScriptCore/runtime/StringObject.h b/JavaScriptCore/runtime/StringObject.h new file mode 100644 index 0000000..9297fd7 --- /dev/null +++ b/JavaScriptCore/runtime/StringObject.h @@ -0,0 +1,72 @@ +/* + * 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<StructureID>); + StringObject(ExecState*, PassRefPtr<StructureID>, 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); + virtual void getPropertyNames(ExecState*, PropertyNameArray&); + + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + + JSString* internalValue() const { return asString(JSWrapperObject::internalValue());} + + static PassRefPtr<StructureID> createStructureID(JSValue* prototype) + { + return StructureID::create(prototype, TypeInfo(ObjectType)); + } + + protected: + StringObject(PassRefPtr<StructureID>, 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/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h b/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h new file mode 100644 index 0000000..d703228 --- /dev/null +++ b/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, + createStructureID(exec->lexicalGlobalObject()->stringPrototype()), string); + } + + private: + StringObjectThatMasqueradesAsUndefined(ExecState* exec, PassRefPtr<StructureID> structure, const UString& string) + : StringObject(exec, structure, string) + { + } + + static PassRefPtr<StructureID> createStructureID(JSValue* proto) + { + return StructureID::create(proto, TypeInfo(ObjectType, MasqueradesAsUndefined)); + } + + virtual bool toBoolean(ExecState*) const { return false; } + }; + +} // namespace JSC + +#endif // StringObjectThatMasqueradesAsUndefined_h diff --git a/JavaScriptCore/runtime/StringPrototype.cpp b/JavaScriptCore/runtime/StringPrototype.cpp new file mode 100644 index 0000000..0b11c24 --- /dev/null +++ b/JavaScriptCore/runtime/StringPrototype.cpp @@ -0,0 +1,774 @@ +/* + * 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 "StringPrototype.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* stringProtoFuncToString(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncCharAt(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncCharCodeAt(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncConcat(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncIndexOf(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncLastIndexOf(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncMatch(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncReplace(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncSearch(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncSlice(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncSplit(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncSubstr(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncSubstring(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncToLowerCase(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncToUpperCase(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncLocaleCompare(ExecState*, JSObject*, JSValue*, const ArgList&); + +static JSValue* stringProtoFuncBig(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncSmall(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncBlink(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncBold(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncFixed(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncItalics(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncStrike(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncSub(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncSup(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncFontcolor(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncFontsize(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* stringProtoFuncAnchor(ExecState*, JSObject*, JSValue*, const ArgList&); +static JSValue* 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<StructureID> 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; + + unsigned short ref = replacement[i + 1]; + if (ref == '$') { + // "$$" -> "$" + ++i; + substitutedReplacement.append(replacement.data() + offset, i - offset); + offset = i + 1; + substitutedReplacement.append('$'); + 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 (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; + } + } + 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* stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + JSString* sourceVal = thisValue->toThisJSString(exec); + const UString& source = sourceVal->value(); + + JSValue* pattern = args.at(exec, 0); + + JSValue* replacement = args.at(exec, 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* regExpObj = 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). + do { + int matchIndex; + int matchLen; + int* ovector; + regExpObj->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]; + ArgList 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 < source.size()) + sourceRanges.append(UString::Range(lastIndex, source.size() - lastIndex)); + + UString result = source.spliceSubstringsWithSeparators(sourceRanges.data(), sourceRanges.size(), replacements.data(), replacements.size()); + + if (result == source) + return sourceVal; + + return jsString(exec, result); + } + + // First arg is a string + UString patternString = pattern->toString(exec); + int matchPos = source.find(patternString); + int matchLen = patternString.size(); + // Do the replacement + if (matchPos == -1) + return sourceVal; + + if (callType != CallTypeNone) { + ArgList 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); + } + + return jsString(exec, source.substr(0, matchPos) + replacementString + source.substr(matchPos + matchLen)); +} + +JSValue* 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* stringProtoFuncCharAt(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + UString s = thisValue->toThisString(exec); + unsigned len = s.size(); + JSValue* a0 = args.at(exec, 0); + if (JSImmediate::isNumber(a0)) { + uint32_t i; + if (JSImmediate::getUInt32(a0, i) && 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* stringProtoFuncCharCodeAt(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + UString s = thisValue->toThisString(exec); + unsigned len = s.size(); + JSValue* a0 = args.at(exec, 0); + if (JSImmediate::isNumber(a0)) { + uint32_t i; + if (JSImmediate::getUInt32(a0, i) && 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* 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).jsValue(exec)->toString(exec); + return jsString(exec, s); +} + +JSValue* stringProtoFuncIndexOf(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + UString s = thisValue->toThisString(exec); + int len = s.size(); + + JSValue* a0 = args.at(exec, 0); + JSValue* a1 = args.at(exec, 1); + UString u2 = a0->toString(exec); + double dpos = a1->toInteger(exec); + if (dpos < 0) + dpos = 0; + else if (dpos > len) + dpos = len; + return jsNumber(exec, s.find(u2, static_cast<int>(dpos))); +} + +JSValue* stringProtoFuncLastIndexOf(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + UString s = thisValue->toThisString(exec); + int len = s.size(); + + JSValue* a0 = args.at(exec, 0); + JSValue* a1 = args.at(exec, 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* stringProtoFuncMatch(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + UString s = thisValue->toThisString(exec); + + JSValue* a0 = args.at(exec, 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* regExpObj = exec->lexicalGlobalObject()->regExpConstructor(); + int pos; + int matchLength; + regExpObj->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 regExpObj->arrayOfMatches(exec); + } + + // return array of matches + ArgList list; + int lastIndex = 0; + while (pos >= 0) { + list.append(jsSubstring(exec, u, pos, matchLength)); + lastIndex = pos; + pos += matchLength == 0 ? 1 : matchLength; + regExpObj->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* stringProtoFuncSearch(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + UString s = thisValue->toThisString(exec); + + JSValue* a0 = args.at(exec, 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* regExpObj = exec->lexicalGlobalObject()->regExpConstructor(); + int pos; + int matchLength; + regExpObj->performMatch(reg.get(), u, 0, pos, matchLength); + return jsNumber(exec, pos); +} + +JSValue* stringProtoFuncSlice(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + UString s = thisValue->toThisString(exec); + int len = s.size(); + + JSValue* a0 = args.at(exec, 0); + JSValue* a1 = args.at(exec, 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* stringProtoFuncSplit(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + UString s = thisValue->toThisString(exec); + + JSValue* a0 = args.at(exec, 0); + JSValue* a1 = args.at(exec, 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()) { + OwnArrayPtr<int> 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* stringProtoFuncSubstr(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + UString s = thisValue->toThisString(exec); + int len = s.size(); + + JSValue* a0 = args.at(exec, 0); + JSValue* a1 = args.at(exec, 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* stringProtoFuncSubstring(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + UString s = thisValue->toThisString(exec); + int len = s.size(); + + JSValue* a0 = args.at(exec, 0); + JSValue* a1 = args.at(exec, 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* 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* 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* 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(exec, 0); + return jsNumber(exec, localeCompare(s, a0->toString(exec))); +} + +JSValue* stringProtoFuncBig(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&) +{ + UString s = thisValue->toThisString(exec); + return jsString(exec, "<big>" + s + "</big>"); +} + +JSValue* stringProtoFuncSmall(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&) +{ + UString s = thisValue->toThisString(exec); + return jsString(exec, "<small>" + s + "</small>"); +} + +JSValue* stringProtoFuncBlink(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&) +{ + UString s = thisValue->toThisString(exec); + return jsString(exec, "<blink>" + s + "</blink>"); +} + +JSValue* stringProtoFuncBold(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&) +{ + UString s = thisValue->toThisString(exec); + return jsString(exec, "<b>" + s + "</b>"); +} + +JSValue* stringProtoFuncFixed(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&) +{ + UString s = thisValue->toThisString(exec); + return jsString(exec, "<tt>" + s + "</tt>"); +} + +JSValue* stringProtoFuncItalics(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&) +{ + UString s = thisValue->toThisString(exec); + return jsString(exec, "<i>" + s + "</i>"); +} + +JSValue* stringProtoFuncStrike(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&) +{ + UString s = thisValue->toThisString(exec); + return jsString(exec, "<strike>" + s + "</strike>"); +} + +JSValue* stringProtoFuncSub(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&) +{ + UString s = thisValue->toThisString(exec); + return jsString(exec, "<sub>" + s + "</sub>"); +} + +JSValue* stringProtoFuncSup(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&) +{ + UString s = thisValue->toThisString(exec); + return jsString(exec, "<sup>" + s + "</sup>"); +} + +JSValue* stringProtoFuncFontcolor(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + UString s = thisValue->toThisString(exec); + JSValue* a0 = args.at(exec, 0); + return jsString(exec, "<font color=\"" + a0->toString(exec) + "\">" + s + "</font>"); +} + +JSValue* stringProtoFuncFontsize(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + UString s = thisValue->toThisString(exec); + JSValue* a0 = args.at(exec, 0); + return jsString(exec, "<font size=\"" + a0->toString(exec) + "\">" + s + "</font>"); +} + +JSValue* stringProtoFuncAnchor(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + UString s = thisValue->toThisString(exec); + JSValue* a0 = args.at(exec, 0); + return jsString(exec, "<a name=\"" + a0->toString(exec) + "\">" + s + "</a>"); +} + +JSValue* stringProtoFuncLink(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) +{ + UString s = thisValue->toThisString(exec); + JSValue* a0 = args.at(exec, 0); + return jsString(exec, "<a href=\"" + a0->toString(exec) + "\">" + s + "</a>"); +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/StringPrototype.h b/JavaScriptCore/runtime/StringPrototype.h new file mode 100644 index 0000000..b127885 --- /dev/null +++ b/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<StructureID>); + + 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/JavaScriptCore/runtime/StructureID.cpp b/JavaScriptCore/runtime/StructureID.cpp new file mode 100644 index 0000000..8333595 --- /dev/null +++ b/JavaScriptCore/runtime/StructureID.cpp @@ -0,0 +1,902 @@ +/* + * 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 "StructureID.h" + +#include "JSObject.h" +#include "PropertyNameArray.h" +#include "StructureIDChain.h" +#include "identifier.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 WTF::doubleHash; + +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; + +#ifndef NDEBUG +static WTF::RefCountedLeakCounter structureIDCounter("StructureID"); + +#if ENABLE(JSC_MULTIPLE_THREADS) +static Mutex ignoreSetMutex; +#endif + +static bool shouldIgnoreLeaks; +static HashSet<StructureID*> ignoreSet; +#endif + +#if DUMP_STRUCTURE_ID_STATISTICS +static HashSet<StructureID*> liveStructureIDSet; +#endif + +void StructureID::dumpStatistics() +{ +#if DUMP_STRUCTURE_ID_STATISTICS + unsigned numberLeaf = 0; + unsigned numberUsingSingleSlot = 0; + unsigned numberSingletons = 0; + unsigned totalPropertyMapsSize = 0; + + HashSet<StructureID*>::const_iterator end = liveStructureIDSet.end(); + for (HashSet<StructureID*>::const_iterator it = liveStructureIDSet.begin(); it != end; ++it) { + StructureID* structureID = *it; + if (structureID->m_usingSingleTransitionSlot) { + if (!structureID->m_transitions.singleTransition) + ++numberLeaf; + else + ++numberUsingSingleSlot; + + if (!structureID->m_previous && !structureID->m_transitions.singleTransition) + ++numberSingletons; + } + + if (structureID->m_propertyTable) + totalPropertyMapsSize += PropertyMapHashTable::allocationSize(structureID->m_propertyTable->size); + } + + printf("Number of live StructureIDs: %d\n", liveStructureIDSet.size()); + printf("Number of StructureIDs using the single item optimization for transition map: %d\n", numberUsingSingleSlot); + printf("Number of StructureIDs that are leaf nodes: %d\n", numberLeaf); + printf("Number of StructureIDs that singletons: %d\n", numberSingletons); + + printf("Size of a single StructureIDs: %d\n", static_cast<unsigned>(sizeof(StructureID))); + 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>(liveStructureIDSet.size())); +#else + printf("Dumping StructureID statistics is not enabled.\n"); +#endif +} + +StructureID::StructureID(JSValue* prototype, const TypeInfo& typeInfo) + : m_typeInfo(typeInfo) + , m_prototype(prototype) + , m_cachedPrototypeChain(0) + , m_previous(0) + , m_nameInPrevious(0) + , m_transitionCount(0) + , m_propertyTable(0) + , m_propertyStorageCapacity(JSObject::inlineStorageCapacity) + , m_cachedTransistionOffset(WTF::notFound) + , m_isDictionary(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 + structureIDCounter.increment(); +#endif + +#if DUMP_STRUCTURE_ID_STATISTICS + liveStructureIDSet.add(this); +#endif +} + +StructureID::~StructureID() +{ + 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, m_attributesInPrevious))); + m_previous->m_transitions.table->remove(make_pair(m_nameInPrevious, m_attributesInPrevious)); + } + } + + if (m_cachedPropertyNameArrayData) + m_cachedPropertyNameArrayData->setCachedStructureID(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(); + } + fastFree(m_propertyTable); + } + +#ifndef NDEBUG +#if ENABLE(JSC_MULTIPLE_THREADS) + MutexLocker protect(ignoreSetMutex); +#endif + HashSet<StructureID*>::iterator it = ignoreSet.find(this); + if (it != ignoreSet.end()) + ignoreSet.remove(it); + else + structureIDCounter.decrement(); +#endif + +#if DUMP_STRUCTURE_ID_STATISTICS + liveStructureIDSet.remove(this); +#endif +} + +void StructureID::startIgnoringLeaks() +{ +#ifndef NDEBUG + shouldIgnoreLeaks = true; +#endif +} + +void StructureID::stopIgnoringLeaks() +{ +#ifndef NDEBUG + shouldIgnoreLeaks = false; +#endif +} + +void StructureID::getEnumerablePropertyNames(ExecState* exec, PropertyNameArray& propertyNames, JSObject* baseObject) +{ + bool shouldCache = propertyNames.cacheable() && !(propertyNames.size() || m_isDictionary); + + if (shouldCache) { + if (m_cachedPropertyNameArrayData) { + if (structureIDChainsAreEqual(m_cachedPropertyNameArrayData->cachedPrototypeChain(), cachedPrototypeChain())) { + propertyNames.setData(m_cachedPropertyNameArrayData); + return; + } + } + propertyNames.setCacheable(false); + } + + getEnumerablePropertyNamesInternal(propertyNames); + + // Add properties from the static hashtables of properties + for (const ClassInfo* info = baseObject->classInfo(); info; info = info->parentClass) { + const HashTable* table = info->propHashTable(exec); + if (!table) + continue; + table->initializeIfNeeded(exec); + ASSERT(table->table); + int hashSizeMask = table->hashSizeMask; + const HashEntry* entry = table->table; + for (int i = 0; i <= hashSizeMask; ++i, ++entry) { + if (entry->key() && !(entry->attributes() & DontEnum)) + propertyNames.add(entry->key()); + } + } + + if (m_prototype->isObject()) + asObject(m_prototype)->getPropertyNames(exec, propertyNames); + + if (shouldCache) { + if (m_cachedPropertyNameArrayData) + m_cachedPropertyNameArrayData->setCachedStructureID(0); + + m_cachedPropertyNameArrayData = propertyNames.data(); + + StructureIDChain* chain = cachedPrototypeChain(); + if (!chain) + chain = createCachedPrototypeChain(); + m_cachedPropertyNameArrayData->setCachedPrototypeChain(chain); + m_cachedPropertyNameArrayData->setCachedStructureID(this); + } +} + +void StructureID::clearEnumerationCache() +{ + if (m_cachedPropertyNameArrayData) + m_cachedPropertyNameArrayData->setCachedStructureID(0); + m_cachedPropertyNameArrayData.clear(); +} + +void StructureID::growPropertyStorageCapacity() +{ + if (m_propertyStorageCapacity == JSObject::inlineStorageCapacity) + m_propertyStorageCapacity = JSObject::nonInlineBaseStorageCapacity; + else + m_propertyStorageCapacity *= 2; +} + +PassRefPtr<StructureID> StructureID::addPropertyTransition(StructureID* structureID, const Identifier& propertyName, unsigned attributes, size_t& offset) +{ + ASSERT(!structureID->m_isDictionary); + ASSERT(structureID->typeInfo().type() == ObjectType); + + if (structureID->m_usingSingleTransitionSlot) { + StructureID* existingTransition = structureID->m_transitions.singleTransition; + if (existingTransition && existingTransition->m_nameInPrevious == propertyName.ustring().rep() && existingTransition->m_attributesInPrevious == attributes) { + offset = structureID->m_transitions.singleTransition->cachedTransistionOffset(); + ASSERT(offset != WTF::notFound); + return existingTransition; + } + } else { + if (StructureID* existingTransition = structureID->m_transitions.table->get(make_pair(propertyName.ustring().rep(), attributes))) { + offset = existingTransition->cachedTransistionOffset(); + ASSERT(offset != WTF::notFound); + return existingTransition; + } + } + + if (structureID->m_transitionCount > s_maxTransitionLength) { + RefPtr<StructureID> transition = toDictionaryTransition(structureID); + offset = transition->put(propertyName, attributes); + if (transition->propertyStorageSize() > transition->propertyStorageCapacity()) + transition->growPropertyStorageCapacity(); + return transition.release(); + } + + RefPtr<StructureID> transition = create(structureID->m_prototype, structureID->typeInfo()); + transition->m_cachedPrototypeChain = structureID->m_cachedPrototypeChain; + transition->m_previous = structureID; + transition->m_nameInPrevious = propertyName.ustring().rep(); + transition->m_attributesInPrevious = attributes; + transition->m_transitionCount = structureID->m_transitionCount + 1; + transition->m_propertyTable = structureID->copyPropertyTable(); + transition->m_deletedOffsets = structureID->m_deletedOffsets; + transition->m_propertyStorageCapacity = structureID->m_propertyStorageCapacity; + transition->m_hasGetterSetterProperties = structureID->m_hasGetterSetterProperties; + + offset = transition->put(propertyName, attributes); + if (transition->propertyStorageSize() > transition->propertyStorageCapacity()) + transition->growPropertyStorageCapacity(); + + transition->setCachedTransistionOffset(offset); + + if (structureID->m_usingSingleTransitionSlot) { + if (!structureID->m_transitions.singleTransition) { + structureID->m_transitions.singleTransition = transition.get(); + return transition.release(); + } + + StructureID* existingTransition = structureID->m_transitions.singleTransition; + structureID->m_usingSingleTransitionSlot = false; + StructureIDTransitionTable* transitionTable = new StructureIDTransitionTable; + structureID->m_transitions.table = transitionTable; + transitionTable->add(make_pair(existingTransition->m_nameInPrevious, existingTransition->m_attributesInPrevious), existingTransition); + } + structureID->m_transitions.table->add(make_pair(propertyName.ustring().rep(), attributes), transition.get()); + return transition.release(); +} + +PassRefPtr<StructureID> StructureID::removePropertyTransition(StructureID* structureID, const Identifier& propertyName, size_t& offset) +{ + ASSERT(!structureID->m_isDictionary); + + RefPtr<StructureID> transition = create(structureID->m_prototype, structureID->typeInfo()); + transition->m_isDictionary = true; + transition->m_propertyTable = structureID->copyPropertyTable(); + transition->m_deletedOffsets = structureID->m_deletedOffsets; + transition->m_propertyStorageCapacity = structureID->m_propertyStorageCapacity; + transition->m_hasGetterSetterProperties = structureID->m_hasGetterSetterProperties; + + offset = transition->remove(propertyName); + + return transition.release(); +} + +PassRefPtr<StructureID> StructureID::toDictionaryTransition(StructureID* structureID) +{ + ASSERT(!structureID->m_isDictionary); + + RefPtr<StructureID> transition = create(structureID->m_prototype, structureID->typeInfo()); + transition->m_isDictionary = true; + transition->m_propertyTable = structureID->copyPropertyTable(); + transition->m_deletedOffsets = structureID->m_deletedOffsets; + transition->m_propertyStorageCapacity = structureID->m_propertyStorageCapacity; + transition->m_hasGetterSetterProperties = structureID->m_hasGetterSetterProperties; + return transition.release(); +} + +PassRefPtr<StructureID> StructureID::fromDictionaryTransition(StructureID* structureID) +{ + ASSERT(structureID->m_isDictionary); + + // Since dictionary StructureIDs are not shared, and no opcodes specialize + // for them, we don't need to allocate a new StructureID when transitioning + // to non-dictionary status. + structureID->m_isDictionary = false; + return structureID; +} + +PassRefPtr<StructureID> StructureID::changePrototypeTransition(StructureID* structureID, JSValue* prototype) +{ + RefPtr<StructureID> transition = create(prototype, structureID->typeInfo()); + transition->m_transitionCount = structureID->m_transitionCount + 1; + transition->m_propertyTable = structureID->copyPropertyTable(); + transition->m_deletedOffsets = structureID->m_deletedOffsets; + transition->m_propertyStorageCapacity = structureID->m_propertyStorageCapacity; + transition->m_hasGetterSetterProperties = structureID->m_hasGetterSetterProperties; + return transition.release(); +} + +PassRefPtr<StructureID> StructureID::getterSetterTransition(StructureID* structureID) +{ + RefPtr<StructureID> transition = create(structureID->storedPrototype(), structureID->typeInfo()); + transition->m_transitionCount = structureID->m_transitionCount + 1; + transition->m_propertyTable = structureID->copyPropertyTable(); + transition->m_deletedOffsets = structureID->m_deletedOffsets; + transition->m_propertyStorageCapacity = structureID->m_propertyStorageCapacity; + transition->m_hasGetterSetterProperties = transition->m_hasGetterSetterProperties; + return transition.release(); +} + +size_t StructureID::addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes) +{ + size_t offset = put(propertyName, attributes); + if (propertyStorageSize() > propertyStorageCapacity()) + growPropertyStorageCapacity(); + clearEnumerationCache(); + return offset; +} + +size_t StructureID::removePropertyWithoutTransition(const Identifier& propertyName) +{ + size_t offset = remove(propertyName); + clearEnumerationCache(); + return offset; +} + +StructureIDChain* StructureID::createCachedPrototypeChain() +{ + ASSERT(typeInfo().type() == ObjectType); + ASSERT(!m_cachedPrototypeChain); + + JSValue* prototype = storedPrototype(); + if (JSImmediate::isImmediate(prototype)) + return 0; + + RefPtr<StructureIDChain> chain = StructureIDChain::create(asObject(prototype)->structureID()); + setCachedPrototypeChain(chain.release()); + return cachedPrototypeChain(); +} + +#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 StructureID::checkConsistency() +{ +} + +#endif + +PropertyMapHashTable* StructureID::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(); + } + + return newTable; +} + +size_t StructureID::get(const Identifier& propertyName, unsigned& attributes) const +{ + ASSERT(!propertyName.isNull()); + + 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) { + attributes = m_propertyTable->entries()[entryIndex - 1].attributes; + 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 WTF::notFound; + + if (rep == m_propertyTable->entries()[entryIndex - 1].key) { + attributes = m_propertyTable->entries()[entryIndex - 1].attributes; + return m_propertyTable->entries()[entryIndex - 1].offset; + } + } +} + +size_t StructureID::put(const Identifier& propertyName, unsigned attributes) +{ + ASSERT(!propertyName.isNull()); + ASSERT(get(propertyName) == WTF::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].index = ++m_propertyTable->lastIndexUsed; + + unsigned newOffset; + if (!m_deletedOffsets.isEmpty()) { + newOffset = m_deletedOffsets.last(); + m_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 StructureID::remove(const Identifier& propertyName) +{ + ASSERT(!propertyName.isNull()); + + checkConsistency(); + + UString::Rep* rep = propertyName._ustring.rep(); + + if (!m_propertyTable) + return WTF::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 WTF::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].offset = 0; + m_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 StructureID::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 StructureID::expandPropertyMapHashTable() +{ + ASSERT(m_propertyTable); + rehashPropertyMapHashTable(m_propertyTable->size * 2); +} + +void StructureID::createPropertyMapHashTable() +{ + const unsigned newTableSize = 16; + + ASSERT(!m_propertyTable); + + checkConsistency(); + + m_propertyTable = static_cast<PropertyMapHashTable*>(fastZeroedMalloc(PropertyMapHashTable::allocationSize(newTableSize))); + m_propertyTable->size = newTableSize; + m_propertyTable->sizeMask = newTableSize - 1; + + checkConsistency(); +} + +void StructureID::rehashPropertyMapHashTable() +{ + ASSERT(m_propertyTable); + ASSERT(m_propertyTable->size); + rehashPropertyMapHashTable(m_propertyTable->size); +} + +void StructureID::rehashPropertyMapHashTable(unsigned newTableSize) +{ + ASSERT(m_propertyTable); + + 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; + + 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 StructureID::getEnumerablePropertyNamesInternal(PropertyNameArray& propertyNames) const +{ + 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 && !(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 && !(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); + } +} + +#if DO_PROPERTYMAP_CONSTENCY_CHECK + +void StructureID::checkConsistency() +{ + if (!m_propertyTable) + return; + + ASSERT(m_propertyTable->size >= 16); + 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/JavaScriptCore/runtime/StructureID.h b/JavaScriptCore/runtime/StructureID.h new file mode 100644 index 0000000..4f45dac --- /dev/null +++ b/JavaScriptCore/runtime/StructureID.h @@ -0,0 +1,216 @@ +/* + * 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 StructureID_h +#define StructureID_h + +#include "JSType.h" +#include "JSValue.h" +#include "PropertyMapHashTable.h" +#include "StructureIDChain.h" +#include "StructureIDTransitionTable.h" +#include "TypeInfo.h" +#include "identifier.h" +#include "ustring.h" +#include <wtf/HashFunctions.h> +#include <wtf/HashTraits.h> +#include <wtf/OwnArrayPtr.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 StructureID : public RefCounted<StructureID> { + public: + friend class CTI; + static PassRefPtr<StructureID> create(JSValue* prototype, const TypeInfo& typeInfo) + { + return adoptRef(new StructureID(prototype, typeInfo)); + } + + static void startIgnoringLeaks(); + static void stopIgnoringLeaks(); + + static void dumpStatistics(); + + static PassRefPtr<StructureID> changePrototypeTransition(StructureID*, JSValue* prototype); + static PassRefPtr<StructureID> addPropertyTransition(StructureID*, const Identifier& propertyName, unsigned attributes, size_t& offset); + static PassRefPtr<StructureID> removePropertyTransition(StructureID*, const Identifier& propertyName, size_t& offset); + static PassRefPtr<StructureID> getterSetterTransition(StructureID*); + static PassRefPtr<StructureID> toDictionaryTransition(StructureID*); + static PassRefPtr<StructureID> fromDictionaryTransition(StructureID*); + + ~StructureID(); + + void mark() + { + if (!m_prototype->marked()) + m_prototype->mark(); + } + + // These should be used with caution. + size_t addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes); + 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; } + + // For use when first creating a new structure. + TypeInfo& mutableTypeInfo() { return m_typeInfo; } + + JSValue* storedPrototype() const { return m_prototype; } + JSValue* prototypeForLookup(ExecState*); + + StructureID* previousID() const { return m_previous.get(); } + + StructureIDChain* createCachedPrototypeChain(); + void setCachedPrototypeChain(PassRefPtr<StructureIDChain> cachedPrototypeChain) { m_cachedPrototypeChain = cachedPrototypeChain; } + StructureIDChain* cachedPrototypeChain() const { return m_cachedPrototypeChain.get(); } + + void setCachedTransistionOffset(size_t offset) { m_cachedTransistionOffset = offset; } + size_t cachedTransistionOffset() const { return m_cachedTransistionOffset; } + + void growPropertyStorageCapacity(); + size_t propertyStorageCapacity() const { return m_propertyStorageCapacity; } + size_t propertyStorageSize() const { return m_propertyTable ? m_propertyTable->keyCount + m_deletedOffsets.size() : 0; } + + size_t get(const Identifier& propertyName) const; + size_t get(const Identifier& propertyName, unsigned& attributes) const; + void getEnumerablePropertyNames(ExecState*, PropertyNameArray&, JSObject*); + + bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; } + void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; } + + bool isEmpty() const { return !m_propertyTable; } + + private: + StructureID(JSValue* prototype, const TypeInfo&); + + size_t put(const Identifier& propertyName, unsigned attributes); + size_t remove(const Identifier& propertyName); + void getEnumerablePropertyNamesInternal(PropertyNameArray&) const; + + void expandPropertyMapHashTable(); + void rehashPropertyMapHashTable(); + void rehashPropertyMapHashTable(unsigned newTableSize); + void createPropertyMapHashTable(); + void insertIntoPropertyMapHashTable(const PropertyMapEntry&); + void checkConsistency(); + + PropertyMapHashTable* copyPropertyTable(); + + void clearEnumerationCache(); + + static const unsigned emptyEntryIndex = 0; + + static const size_t s_maxTransitionLength = 64; + + TypeInfo m_typeInfo; + + JSValue* m_prototype; + RefPtr<StructureIDChain> m_cachedPrototypeChain; + + RefPtr<StructureID> m_previous; + UString::Rep* m_nameInPrevious; + + size_t m_transitionCount; + union { + StructureID* singleTransition; + StructureIDTransitionTable* table; + } m_transitions; + + RefPtr<PropertyNameArrayData> m_cachedPropertyNameArrayData; + + PropertyMapHashTable* m_propertyTable; + Vector<unsigned> m_deletedOffsets; + + size_t m_propertyStorageCapacity; + + size_t m_cachedTransistionOffset; + + bool m_isDictionary : 1; + bool m_hasGetterSetterProperties : 1; + bool m_usingSingleTransitionSlot : 1; + unsigned m_attributesInPrevious : 5; + }; + + inline size_t StructureID::get(const Identifier& propertyName) const + { + ASSERT(!propertyName.isNull()); + + 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 // StructureID_h diff --git a/JavaScriptCore/runtime/StructureIDChain.cpp b/JavaScriptCore/runtime/StructureIDChain.cpp new file mode 100644 index 0000000..83d9254 --- /dev/null +++ b/JavaScriptCore/runtime/StructureIDChain.cpp @@ -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. + */ + +#include "config.h" +#include "StructureIDChain.h" + +#include "JSObject.h" +#include "StructureID.h" +#include <wtf/RefPtr.h> + +namespace JSC { + +StructureIDChain::StructureIDChain(StructureID* structureID) +{ + size_t size = 1; + + StructureID* tmp = structureID; + while (!tmp->storedPrototype()->isNull()) { + ++size; + tmp = asCell(tmp->storedPrototype())->structureID(); + } + + m_vector.set(new RefPtr<StructureID>[size + 1]); + + size_t i; + for (i = 0; i < size - 1; ++i) { + m_vector[i] = structureID; + structureID = asObject(structureID->storedPrototype())->structureID(); + } + m_vector[i] = structureID; + m_vector[i + 1] = 0; +} + +bool structureIDChainsAreEqual(StructureIDChain* chainA, StructureIDChain* chainB) +{ + if (!chainA || !chainB) + return false; + + RefPtr<StructureID>* a = chainA->head(); + RefPtr<StructureID>* b = chainB->head(); + while (1) { + if (*a != *b) + return false; + if (!*a) + return true; + a++; + b++; + } +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/StructureIDChain.h b/JavaScriptCore/runtime/StructureIDChain.h new file mode 100644 index 0000000..2d554a7 --- /dev/null +++ b/JavaScriptCore/runtime/StructureIDChain.h @@ -0,0 +1,54 @@ +/* + * 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 StructureIDChain_h +#define StructureIDChain_h + +#include <wtf/OwnArrayPtr.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace JSC { + + class StructureID; + + class StructureIDChain : public RefCounted<StructureIDChain> { + public: + static PassRefPtr<StructureIDChain> create(StructureID* structureID) { return adoptRef(new StructureIDChain(structureID)); } + + RefPtr<StructureID>* head() { return m_vector.get(); } + + private: + StructureIDChain(StructureID* structureID); + + OwnArrayPtr<RefPtr<StructureID> > m_vector; + }; + + bool structureIDChainsAreEqual(StructureIDChain*, StructureIDChain*); + +} // namespace JSC + +#endif // StructureIDChain_h diff --git a/JavaScriptCore/runtime/StructureIDTransitionTable.h b/JavaScriptCore/runtime/StructureIDTransitionTable.h new file mode 100644 index 0000000..dd65971 --- /dev/null +++ b/JavaScriptCore/runtime/StructureIDTransitionTable.h @@ -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. + * + * 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 StructureIDTransitionTable_h +#define StructureIDTransitionTable_h + +#include "ustring.h" +#include <wtf/HashFunctions.h> +#include <wtf/HashMap.h> +#include <wtf/HashTraits.h> +#include <wtf/RefPtr.h> + +namespace JSC { + + class StructureID; + + struct StructureIDTransitionTableHash { + typedef std::pair<RefPtr<UString::Rep>, unsigned> 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 StructureIDTransitionTableHashTraits { + typedef WTF::HashTraits<RefPtr<UString::Rep> > FirstTraits; + typedef WTF::GenericHashTraits<unsigned> SecondTraits; + typedef std::pair<FirstTraits::TraitType, SecondTraits::TraitType> TraitType; + + static const bool emptyValueIsZero = FirstTraits::emptyValueIsZero && SecondTraits::emptyValueIsZero; + static TraitType emptyValue() { return std::make_pair(FirstTraits::emptyValue(), SecondTraits::emptyValue()); } + + static const bool needsDestruction = FirstTraits::needsDestruction || SecondTraits::needsDestruction; + + static void constructDeletedValue(TraitType& slot) { FirstTraits::constructDeletedValue(slot.first); } + static bool isDeletedValue(const TraitType& value) { return FirstTraits::isDeletedValue(value.first); } + }; + + typedef HashMap<StructureIDTransitionTableHash::Key, StructureID*, StructureIDTransitionTableHash, StructureIDTransitionTableHashTraits> StructureIDTransitionTable; + +} // namespace JSC + +#endif // StructureIDTransitionTable_h diff --git a/JavaScriptCore/runtime/SymbolTable.h b/JavaScriptCore/runtime/SymbolTable.h new file mode 100644 index 0000000..d730d58 --- /dev/null +++ b/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/JavaScriptCore/runtime/Tracing.d b/JavaScriptCore/runtime/Tracing.d new file mode 100644 index 0000000..b9efaff --- /dev/null +++ b/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/JavaScriptCore/runtime/Tracing.h b/JavaScriptCore/runtime/Tracing.h new file mode 100644 index 0000000..e544f66 --- /dev/null +++ b/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 |